Converting Virtual into Physical Addresses

While analyzing a memory dump, sooner or later you'll have to convert a virtual into a physical address. This can be a challenging task when it's done for the first time. This article will guide you through the process.

For an introductory reading into the concept of virtual memory and its implementation in Microsoft Windows I recommend

  • Undocumented Windows 2000, chapter 4 by Sven B. Schreiber
  • Windows Internals (4th ed.), chapter 7 by Mark Russinovich and David Salomon.

You should also get the free manuals from Intel. Chapter 3.7 of Volume 3A explains the mechanics of 32-bit physical addresses. But why is it so important to understand this technology at all? Please have a look at the following excerpt taken from a debugger session:

kd> !process 0 0
PROCESS 829516a0  SessionId: 0  Cid: 0008    Peb: 00000000  ParentCid: 0000
    DirBase: 00030000  ObjectTable: 82976108  TableSize: 235.
    Image: System
PROCESS 8246c6a0  SessionId: 0  Cid: 00a4    Peb: 7ffdf000  ParentCid: 0008
    DirBase: 04e4b000  ObjectTable: 8246cd88  TableSize:  33.
    Image: SMSS.EXE
PROCESS 82442020  SessionId: 0  Cid: 00bc    Peb: 7ffdf000  ParentCid: 00a4
    DirBase: 07409000  ObjectTable: 824ec9a8  TableSize: 399.
    Image: CSRSS.EXE
PROCESS 824038c0  SessionId: 0  Cid: 00d0    Peb: 7ffdf000  ParentCid: 00a4
    DirBase: 07dce000  ObjectTable: 82404ae8  TableSize: 422.

Did you notice that with the exception of the system process all processes seem to refer to the same Process Environment Block (Peb)? The Peb is a large structure which among other things refers to the program file loaded into memory, so obviously this can't be true. The solution to this problem is strikingly simple - the Peb's address 0x7ffdf000 is a virtual address! But that doesn't help you much if all you've got is a memory dump. To read the Peb you'll have to convert the virtual address into a physical address and turn this into an offset into the dump file.

The following example will guide you through the process. Once again I will use the first image from the DFRWS Memory Analysis Challenge. First, it's free and publicly available. Second, the image was generated with dd. Therefore an offset into the image file equals an address in physical memory. Other file types would require some knowledge about the file internals and some mathematics to calculate back and forth between offsets and physical addresses.

Let's have a look at the Peb of UMGR32.EXE. As shown in the Intel manual, your starting point to convert virtual into physical addresses is the CPU's CR3 control register. Its value will be different for every process because each process has got a virtual address space of its own. The proper value for CR3 is saved in a variable named DirectoryTableBase of the EPROCESS structure. I've slightly modified PTfinder to report this value (column title is "PDB").

> --nothreads dfrws2005-physical-memory1.dmp
No.  Type PID    TID    Time created        Offset     PDB        Remarks
---- ---- ------ ------ ------------------- ---------- ---------- ----------------
   4 Proc    668        2005-06-05 00:55:08 0x0095f020 0x075a7000 UMGR32.EXE

Let's find out the (virtual) address of the Peb. Therefore open the dump in a hex editor and seek to offset 0x0095f020. From there proceed to the Peb's offset (0x1b0 for Windows 2000). There you'll find the byte sequence 0x00 0xf0 0xfd 0x7f. So the Peb's address is 0x7ffdf000.

Write down this address as a binary number and get the most significant 10 digits. They'll give you an index into the Page Directory. In this example the index is 0x1ff.

Getting the Page Directory Index
Page Directory IndexRemainder
31 - 2221-0
0x1ff (511) 

As seen above the Page Directory starts at physical address 0x075a7000. Each Page Directory Entry (PDE) is 4 Bytes in size. So the address for entry no. 0x1ff is 0x075a7000+0x1ff*4 = 0x075a77fc. The PDE reads 0x05cee067.

The Page Directory Entry
Page Table Base AddressunusedGPS0ACDWTU/SR/WP
31 - 1211109876543210

First thing to look at is the Page Size (PS) flag. If set, the address belongs to a 4 MB page. Windows uses large pages only for the kernel's code. So not surprisingly our address belongs to a small (that is 4 kb) page. As the Present (P) flag indicates, this page is present in physical memory. So we can proceed examining the memory.

Because the address belongs to a small page the next 10 bits (21 to 12) are to be interpreted as an index into a Page Table. The remaining 12 bits are an offset into the memory page.

Getting the Page Table Index
Page Directory IndexPage Table IndexOffset in Page
31 - 2221 - 1211 - 0
0x1ff (511)0x3df (991) 0

The Page Table starts at address 0x5cee * 0x1000. Each Page Table Entry (PDE) is 4 bytes large. So we'll find entry no. 0x3df at physical address 0x5cee * 0x1000 + 0x3df * 4 = 0x5ceef7c. It reads 0x0532f047. Let's parse this entry, too:

The Page Table Entry
Page Base AddressunusedGPATDACDWTU/SR/WP
31 - 1211109876543210

This gives us a Page Base Address of 0x0532f * 0x1000. The offset into this page is 0. So for the virtual address 0x7ffdf000 the physical address is 0x0532f * 0x1000 + 0 = 0x532f000.

03/12/2006: Corrected a typo in an address and fixed the last table.



This blog is a project of:
Andreas Schuster
Im Äuelchen 45
D-53177 Bonn

Copyright © 2005-2012 by
Andreas Schuster
All rights reserved.
Powered by Movable Type 5.12