mit einem Klick
extract-udwm-offsets
// Extract all udwm.dll struct member and vtable offsets from the current IDA instance. Follow 7 phases in order — do NOT skip. Output ready-to-paste C++ for uDwmProjection.Offsets.hpp.
// Extract all udwm.dll struct member and vtable offsets from the current IDA instance. Follow 7 phases in order — do NOT skip. Output ready-to-paste C++ for uDwmProjection.Offsets.hpp.
| name | extract-udwm-offsets |
| description | Extract all udwm.dll struct member and vtable offsets from the current IDA instance. Follow 7 phases in order — do NOT skip. Output ready-to-paste C++ for uDwmProjection.Offsets.hpp. |
| disable-model-invocation | true |
| allowed-tools | Bash(git *) mcp__ida-pro-mcp__* |
Extract offsets from the udwm.dll currently loaded in IDA Pro. Follow every phase, in order. Do not skip. Do not summarize until the final phase.
GetOffset, GetSize, GetHwnd as standalone functions..hpp output rules including feature gates.Each offset struct in uDwmProjection.Offsets.hpp now has inline comments documenting:
When re-extracting offsets for a new build, read the comment above each struct first — it tells you exactly which function to decompile and what pattern to look for.
survey_binary → record md5, path hintOSHelper.hpp for existing build constants| Feature check | Means at least |
|---|---|
CContainerVisual present (search ??0CContainerVisual or check if CTopLevelWindow ctor takes CWindowData*) | Windows 11 24H2 |
CDWriteText present (search ??0CDWriteText or CDWriteText::Create) | Windows 11 22H2 |
CAcrylicSheet present (search ??0CAcrylicSheet) instead of CAnimatedGlassSheet | Windows 11 21H2 |
Feature gates:
GetSystemBackdropType → 21H2+ only (WinUI 3 backdrop feature)GetDWriteTextVisual_Index → 22H2+ (not 24H2+; appears with CDWriteText)_OnLegacy variants (GetBorderGeometry/CaptionGeometry/CaptionBrush/BorderBrush) → 22H2+ (CLegacyNonClientBackground introduced)CWindowBorder / GetWindowBorder_Index / GetIsBorderUpdatesSuppressed → 21H2+ (present in 21H2 RTM; do NOT assume 22H2+)CTopLevelWindow base class: CVisual (pre-24H2) → CContainerVisual (24H2+)CAnimatedGlassSheet → pre-21H2; replaced by CAcrylicSheet in 21H2+[!IMPORTANT] The hpp entry's
.buildfield is the interval right boundary, NOT the feature introduction point. A feature may exist in builds BEFORE the first hpp entry. Always search the binary for the class/function (e.g.CWindowBorder,SetSuppressBorderUpdates) to confirm existence rather than inferring absence from the hpp chain.
Output the build classification and expected codebase generation before continuing.
[!IMPORTANT] Do NOT blindly trust existing
.hppentries. Every offset must be independently verified from the actual IDA data. However, when your reading disagrees with the.hpp, double-check your interpretation before claiming the.hppis wrong — it has been validated across many builds. Also check for unit mistakes: a byte flag entry usingsizeof(ULONG_PTR)is likely wrong (e.g.128 * sizeof(ULONG_PTR)should be just128).
Gate check: search for the CVisual constructor (??0CVisual@@IEAA@XZ). Decompile it. If absent, CVisual removed — skip phase.
For each offset, see the comment in uDwmProjection.Offsets.hpp for the exact accessor function and pseudocode pattern.
It initializes members to 0, 1.0f (float) or 0x3FF0000000000000 (double 1.0), or sentinel values like -1, -2, 0x7FFFFFFF. Each assignment reveals a member:
| Member | Constructor pattern |
|---|---|
| VisualProxy | *(QWORD*)(this+N) = 0 — first pointer after vtable |
| TransformParent (member) | *(QWORD*)(this+N) = 0 — adjacent pointer slot |
| VisualCollection | *(QWORD*)(this+N) = &VisualCollection::vftable (pre-22H2) or absent (22H2+) |
| Scale (D2D1) | *(float*)(this+N) = 1.0f ×2 (X and Y adjacent floats) |
| Scale (MilSizeD) | *(double*)(this+N) = 1.0 (pre-22H2) or separate from D2D scale (22H2+) |
| Inset sentinels | *(DWORD*)(this+N) = 0x7FFFFFFF repeated 4 times in sequence |
Map each to a named offset by comparing with the existing .hpp entry that matches the same codebase generation.
| Offset | Set* accessor | Assembly pattern |
|---|---|---|
| GetScale_D2D1_SIZE_F | SetScale@CVisual | *((float*)this + N) ×2 — two adjacent floats |
| GetSize | SetSize@CVisual | [rcx+N] for SIZE width/height — two DWORD compares then store |
| GetOffset | SetOffset@CVisual | [rcx+N] for POINT x/y — same pattern |
| GetDirtyFlags | SetDirtyFlags@CVisual | [rcx+N] DWORD read-modify-write |
| IsRTLMirrored | SetRTLMirror@CVisual | [rcx+N] byte bit-test (reads byte, toggles bit) |
| SetExcludeSubtree | Same function or nearby | Different bit at same or different byte |
Read the CVisual vtable (address from constructor: *(QWORD*)this = &CVisual::vftable). Decode 8-byte slots, look up function addresses.
| Offset | How to identify |
|---|---|
| GetTransformParent | Find GetTransformParent@CVisual in vtable → slot × 8 |
| _ValidateVisual | Find ValidateVisual@CVisual in vtable → slot × 8 |
| GetDirtyFlags (vtable) | Find SetDirtyFlags@CVisual in vtable → slot × 8 |
Critical: these are VTABLE SLOT indices, not member data offsets. The function body reads a member at a fixed offset (e.g. [rcx+18h] for GetTransformParent), but the .hpp offset is slot_index × sizeof(ULONG_PTR).
Gate check: functions like CWindowList::BlurBehindChange or CLivePreview::_CollectWindows reference CWindowData members. If absent, class removed.
Most CWindowData getters are inlined. See uDwmProjection.Offsets.hpp for the exact accessor function for each offset.
| Offset | Accessor | How to identify |
|---|---|---|
| GetHwnd | CLivePreview::_CollectWindows | *(HWND*)(data+40) — 5×PTR; HWND is 8 bytes on x64 |
| GetWindowContext | Constructor or GetWindowBand | *(QWORD*)(this+N) — 3×PTR |
| GetWindow_Index | CWindowList::BlurBehindChange | *(QWORD*)(data+N) → pointer back to CTopLevelWindow |
| GetAccentPolicy | CTopLevelWindow::UpdateAccent or CAccent::UpdateAccentPolicy | *(QWORD*)(this+N) |
| GetSystemBackdropType | 21H2+ only. CWindowList::SetSystemBackdropType (21H2+) or CTopLevelWindow::GetEffectiveSystemBackdropType (22H2+) | *(DWORD*)(this+N×4) — SetSystemBackdropType writes the DWORD directly |
| GetWindowDPI | CTopLevelWindow::CalculateOutsideMargins | *(unsigned int*)(this+N×4) |
| GetNonClientAttribute | CWindowList::BlurBehindChange | *(BYTE*)(data+N) bit-test — not necessarily near ClientBlur |
| GetClientBlurAttribute | Same function | *(BYTE*)(data+N) bit-test — verify independently, do NOT assume NonClient+1 |
| GetWindowRect | CLivePreview::_CollectWindows | *(RECT*)(data+N) |
| GetClientMargins | Constructor or CalculateOutsideMargins | *(MARGINS*)(this+N) |
| GetExtendedFrameMargins | Same | *(MARGINS*)(this+N) |
Gate check: find Create@CTopLevelWindow or the constructor. Record allocation size and vtable assignments.
First: decompile the constructor. All pointer-index slots are zero-initialized in sequence. The constructor also initializes MARGINS structures at fixed byte offsets.
Key structural notes:
CVisual, constructor takes no parametersCContainerVisual, constructor takes CWindowData*BlurBehindChange: *(QWORD*)(data + GetWindow_Index) = thisFor each specific offset, see the comment in uDwmProjection.Offsets.hpp.
For each offset, see the comment in uDwmProjection.Offsets.hpp for the exact accessor function and pseudocode pattern.
Key gotchas documented in the offset comments:
CButton::SetVisualStates, NOT UpdateCurrentGlyphOpacityAddInstruction/ClearInstructions, NOT WriteInstructionShouldDrawAtlasImage/ShouldCloneAtlasImage, NOT SetDirtyFlagsSetScale takes float or double paramsSetScale takes double, MilSizeD is in use and D2D1 scale may not existGate check: verify CLivePreview::Create and CDesktopManager::Initialize exist. If absent, skip affected offsets.
For each offset, see the comment in uDwmProjection.Offsets.hpp.
Key structural notes:
sizeof(ULONG_PTR) index)GetD2DDevice_OnThis, GetDCompDevice_OnThis): removed in 21H2+ when CGraphicsManager/CInteropManager took over. No build=0.Gate check: CLivePreview::_UpdateResourcesForMonitor must exist. CAnimatedGlassSheet is pre-21H2 only; if using 21H2+, verify CAcrylicSheet instead.
For each offset, see the comment in uDwmProjection.Offsets.hpp.
Key gotchas:
_UpdateResourcesForMonitorHelper (first IntersectRect call, third arg is MonitorRect), NOT _UpdateResourcesForMonitor×sizeof(ULONG_PTR) or ×PTRsizeof(RECT) units. Atlas padding RECTs are found in Initialize near the end of the method================================================================
COMPLETE uDWM OFFSET REPORT — <build description>
image_size: 0x... functions: N codebase: <17763|18362|19041|22000|22621|26100|28100>
================================================================
CHANGED FROM PREVIOUS BUILD:
OffsetName: old → new (source function)
UNCHANGED:
[✓] OffsetName value (source function)
SKIPPED — CLASS/FEATURE REMOVED:
[✗] OffsetName — reason (e.g. "GetSystemBackdropType absent pre-21H2")
REMOVED IN THIS BUILD (member gone, class still exists):
[✗] OffsetName — no code accesses this member
NOT VERIFIED (accessor not found, may be renamed):
[?] OffsetName — reason
TOTAL: N verified (M changed, X unchanged), Y skipped/removed, Z not verified
================================================================
Most uDWM offsets only change at recompile boundaries. Within the same codebase generation, they are identical. The most volatile: CTopLevelWindow pointer indices, CWindowData size-based offsets, and MARGINS positions.
Before emitting C++: Apply output rules from decompilation.md. Member exists → build=0 last entry. Member removed → no build=0. Feature gated (e.g. 21H2+) → first entry names the gate build.
Only after all phases complete and report is shown, ask whether the user wants C++ emitted.