# Binary Diff Report — mqac.sys / KB5071544 / CVE-2025-62455

**Tool:** ghidriff (Ghidra-based binary differ, PDB symbols resolved from Microsoft symbol server)
**Pre-patch:**  `mqac.sys` 10.0.17763.7919 — PE timestamp `0x7097E836` — SHA-256 `19f7a631…` — 189,952 bytes
**Post-patch:** `mqac.sys` 10.0.17763.8146 — PE timestamp `0xC963E042` — SHA-256 `bcaa934f…` — 190,464 bytes (+512)
**KB:** KB5071544 (Windows 10 Version 1809 / Windows Server 2019 — December 9, 2025 Patch Tuesday)
**CVE:** CVE-2025-62455

---

## Summary

Arbitrary-file-write fix in the MSMQ kernel driver. Both `ACpCreateBitmap` and `CMMFAllocator::Create` previously called `ZwCreateFile` with a DOS path (`C:\Windows\System32\msmq\storage\l%07u.mq`) using `OBJECT_ATTRIBUTES.Attributes = 0x240` (`OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE`). The path is resolved through the calling process's device map (`_EPROCESS.DeviceMap`), which any unprivileged process can redirect via `NtSetInformationProcess(ProcessDeviceMap, ...)` to cause SYSTEM-privilege file creation at an arbitrary path.

**Patch:** Both functions now query feature flag `g_Feature_1840809274_58536133` via `EvaluateCurrentState` before calling `ZwCreateFile`. When the flag is enabled, `OBJECT_ATTRIBUTES.Attributes` is set to `0x640` (`OBJ_FORCE_ACCESS_CHECK | OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE`), adding `OBJ_FORCE_ACCESS_CHECK` (0x400). The `ZwCreateFile` call and the DOS path are retained in both versions — the fix is in the `Attributes` field. Deployment uses Microsoft's feature experimentation rollout mechanism (same pattern as CLFS.sys patches) for kill-switch capability. Error handling in both functions now distinguishes `STATUS_ACCESS_DENIED` (0xC0000022) from other `ZwCreateFile` failures with a dedicated WPP trace message, suggesting the new flag is expected to produce access-denied responses in exploit scenarios.

---

## Statistics

| Metric | Value |
|---|---|
| Total functions analyzed (pre) | 1142 |
| Total functions analyzed (post) | 1142 |
| Functions with code changes | 3 |
| Functions with non-code changes (address/refcount) | 1 |
| Net binary size delta | +512 bytes |

---

## Functions Changed (Code)

### 1. `ACpCreateBitmap` — **PRIMARY FIX**

| Field | Pre-patch | Post-patch |
|---|---|---|
| Address | `1c0010de4` | `1c000f76c` |
| Length | 439 bytes | 626 bytes |
| Delta | +187 bytes | |
| Match ratio | 78% | |

**Key diff (decompiled C):**

