From 5f90ddc085c18b0082374b3e87171b99ffe905bb Mon Sep 17 00:00:00 2001 From: lhodges1 Date: Sat, 26 Aug 2023 23:29:12 +1000 Subject: [PATCH] e --- driver/pool.c | 90 ++++++++++++++++++++++++++++++++++++--------------- driver/pool.h | 7 ++++ 2 files changed, 71 insertions(+), 26 deletions(-) diff --git a/driver/pool.c b/driver/pool.c index ef67993..f35885f 100644 --- a/driver/pool.c +++ b/driver/pool.c @@ -46,6 +46,53 @@ end: return debugger_data; } +VOID ScanPageForProcessAllocations( + _In_ UINT64 PageBase, + _In_ ULONG PageSize +) +{ + if ( !PageBase || !PageSize ) + return; + + CHAR process[ 4 ] = { 'Proc' }; + + DEBUG_LOG( "1: %hhx, 2: %hhx, 3: %hhx, 5: %hhx", process[ 0 ], process[ 1 ], process[ 2 ], process[ 3 ] ); + + __debugbreak(); + + for ( INT offset = 0; offset < PageSize; offset++ ) + { + if ( !MmIsAddressValid( PageBase + offset ) ) + continue; + + CHAR current_char = *( PCHAR )( PageBase + offset ); + } +} + +/* +* This is your basic page table walk function. On intel systems, paging has 4 levels, +* each table holds 512 entries with a total size of 0x1000 (512 * sizeof(QWORD)). Each entry +* in each table contains a value with a subset bitfield containing the physical address +* of the base of the next table in the structure. So for example, a PML4 entry contains +* a physical address that points to the base of the PDPT table, it is the same for a PDPT +* entry -> PD base and so on. +* +* However, as with all good things Windows has implemented security features meaning +* we cannot use functions such as MmCopyMemory or MmMapIoSpace on paging structures, +* so we must find another way to walk the pages. Luckily for us, there exists +* MmGetVirtualForPhysical. This function is self explanatory and returns the corresponding +* virtual address given a physical address. What this means is that we can extract a page +* entry physical address, pass it to MmGetVirtualForPhysical which returns us the virtual +* address of the base of the next page structure. This is because page tables are still +* mapped by the kernel and exist in virtual memory just like everything else and hence +* reading the value at all 512 entries from the virtual base will give us the equivalent +* value as directly reading the physical address. +* +* Using this, we essentially walk the page tables as any regular translation would +* except instead of simply reading the physical we translate it to a virtual address +* and extract the physical address from the value at each virtual address page entry. +*/ + VOID WalkKernelPageTables() { CR3 cr3; @@ -60,41 +107,33 @@ VOID WalkKernelPageTables() PTE pt_base; PTE pt_entry; UINT64 base_physical_page; + UINT64 base_virtual_page; PHYSICAL_ADDRESS physical; cr3.BitAddress = __readcr3(); - DEBUG_LOG( "cr3: %llx", cr3.BitAddress ); + physical.QuadPart = cr3.Bits.PhysicalAddress << PAGE_4KB_SHIFT; - physical.QuadPart = cr3.Bits.PhysicalAddress << 12; - - /* Get our PML4 base address */ pml4_base.BitAddress = MmGetVirtualForPhysical( physical ); - if ( !MmIsAddressValid(pml4_base.BitAddress) || !pml4_base.BitAddress ) - { - DEBUG_ERROR( "Pml4 base is null or invalid" ); + if ( !MmIsAddressValid( pml4_base.BitAddress ) || !pml4_base.BitAddress ) return; - } - for ( INT pml4_index = 0; pml4_index < 512; pml4_index++ ) + for ( INT pml4_index = 0; pml4_index < PML4_ENTRY_COUNT; pml4_index++ ) { - /* get our PML4 entry*/ pml4_entry.BitAddress = *(UINT64*)( pml4_base.BitAddress + pml4_index * sizeof( UINT64 ) ); - /* check the present bit */ if ( pml4_entry.Bits.Present == NULL ) continue; - /* read our pml4 entry */ - physical.QuadPart = pml4_entry.Bits.PhysicalAddress << 12; + physical.QuadPart = pml4_entry.Bits.PhysicalAddress << PAGE_4KB_SHIFT; pdpt_base.BitAddress = MmGetVirtualForPhysical( physical ); if ( !pdpt_base.BitAddress || !MmIsAddressValid( pdpt_base.BitAddress ) ) continue; - for ( INT pdpt_index = 0; pdpt_index < 512; pdpt_index++ ) + for ( INT pdpt_index = 0; pdpt_index < PDPT_ENTRY_COUNT; pdpt_index++ ) { pdpt_entry.BitAddress = *( UINT64* )( pdpt_base.BitAddress + pdpt_index * sizeof( UINT64 ) ); @@ -103,21 +142,19 @@ VOID WalkKernelPageTables() if ( IS_LARGE_PAGE( pdpt_entry.BitAddress ) ) { + /* 2GB size page */ pdpt_large_entry.BitAddress = pdpt_entry.BitAddress; - - //scan large page bla bla - continue; } - physical.QuadPart = pdpt_entry.Bits.PhysicalAddress << 12; + physical.QuadPart = pdpt_entry.Bits.PhysicalAddress << PAGE_4KB_SHIFT; pd_base.BitAddress = MmGetVirtualForPhysical( physical ); if ( !pd_base.BitAddress || !MmIsAddressValid( pd_base.BitAddress ) ) continue; - for ( INT pd_index = 0; pd_index < 512; pd_index++ ) + for ( INT pd_index = 0; pd_index < PD_ENTRY_COUNT; pd_index++ ) { pd_entry.BitAddress = *( UINT64* )( pd_base.BitAddress + pd_index * sizeof( UINT64 ) ); @@ -128,34 +165,35 @@ VOID WalkKernelPageTables() { /* 2MB size page */ pd_large_entry.BitAddress = pd_entry.BitAddress; - - //scan etc. - continue; } - physical.QuadPart = pd_entry.Bits.PhysicalAddress << 12; + physical.QuadPart = pd_entry.Bits.PhysicalAddress << PAGE_4KB_SHIFT; pt_base.BitAddress = MmGetVirtualForPhysical( physical ); if ( !pt_base.BitAddress || !MmIsAddressValid( pt_base.BitAddress ) ) continue; - for ( INT pt_index = 0; pt_index < 512; pt_index++ ) + for ( INT pt_index = 0; pt_index < PT_ENTRY_COUNT; pt_index++ ) { pt_entry.BitAddress = *( UINT64* )( pt_base.BitAddress + pt_index * sizeof( UINT64 ) ); if ( pt_entry.Bits.Present == NULL ) continue; - base_physical_page = pt_entry.Bits.PhysicalAddress << 12; - + physical.QuadPart = pt_entry.Bits.PhysicalAddress << PAGE_4KB_SHIFT; + base_virtual_page = MmGetVirtualForPhysical( physical ); + + ScanPageForProcessAllocations( base_virtual_page, PAGE_BASE_SIZE ); } } } } + DEBUG_LOG( "Finished scanning memory" ); + } VOID ScanNonPagedPoolForProcessTags() diff --git a/driver/pool.h b/driver/pool.h index ff67055..5eb2d01 100644 --- a/driver/pool.h +++ b/driver/pool.h @@ -6,6 +6,13 @@ #define POOL_DUMP_BLOCK_TAG 'dump' #define POOL_DEBUGGER_DATA_TAG 'data' +#define PML4_ENTRY_COUNT 512 +#define PDPT_ENTRY_COUNT 512 +#define PD_ENTRY_COUNT 512 +#define PT_ENTRY_COUNT 512 + +#define PAGE_BASE_SIZE 0x1000 + /* creds: https://www.unknowncheats.me/forum/2602838-post2.html */ typedef struct _DBGKD_DEBUG_DATA_HEADER64