Wednesday, 20 September 2017

Practical Reverse Engineering Exercise Solutions: Page 35 / Exercise 11

Read the Virtual Memory chapter in Intel Software Developer Manual,
Volume 3 and AMD64 Architecture Programmer’s Manual, Volume 2: System Programming. Perform a few virtual address to physical address translations yourself and verify the result with a kernel debugger. Explain how data execution prevention (DEP) works.

For this exercise, we first have to set up a remote kernel debugging session. (see https://codemetrix.net/windows-kernel-debugging-setup/https://securityblog.gr/3253/debug-user-mode-processes-using-a-kernel-debugger/ and http://securityblog.gr/3023/windows-kernel-debugging/ for excellent explanations)
Local kernel debugging is not an option in this case since examining register contents requires remote kernel debugging.
As a reminder, WinDbg has two different commands for inspecting memory contents:

d* commands (e.g., db): Display memory data at a specified virtual address
!d* commands (e.g., !db): Display data at a specified physical address

We perform a couple of translations from virtual addresses to physical addresses:

kd> db 8283c054 L8
8283c054  72 6f 67 72 61 6d 20 63 rogram c

The binary representation of this address yields:

10000010100000111100000001010100‬

By splitting this binary representation into groups, we obtain the indices for the PT:

‭10 000010100 000111100 000001010100‬

Index into page directory pointer table (PDPT): 10  (0x2)
Index into page directory (PD): 000010100 (0x14)
Index into  page table (PT):000111100 (0x3C)
Page offset: 000001010100‬ (0x54)

kd> r @cr3
cr3=00185000

The CR3 register contains the base address of the page directory pointer table (PDPT).
We continue to calculate the PDPT entry:

kd> !dq @cr3+2*8 L1
#  185010 00000000`00188001

Of course, we could employ another program for converting, such as hexadecimal to binary representations.
But WinDbg has already implemented a command for this very purpose, namely .formats.

kd> .formats 00000000`00188001
Evaluate expression:
Hex:     00188001
Decimal: 1605633
Octal:   00006100001
Binary:  00000000 00011000 10000000 00000001
Chars:   ....
Time:    Mon Jan 19 15:00:33 1970
Float:   low 2.24997e-039 high 0
Double:  7.93288e-318

The bottom 12 bits of the PDPT entry have to be cleared, which yields:

00000000 00011000 10000000 00000000

Converted to hex: 0x188000

The page directory entry is in turn calculated by adding the index into PD to the PDPT base:

kd> !dq 188000+0x14*8 L1
#  1880a0 00000000`001d0063

Converted to binary: 00000000 00011101 00000000 01100011

Similarly to the previous step, we have to clear the lowest 12 bits to calculate the base of the page table (PT):

00000000 00011101 00000000 00000000

Converted to hex: 0x‭1D0000

The page table entry is calculated as follows:

kd> !dq 1D0000+0x3C*8 L1
#  1d01e0 00000000`0283c963

Converted to binary: 00000010 10000011 11001001 01100011

Similarly to the previous step, we clear the lowest 12 bits and obtain:

00000010 10000011 11000000 00000000

Converted to hex: 0x283C000

Finally, we can add the page offset to the page entry base to calculate the page's physical address:

kd> !db 0x283C000+0x54 L8
# 283c054 72 6f 67 72 61 6d 20 63 rogram c .L.....

We can confirm the contents of physical address 0x283c054 and virtual address 0x8283c054 are identical:

kd> db 0x8283c054 L8
8283c054  72 6f 67 72 61 6d 20 63 rogram c

As the manual calculation is a rather cumbersome process, WinDbg has already implemented a function to calculate the physical address of a virtual address. In addition to the virtual address, it requires the base address of the page directory pointer table as an input (https://zerosum0x0.blogspot.de/2015/01/practical-reverse-engineering-p-36-11.html)

kd> !vtop 00185000 8283c054
X86VtoP: Virt 8283c054, pagedir 185000
X86VtoP: PAE PDPE 185010 - 0000000000188001
X86VtoP: PAE PDE 1880a0 - 00000000001d0063
X86VtoP: PAE PTE 1d01e0 - 000000000283c963
X86VtoP: PAE Mapped phys 283c054

Nevertheless, we perform another translation from virtual to physical address manually:

kd> db 83e31738 L8
83e31738  41 db e8 59 e9 0c 00 00

‭10 000011111 000110001 011100111000‬

PDPT Index: 0x2
PD Index: 0x1F
PT Index: 0x31
Page Offset: 0738

kd> r @cr3
cr3=00185000

PDPT base:
kd> !dq @cr3+0x2*8 L1
#  185010 00000000`00188001

Binary: 110001000000000000001
Truncated: 110001000000000000000 (0x188000)

PD Base:
kd> !dq 188000+0x1F*8 L1
#  1880f8 00000000`1ff80863

Binary: 11111111110000000100001100011
Truncated: 11111111110000000000000000000 (0x1FF80000)

PT Base:
kd> !dq 0x1FF80000+0x31*8 L1
#1ff80188 00000000`1fc31963

Binary: 11111110000110001100101100011
Truncated: 11111110000110001000000000000 (0x1FC31000)