```diff
--- ACpCreateBitmap
+++ ACpCreateBitmap
@@ -1,66 +1,100 @@
 CPingPong * __cdecl
 ACpCreateBitmap(_DEVICE_OBJECT *param_1,wchar_t *param_2,wchar_t **param_3,void **param_4)
 {
   longlong lVar1;
   int iVar2;
-  CPingPong *pCVar3;
+  int iVar3;
   CPingPong *pCVar4;
+  CPingPong *pCVar5;
+  undefined2 uVar6;
+  undefined4 *puVar7;
   ...
   lVar1 = *(longlong *)(param_1 + 0x40);
-  pCVar3 = (CPingPong *)ExAllocatePoolWithTagPriority(1,0x1000,0x4841514d);
-  if (pCVar3 == (CPingPong *)0x0) {
-    if (((undefined **)WPP_GLOBAL_Control != &WPP_GLOBAL_Control) &&
-       ((*(uint *)(WPP_GLOBAL_Control + 0x6c) & 1) != 0)) {
-      WPP_SF_D(...,0xe,...,0x1000);
+  pCVar4 = (CPingPong *)ExAllocatePoolWithTagPriority(1,0x1000,0x4841514d);
+  if (pCVar4 == (CPingPong *)0x0) {
+    if ((undefined **)WPP_GLOBAL_Control == &WPP_GLOBAL_Control) {
+      return (CPingPong *)0x0;
     }
+    ...
+    WPP_SF_D(...,0xe,...,0x1000);
+    return (CPingPong *)0x0;
   }
-  else {
-    ...
-    pCVar4 = (CPingPong *)ACpGenerateFileName(param_2,...);
-    if (pCVar4 == (CPingPong *)0x0) {
-      ...
-    }
-    else {
-      RtlInitUnicodeString(local_70,pCVar4);
-      local_40 = local_70;
-      local_48 = 0;
-      local_50[0] = 0x30;
-      local_38 = 0x240;          // <── OBJECT_ATTRIBUTES.Attributes (vulnerable)
-      local_30 = 0;
-      uStack_28 = 0;
-      local_res8 = 0x2000;
-      iVar2 = ZwCreateFile(&local_78,0xc0100000,local_50,...);
-      *(undefined4 *)pCVar3 = 0x7a657245;
-      if (-1 < iVar2) {
-        *param_3 = (wchar_t *)pCVar4;
-        *param_4 = local_78;
-        return pCVar3;
-      }
-      *(undefined4 *)pCVar3 = 0;
-      ExFreePoolWithTag(pCVar3,0);
-    }
-    ExFreePoolWithTag(pCVar4,0);
+  *(undefined4 *)(pCVar4 + 4) = 0;
+  ...
+  pCVar5 = (CPingPong *)ACpGenerateFileName(param_2,...);
+  if (pCVar5 == (CPingPong *)0x0) {
+    *(undefined4 *)pCVar4 = 0;
+    pCVar5 = pCVar4;
+    goto LAB_0;
   }
+  RtlInitUnicodeString(local_70,pCVar5);
+  iVar2 = EvaluateCurrentState(                            // <── NEW: query feature flag
+                    (reg_FeatureDescriptor *)
+                    &g_Feature_1840809274_58536133_FeatureDescriptorDetails);
+  local_48 = 0;
+  local_50[0] = 0x30;
+  local_40 = local_70;
+  local_38 = 0x640;                                        // <── default: add OBJ_FORCE_ACCESS_CHECK
+  local_30 = 0;
+  uStack_28 = 0;
+  if (iVar2 == 0) {
+    local_38 = 0x240;                                      // <── feature disabled: old behavior
+  }
+  puVar7 = local_50;
+  local_res8 = 0x2000;
+  iVar2 = ZwCreateFile(&local_78,0xc0100000,puVar7,...);   // ZwCreateFile still called
+  *(undefined4 *)pCVar4 = 0x7a657245;
+  iVar3 = EvaluateCurrentState(                            // <── NEW: second flag check for logging
+                    (reg_FeatureDescriptor *)
+                    &g_Feature_1840809274_58536133_FeatureDescriptorDetails);
+  if (-1 < iVar2) {
+    if (((iVar3 != 0) && ...) {                            // <── new success trace (feature only)
+      WPP_SF_S(...,0x11,...,(wchar_t *)pCVar5);
+    }
+    *param_3 = (wchar_t *)pCVar5;
+    *param_4 = local_78;
+    return pCVar4;
+  }
+  if (iVar3 != 0) {
+    if (iVar2 == -0x3fffffde) {                            // STATUS_ACCESS_DENIED (0xC0000022)
+      WPP_SF_SD(...,0xf,...,(wchar_t *)pCVar5);            // <── dedicated denial trace
+    }
+    else {
+      WPP_SF_SD(...,0x10,...,(wchar_t *)pCVar5);           // <── generic failure trace
+    }
+  }
+  *(undefined4 *)pCVar4 = 0;
+  ExFreePoolWithTag(pCVar4,0);
+LAB_0:
+  ExFreePoolWithTag(pCVar5,0);
   return (CPingPong *)0x0;
 }
```

**Analysis:**

The primary change is in `OBJECT_ATTRIBUTES.Attributes`. Previously hardcoded to `0x240`; now set to `0x640` (adds `OBJ_FORCE_ACCESS_CHECK` = 0x400) when feature flag `g_Feature_1840809274_58536133` is enabled, or `0x240` (old behavior) when disabled. `ZwCreateFile` remains in both versions at the same call site. The new error path specifically distinguishes `STATUS_ACCESS_DENIED` from other failures — consistent with the expectation that `OBJ_FORCE_ACCESS_CHECK` will cause the kernel to return access-denied when a redirected device-map path fails an access check.

