acx01000.sys — telemetry and feature-staging churn
KB5075912
1. Overview
- Unpatched Binary:
acx01000_unpatched.sys - Patched Binary:
acx01000_patched.sys - Overall Similarity: 98.75%
- Diff Statistics: 1223 matched functions, 13 changed functions, 1210 identical functions, 0 unmatched.
- Verdict: The patch adds conditional WPP/ETW trace instrumentation to the
AfxDataFormatListdata-format list operations (add / remove / destroy), gated by a WIL feature flag, and refines de-duplication bookkeeping in the WIL feature-usage reporting cache. The remaining changed functions are WIL feature-staging and feature-configuration-change-notification registration churn plus WPP tracing. No memory-safety vulnerability is fixed or introduced by this patch; the changed list-management functions use consistent structure offsets across both versions.
2. Change Summary
Finding 1: Conditional ETW Instrumentation in AfxDataFormatList Cleanup
- Severity: Informational (non-security)
- Class: Telemetry / instrumentation
- Affected Functions:
Acx::AfxDataFormatList::~AfxDataFormatList— unpatched scalar-deleting destructor??_GAfxDataFormatList@0x1C0008ED8, patched??1AfxDataFormatList@0x1C0008B6CAcx::AfxDataFormatList::AddDataFormat@0x1C000818C(unpatched) /0x1C0008D60(patched)Acx::AfxDataFormatList::RemoveDataFormat@0x1C00084B4(unpatched) /0x1C00090D0(patched)
Description:
AfxDataFormatList maintains a doubly-linked list of AfxDataFormat pool allocations (pool tag 'AfxD' / 0x44786641) anchored at structure offset +0x30. The insert (AddDataFormat), remove (RemoveDataFormat), and destructor all use offset +0x30 for this list, and they do so identically in both the unpatched and patched binaries. The list offset is unchanged.
The patch adds conditional WPP/ETW trace records around these list operations, gated by Feature_Servicing_Audio_ACXGetNotificationDevice__private_IsEnabledDeviceUsage(). When the feature is enabled, a trace record is emitted as each AfxDataFormat entry is unlinked and freed with ExFreePoolWithTag. This is instrumentation only; the freeing logic and list traversal are otherwise unchanged.
Acx::AfxTargetPin:: scalar deleting destructor (unpatched 0x1C0005368, patched 0x1C0005CF8) is a separate class's destructor that walks its own list at offset +0x80; it uses +0x80 in both versions and is functionally unchanged.
Finding 2: WIL Feature-Usage Reporting Cache De-duplication Refinement
- Severity: Informational (non-security)
- Class: Telemetry / feature-staging bookkeeping
- Affected Function:
wil_details_FeatureReporting_RecordUsageInCache(unpatched0x1C0001ABC/ patched0x1C00022E4)
Description:
This is Windows Implementation Library (WIL) feature-usage reporting cache code. It fills a caller-supplied 24-byte report descriptor (a1) and updates the per-feature usage bits held in *a2 via an interlocked compare-exchange loop. In the unpatched version, after the compare-exchange loop the report-descriptor fields at a1+4 (kind = 1), a1+8 (= a3) and a1+12 (= a4) are written unconditionally. The patched version writes those fields only when the usage was not already recorded this session — that is, when the reporting-index is out of range (>= 0x40) or when the "already recorded" flag stored at a1+16 is zero after the loop (a cache miss). On a cache hit the patched build skips re-populating the descriptor, so an already-reported usage is not re-emitted. The bounds written into a1 (offsets 0 through 16) are identical in both builds. This is a de-duplication refinement in WIL's usage-reporting cache; it changes what gets reported to telemetry, not memory safety.
3. Pseudocode Diff
Acx::AfxDataFormatList::~AfxDataFormatList (unpatched 0x1C0008ED8 → patched 0x1C0008B6C)
// UNPATCHED ~AfxDataFormatList (0x1C0008ED8)
void ~AfxDataFormatList(AfxDataFormatList* obj) {
ListEntry* list_head = (ListEntry*)((char*)obj + 0x30); // list anchor at +0x30
while (list_head->Flink != list_head) {
ListEntry* entry = list_head->Flink;
UnlinkEntry(entry);
ExFreePoolWithTag(entry, 'AfxD'); // free 'AfxD' entry
}
}
// PATCHED ~AfxDataFormatList (0x1C0008B6C)
void ~AfxDataFormatList(AfxDataFormatList* obj) {
bool log_enabled = Feature_..._ACXGetNotificationDevice_IsEnabledDeviceUsage();
ListEntry* list_head = (ListEntry*)((char*)obj + 0x30); // SAME anchor at +0x30
while (list_head->Flink != list_head) {
ListEntry* entry = list_head->Flink;
if (log_enabled)
WppTraceFree(entry); // NEW: conditional trace record
UnlinkEntry(entry);
ExFreePoolWithTag(entry, 'AfxD');
}
}
4. Assembly Analysis
Patched ~AfxDataFormatList (0x1C0008B6C) — list walk with new instrumentation
0x1c0008c0c: lea rbx, [rsi+0x30] ; list anchor at +0x30 (unchanged)
0x1c0008c10: call Feature_..._ACXGetNotificationDevice_IsEnabledDeviceUsage
0x1c0008c15: test eax, eax ; feature flag gate for tracing
0x1c0008c71: call qword [rel __guard_dispatch_icall_fptr]
0x1c0008c7f: call qword [rel __imp_ExFreePoolWithTag] ; free 'AfxD' entry
The unpatched scalar-deleting destructor at 0x1C0008ED8 performs the same +0x30 list walk and ExFreePoolWithTag free without the feature-gated trace calls.
5. Behavioral Notes
- The
AfxDataFormatListlist anchor is+0x30in both binaries;AddDataFormat,RemoveDataFormat, and the destructor agree on this offset in both versions. - The
AfxTargetPindestructor uses+0x80for its own (different) list in both versions; this offset is correct for that class and unchanged. - The only functional delta on the
AfxDataFormatListpath is the addition of feature-gated WPP/ETW trace records.
6. Changed Functions — Full Triage
Acx::AfxDataFormatList::~AfxDataFormatList(unpatched0x1C0008ED8/ patched0x1C0008B6C, Sim: 0.8058 in the diff pairing): [Informational] Added feature-gated WPP/ETW trace records around the+0x30'AfxD'list free loop. List offset unchanged.sub_1C00084B4(RemoveDataFormat) (Sim: 0.9545): [Informational] Added conditional ETW logging when removing/freeing list entries.sub_1C000818C(AddDataFormat) (Sim: 0.9719): [Informational] Added conditional ETW logging when inserting list entries.wil_details_FeatureReporting_RecordUsageInCache(unpatched0x1C0001ABC/ patched0x1C00022E4, Sim: 0.9808): [Informational] WIL usage-reporting cache now skips re-populating the report descriptor on a cache hit (already-recorded usage). De-duplication bookkeeping;a1output bounds unchanged.wil_details_FeatureStateCache_TryEnableDeviceUsageFastPath(unpatched0x1C0001E78/ patched0x1C00027D0): [Behavioral, non-security] WIL feature-state cache. Unpatched unconditionally set bit0x10in the multi-stack-support feature-state word; patched takes the feature-state pointer and kind as parameters and conditionally sets bit0x10or0x20via an interlocked update. Feature-staging infrastructure, not memory safety.wil_details_FeatureReporting_ReportUsageToServiceDirect(unpatched0x1C0001D88/ patched0x1C00025BC): [Behavioral, non-security] WIL usage-reporting. Unpatched hard-coded the feature id7189701and the static_reportingglobal; patched reads the feature id and reporting pointer from its parameters. SameRecordUsageInCache/RtlNotifyFeatureUsageflow, now parameterized. Feature-staging telemetry, not memory safety.sub_1C002EC10(Sim: 0.8804): [Behavioral] Added cleanup forRtlUnregisterFeatureConfigurationChangeNotification.sub_1C0091790&sub_1C0090C30&sub_1C0070620&sub_1C007C8F0&sub_1C00A9008(Sim: 0.88 - 0.94): [Cosmetic] Telemetry notification refactoring and data reference relocations.sub_1C001628C(Sim: 0.9796): [Cosmetic] Register renaming and small ETW updates.
7. Unmatched Functions
There are no added or removed functions. The patch consists entirely of in-place modifications.
8. Confidence & Caveats
- Confidence: High. Both the unpatched (
0x1C0008ED8) and patched (0x1C0008B6C)AfxDataFormatListdestructors walk the+0x30list and free'AfxD'entries; the patched version differs only by feature-gated trace calls.AddDataFormat/RemoveDataFormatuse+0x30in both versions.AfxTargetPin's destructor (0x1C0005368unpatched /0x1C0005CF8patched) uses+0x80in both versions.