Skip to content

Fix PAE DTB detection rejecting valid 4-entry PDPTs#1993

Closed
ricardojrdez wants to merge 1 commit into
volatilityfoundation:developfrom
ricardojrdez:fix/pae-dtb-dummy-threshold
Closed

Fix PAE DTB detection rejecting valid 4-entry PDPTs#1993
ricardojrdez wants to merge 1 commit into
volatilityfoundation:developfrom
ricardojrdez:fix/pae-dtb-dummy-threshold

Conversation

@ricardojrdez

Copy link
Copy Markdown

On PAE 32-bit Windows images the WindowsIntelStacker discarded the correct WindowsIntelPAE DTB and fell back to a false-positive non-PAE DTB, leaving list-walking plugins (e.g. windows.pslist) empty while pool scanners still worked.

Both DTB candidates are found and the PAE one sorts first, but page_table_is_dummy() required at least 10 valid pointers. A PAE top-level table is the PDPT pointed to by CR3, which legitimately holds only four entries, so the valid PAE DTB was rejected as a dummy table and the stacker fell through to the bogus non-PAE candidate.

Make the dummy-table threshold PAE-aware (4 entries for WindowsIntelPAE, 10 otherwise). The x64/non-PAE detection path is unchanged.

Validated on a PAE XP image (windows.pslist now lists all processes with IsPAE=True) and regression-checked on an x64 image (still WindowsIntel32e).

On PAE 32-bit Windows images the WindowsIntelStacker discarded the correct
WindowsIntelPAE DTB and fell back to a false-positive non-PAE DTB, leaving
list-walking plugins (e.g. windows.pslist) empty while pool scanners still
worked.

Both DTB candidates are found and the PAE one sorts first, but
page_table_is_dummy() required at least 10 valid pointers. A PAE top-level
table is the PDPT pointed to by CR3, which legitimately holds only four
entries, so the valid PAE DTB was rejected as a dummy table and the stacker
fell through to the bogus non-PAE candidate.

Make the dummy-table threshold PAE-aware (4 entries for WindowsIntelPAE, 10
otherwise). The x64/non-PAE detection path is unchanged.

Validated on a PAE XP image (windows.pslist now lists all processes with
IsPAE=True) and regression-checked on an x64 image (still WindowsIntel32e).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Abyss-W4tcher

Copy link
Copy Markdown
Contributor

Hi @ricardojrdez, we've been working on improving this check by not relying on an arbitrary number of pointers. Could you please try out this branch: #1992 against your sample and tell us if it solves the issue? Thanks

@ricardojrdez

Copy link
Copy Markdown
Author

Hey @Abyss-W4tcher , thanks for the alternative approach. I tested #1992 against both of my samples and it works great.

  • PAE x86 (the original failing case, a WinXP SP2, ntkrnlpa.pdb BD8F451F…-1):

    • DtbSelfRefPae now succeeds at 0x319000 (the correct PAE DTB)
    • DTB was found at: 0x319000
    • windows.pslist -> 25 processes -> OK!

    Previously this picked a false-positive non-PAE DTB at 0x39000 because the PAE top-level table (PDPT) only has 4 entries and was rejected by the old page_table_is_dummy() >= 10-pointer heuristic. Your _KUSER_SHARED_DATA translation check handles it correctly without relying on a pointer count.

  • x64 regression (Windows, ntkrnl):

    • DtbSelfRef64bit succeeds at 0x1ae000 -> WindowsIntel32e
    • windows.pslist -> 220 processes -> OK!

So no regression on the 64-bit path either. The translation-check approach is a much cleaner fix than counting pointers. I'm happy to close #1993 in favor of this.

@Abyss-W4tcher

Copy link
Copy Markdown
Contributor

Nice, thank you for testing it! As everything worked as expected then closing it in favor of #1993 would be much appreciated yes 👍.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants