In previous posts we talked about virtual address space and how virtual memory is managed.  I've never posted anything about virtual address translation though, and for the ones interested on the details behing this operation I recommend reading the chapter 7 - Memory Management (specifically the Address Translation section) of the Windows Internals 4th Edition book.  So I won't go too deep on the details of how the system does the translation itself, my goal here is just how to show you how easily translate from one address to another once you have a memory dump or a live debugging session.

Once you choose the virtual address you want to do the translation the first step is to run the command !pte and find out some additional information for the corresponding PTE.  For this example I'm going to use the virtual address used as a base address to load the tcpip driver itself on a 32-bit Windows 2003 SP2 system:

 

0: kd> lmvm tcpip

start    end        module name

f7625000 f7686000   tcpip      (deferred)            

    Image path: \SystemRoot\system32\DRIVERS\tcpip.sys

    Image name: tcpip.sys

    Timestamp:        Thu Mar 24 19:40:31 2005 (42435DFF)

    CheckSum:         0005606F

    ImageSize:        00061000

Above highlighted in yellow we have the base address where the tcpip driver has been loaded (virtual address).  Now we run the command !pte passing this address as an argument:

0: kd> !pte f7625000

               VA f7625000

PDE at   C0300F74        PTE at C03DD894

contains 00ACC963      contains 1C055963

pfn acc -G-DA--KWEV    pfn 1c055 -G-DA—KWEV

 

The highlighted information above is about the PFN correlated to the physical address associated with the  virtual address we passed as an input to !pte.  However you noticed that 1c055 uses up to 20 bits (which are used to locate the PDE and PTE itself which will point to the physical page) and we know the completed addresses are 32 bits wide.  The last 12 bits on the translation process are used as a byte index to the physical page where the content is actually stored, so they come straight from the virtual address.

 

The final physical address will then be 1c055 followed by the last 12 bits of the virtual address which in this case is 000.  So putting them together we have that 1c055000 is the physical address correlated to the virtual address f7652000.  Let’s verify that by dumping both address and comparing their content:

 

Dumping the virtual address first:

0: kd> dc f7625000

f7625000  00905a4d 00000003 00000004 0000ffff  MZ..............

f7625010  000000b8 00000000 00000040 00000000  ........@.......

f7625020  00000000 00000000 00000000 00000000  ................

f7625030  00000000 00000000 00000000 000000e0  ................

f7625040  0eba1f0e cd09b400 4c01b821 685421cd  ........!..L.!Th

f7625050  70207369 72676f72 63206d61 6f6e6e61  is program canno

f7625060  65622074 6e757220 206e6920 20534f44  t be run in DOS

f7625070  65646f6d 0a0d0d2e 00000024 00000000  mode....$.......

 

Now let’s dump the physical address and compare the results:

0: kd> dc /p 1c055000

1c055000  00905a4d 00000003 00000004 0000ffff  MZ..............

1c055010  000000b8 00000000 00000040 00000000  ........@.......

1c055020  00000000 00000000 00000000 00000000  ................

1c055030  00000000 00000000 00000000 000000e0  ................

1c055040  0eba1f0e cd09b400 4c01b821 685421cd  ........!..L.!Th

1c055050  70207369 72676f72 63206d61 6f6e6e61  is program canno

1c055060  65622074 6e757220 206e6920 20534f44  t be run in DOS

1c055070  65646f6d 0a0d0d2e 00000024 00000000  mode....$.......

 

The content is identical as expected J.