Tuesday, March 6, 2007

Windows 32-bit Memory Map

Debugging under Windows (even if you made the program that you are debugging) can feel like an expedition to a the amazon jungle; it is very easy to get lost. A thing that is known to help is to have a map and a compass. In case you actually don't visit jungles but like to explore crashdumps, spelunk with breakpoints or climb asserts then the following memory map of Windows would be of interest. This memory map is for 32 versions of Windows such as Windows XP and Windows Server 2003. At the end I have some notes & caveats that you might want to read.







Kernel


0xffffffff

Last virtual address


0xffdff120

Processor 0 Control Block (PRCB)


0xffdff000

Processor 0 Control Region (PCR)

KUSER

SHARED

DATA

0xffdf0300

Syscall stub pointer. Used like this:

mov edx, 0x7ffe0300; call dword ptr [edx]

0xffdf0000

SharedUserData start mapped RW (see 0x7ffe0000)


0xffc00000

Reserved for HAL usage


0xffbfffff

Crash dump driver area end

0xffbe0000

Crash dump driver area


0xffbdffff

End of system non-paged pool area








0xe1000000

Start of system paged area








0xc0c00000

System cache structures and working set list


0xc0800000

System cache begin address


0xc0400000

Process and hyperspace working set lists

Page tables

0xc03fffff


0xc0300000

Current process page directory (1024 entries) is mapped here. The CR3 points to same phys page

0xc0000000

Here is where the OS puts all the page tables for all processes


0xbc3fffff

Session paged pool end

0xbc000000

Session paged pool start




Kernel and HAL code

0x80a6b000

Ntoskernel.exe end address W2k3 SP1

0x80800000

Ntoskernel.exe base address W2k3 SP1

0x806eb780

Ntoskernel.exe end address XP SP2

0x804d7000

Ntoskernel.exe base address XP SP2

0x80036400

Interrupt descriptor table (IDT) 256 entries

0x80036000

Global descriptor table (GDT) 128 entries

0x80000000

Lowest kernel mode address



User


0x7fffffff

Highest user mode address

KUSER SHARED DATA

0x7ffe0300

Syscall stub pointer. Used like this:

mov edx, 0x7ffe0300; call dword ptr [edx]

0x7ffe02d8

TS Active console Id

0x7ffe0000

SharedUserData start (mapped RO)



Heap handles PEB.ProcessHeaps

PEB

0x7ffdf000

Process environment block (PEB) <notXPSP2>

TEB & TIB zone

0x7ffde000

1st thread environment block (TEB) 4kb

0x7ffdd000

2nd thread environment block (TEB) 4kb

0x7ffdc000

3rd thread environment block (TEB) 4kb




Core System DLLs


usual base address

0x7c8d0000

shell32.dll

0x7c800000

ntdll.dll

0x77f50000

advapi32.dll

0x77e40000

kernel32.dll

0x77c50000

rpcrt4.dll

0x77c00000

gdi32.dll

0x77670000

ole32.dll

0x77420000

comctl32.dll

0x77380000

user32.dll

Heaps

0x00b80000

Heap 3 (sample alloc 1MB)

0x00a70000

Heap 2 (sample alloc 1MB)

0x00960000

Heap 0 (sample alloc 1MB)

EXE


Usual base address


.rsrc section (icons, manifest)


.data section


.rdata section (Import address table (IAT))

0x00401000

.text section

0x00400000

PE header = ‘MZ’




Text support tables

0x00310000

Start of sorttbls.nls

0x002C0000

Start of sortkey.nls

0x00280000

Start of locale.nls (or 0x001c0000)

0x00260000

Start of Unicode.nls (or 0x001a0000)




Heaps

0x00250000

Heap 1 (sample alloc 16kB)

0x00150000

Heap 0 (sample alloc 64KB)




Stack of first thread

0x00130000

Stack base (typical)

0x0012ffe0

Typical location of first SEH frame

0x0012ffa8

Typical location of second SEH frame

0x0012ff08

EBP value in WinMain( ) entry

0x00126000

End of initially allocated stack

0x00030100

Typical stack end (~1MB) Typically not mapped


0x0002100A

Memory not mapped (invalid)


0x00020b00

Approximate location of lpCommandline



Memory not mapped (invalid)


0x00020012

Strings (paths?)


0x00012000

Memory not mapped (invalid)


0x00010000

Approximate location of the environment block



Memory not mapped (invalid)

0x00000000

Memory not mapped (invalid)




Notes:
1 - Every version and service pack of Windows changes in some little way the location of some elements but in general things are still to be found in the approximate location shown above. XP SP2 introduces some intentional randomness in the user-mode memory map as a security measure.

2 - The User Mode side of the memory map assumes that you have an EXE loaded and running and that the EXE links with most of the usual Windows DLLs such as User32.dll and so on.

3 - Notice that I have put the approximate locations of four (4) user mode heaps! Until not too long ago I assumed that most programs would have one or at most two heaps; this is not the case in my computer and might be an artifact of other applications that like to inject DLLs in other processes.

4 - While everybody knows that user mode applications get 2GB to play with, note that the way the memory is structured makes it difficult to use it as contiguous chunk: system DLLs grow from the topmost user-mode address towards zero which means that you probably won't be able to use anything above 0x77000000 and on the low end the EXE is usually located at 0x00400000 and below it you will tipically find the unicode support tables (memmory mapped) and the stacks and below the stacks other stuff placed by Windows. This means that the biggest contiguous chunk of RAM available will be about 1.8GB, or in other words 200MB are lost given the inherent fragmentation of user-mode memory.

No comments: