For this exercise, we will use the virtual address of Nt!NtCreateFile as an example and we will convert that address to physical address and compare what's there.
In this example, we use 32-bit windows PAE mode and we can check if windows is in PAE mode in several ways and one easy way to find out if we are running on PAE kernel is to look up where PDE is loaded. If you see that PDE is loaded at 0xC0600000, it is PAE kernel. Please refer to Free System Page Table Entries blog post for more info on it.
PAE mode has the following three level page tables so we need to keep this in mind as we translate.
- Page Directory Pointer Table
- Page Directory
- Page Table
0. Locate virtual address of NtCreateFile
kd> x nt!ntcreatefile
8286f2a2 nt!NtCreateFile = no type information
kd> !pte nt!ntcreatefile
VA 8286f2a2PDE at C06020A0 PTE at C0414378
contains 00000000001D0063 contains 000000000286F121
pfn 1d0 ---DA--KWEV pfn 286f -G--A--KREV
1. Find the current process
kd> !process -1 0
PROCESS 85b9fbb0 SessionId: 0 Cid: 03d0 Peb: 7ffd5000 ParentCid: 0238
DirBase: 7ef5b1a0 ObjectTable: 8a585968 HandleCount: 594.
Image: svchost.exe
2. Check cr3 value for the location of PDPT. This should be same as DirBase from #1 result.
kd> r cr3
cr3=7ef5b080
3. Get binary representation of NtCreateFile virtual address
kd> .formats 0x8286f2a2
Evaluate expression:
Hex: 8286f2a2
Decimal: -2105085278
Octal: 20241571242
Binary: 10000010 10000110 11110010 10100010
.. skip ...
Let us split binary values as follows so that we can use them as an index to tables.
10(index to PDPT) 000010100(index to PDE) 001101111(index to PTE) 001010100010(offset)
4. Get to PDPT entry - 0y means it is binary number representation and l1 means only one entry (it is english alphabet 'l' not pipe '|')
kd> dd /p @cr3+0y10*8 l1
7ef5b090 1ad8b801
5. Check what's in the entry - only the first 20 bits are used and the rest are for flags
kd> .formats 1ad8b801
Evaluate expression:
Hex: 1ad8b801
Decimal: 450410497
Octal: 03266134001
Binary: 00011010 11011000 10111000 00000001
... skip ...
6. Get the address of PDE (Not necessary but this is one way to do hex value converting)
kd> ? 0y00011010110110001011
Evaluate expression: 109963 = 0001ad8b
7. Get to PDE for this particular address
kd> dd /p 0x0001ad8b * 0x1000 + 0y10100 * 8 |1
1ad8b0a0 001d0063
8. Get to PTE
kd> dd /p 0x1d0 * 0x1000 + 0y1101111 * 8 |1
001d0378 0286f121
9. Finally get the actual physical address and this time we do not need to multiply by 8
kd> up 0x286f000+0y1010100010
0286f2a2 8bff mov edi,edi
0286f2a4 55 push ebp
0286f2a5 8bec mov ebp,esp
0286f2a7 51 push ecx
0286f2a8 33c0 xor eax,eax
0286f2aa 50 push eax
0286f2ab 6a20 push 20h
0286f2ad 50 push eax
10. Let us compare disassembly from virtual address
kd> uf nt!ntcreatefile
nt!NtCreateFile:
8286f2a2 8bff mov edi,edi
8286f2a4 55 push ebp
8286f2a5 8bec mov ebp,esp
8286f2a7 51 push ecx
8286f2a8 33c0 xor eax,eax
8286f2aa 50 push eax
8286f2ab 6a20 push 20h
8286f2ad 50 push eax
8286f2ae 50 push eax
They have the same content so we were able to translate the address. Cool!
No comments:
Post a Comment