`OBJECT_ATTRIBUTES.Attributes` flag breakdown:
| Flag | Value | Vulnerable | Patched |
|---|---|---|---|
| `OBJ_CASE_INSENSITIVE` | 0x040 | ✓ | ✓ |
| `OBJ_KERNEL_HANDLE` | 0x200 | ✓ | ✓ |
| `OBJ_FORCE_ACCESS_CHECK` | 0x400 | — | ✓ (when flag enabled) |

---

### 2. `CMMFAllocator::Create` — **PRIMARY FIX (same pattern)**

| Field | Pre-patch | Post-patch |
|---|---|---|
| Address | `1c001001c` | `1c000f0a4` |
| Length | 906 bytes | 1115 bytes |
| Delta | +209 bytes | |
| Match ratio | 74% | |

**Key diff (decompiled C, excerpt):**

```diff
--- CMMFAllocator::Create
+++ CMMFAllocator::Create
@@
-  local_a0 = 0x240;    // OBJECT_ATTRIBUTES.Attributes (vulnerable)
+  iVar2 = EvaluateCurrentState(                       // <── NEW: feature flag check
+                    &g_Feature_1840809274_58536133_FeatureDescriptorDetails);
+  local_a0 = 0x640;                                   // default: add OBJ_FORCE_ACCESS_CHECK
+  if (iVar2 == 0) {
+    local_a0 = 0x240;                                 // feature disabled: old value
+  }
   ...
   lVar2 = ZwCreateFile(&local_c0, ...);               // ZwCreateFile still called
+  iVar2 = EvaluateCurrentState(                       // <── NEW: second check for error logging
+                    &g_Feature_1840809274_58536133_FeatureDescriptorDetails);
+  if (iVar2 != 0) {
+    // extended WPP error logging (feature-enabled path only)
+  }
```

**Analysis:** Identical fix pattern to `ACpCreateBitmap`. Same feature flag, same 0x240 → 0x640 change, same second `EvaluateCurrentState` call gating extended error logging.

---

### 3. `WPP_SF_S` — minor

| Field | Pre-patch | Post-patch |
|---|---|---|
| Address | `1c000fcac` | `1c000fdf4` |
| Length | 116 bytes | 114 bytes |
| Match ratio | 96% | |

Minor change: parameter 2 type narrowed from `undefined8` to `undefined2`; WPP trace GUID updated (`WPP_513747e657fd3457b90b087b9bdb6357` → `WPP_6abace7bf7993bf0a051e292fbd0c98c`). Now called by `ACpCreateBitmap` in addition to `CMMFAllocator::Create` (refcount 2 → 4). Consistent with recompile updating trace registration metadata.

---

## Functions Modified (No Code Changes)

### `EvaluateCurrentState`

Address moved (`1c001272c` → `1c000fdc0`). Code identical (ratio 1.0). Refcount increased 2 → 6 — now called by `ACpCreateBitmap` (×2) and `CMMFAllocator::Create` (×2) in addition to existing callers.

---

## Feature Flag Details

Both patched functions call:

```c
EvaluateCurrentState(
    (reg_FeatureDescriptor *)&g_Feature_1840809274_58536133_FeatureDescriptorDetails
)
```

Return value `0` = feature disabled (old behavior, `Attributes = 0x240`). Non-zero = feature enabled (`Attributes = 0x640`). The feature descriptor `g_Feature_1840809274_58536133` is a Windows Feature Experience Pack / Velocity feature ID, enabling Microsoft to control rollout via A/B staging or emergency kill-switch without re-shipping the binary. This is the same gradual-deployment pattern used in recent CLFS.sys patches.

---

## Import Comparison

No imports added or removed. `EvaluateCurrentState`, `ZwCreateFile`, `ExAllocatePoolWithTagPriority`, `ExFreePoolWithTag`, `RtlInitUnicodeString`, and all WPP trace helpers were already present in the pre-patch import table.

---

## Binaries

| Role | File | SHA-256 | MSDL URL |
|---|---|---|---|
| Pre-patch | `mqac-2025-11.sys` | `19f7a631…` | `https://msdl.microsoft.com/download/symbols/mqac.sys/7097E83634000/mqac.sys` |
| Post-patch | `mqac-2025-12.sys` | `bcaa934f…` | `https://msdl.microsoft.com/download/symbols/mqac.sys/C963E04234000/mqac.sys` |
