Home > Articles > Operating Systems, Server > Microsoft Servers

A Sample Memory Dump Utility

Now that you have worked through the complex and possibly confusing IOCTL function handler code of the memory spy device driver, you probably want to see these functions in action. Therefore, I have created a sample console-mode utility named "SBS Windows 2000 Memory Spy" that loads the spy driver and calls various IOCTL functions, depending on the parameters passed in on the command line. This application resides in the executable file w2k_mem.exe, and its source code is included on the CD accompanying this book, in the directory \src\w2k_mem.

Command Line Format

You can run the memory spy utility from the CD by invoking d:\bin\w2k_mem.exe, where d: should be replaced by the drive letter of your CD-ROM drive. If w2k_mem.exe is started without arguments, the lengthy command info screen shown in Example 4-1 is displayed. The basic command philosophy of w2k_mem is that a command consists of one or more data requests, each providing at least a linear base address where the memory dump should start. Optionally, the memory block size can be specified as well—otherwise, the default size 256 is used. The memory size must be prefixed by the "#" character. Several option switches may be added that modify the default behavior of the command. An option consists of a single-character option ID and a "+" or "–" prefix that determines whether the option is switched on or off. By default, all options are turned off.

Example 4-1. Help Screen of the Memory Spy Utility

// w2k_mem.exe
// SBS Windows 2000 Memory Spy V1.00
// 08-27-2000 Sven B. Schreiber
// sbs@orgon.com

Usage: w2k_mem { { [+option|-option] [/<path>] } [#[[0]x]<size>] [[0]x]<base> }

<path> specifies a module to be loaded into memory.
Use the +x/-x switch to enable/disable its startup code.
If <size> is missing, the default size is 256 bytes.

Display address options (mutually exclusive):
   +z -z   zero-based display         on / OFF
   +r -r   physical RAM addresses     on / OFF

Display mode options (mutually exclusive):

   +w -w   WORD  data formatting      on / OFF
   +d -d   DWORD data formatting      on / OFF
   +q -q   QWORD data formatting      on / OFF

Addressing options (mutually exclusive):

   +t -t   TEB-relative addressing    on / OFF
   +f -f   FS-relative  addressing    on / OFF
   +u -u   user-mode   FS:[<base>]    on / OFF
   +k -k   kernel-mode FS:[<base>]    on / OFF
   +h -h   handle/object resolution   on / OFF
   +a -a   add bias  to  last base    on / OFF
   +s -s   sub bias from last base    on / OFF
   +p -p   pointer  from last block   on / OFF

System status options (cumulative):

   +o -o   display OS  information    on / OFF
   +c -c   display CPU information    on / OFF
   +g -g   display GDT information    on / OFF
   +i -i   display IDT information    on / OFF
   +b -b   display contiguous blocks  on / OFF

Other options (cumulative):

   +x -x   execute DLL startup code   on / OFF

Example: The following command displays the first 64
bytes of the current Process Environment Block (PEB)
in zero-based DWORD format, assuming that a pointer to
the PEB is located at offset 0x30 inside the current
Thread Environment Block (TEB):

   w2k_mem +t #0 0 +pzd #64 0x30

Note: Specifying #0 after +t causes the TEB to be
addressed without displaying its contents.

A data request is executed for each command line token that cannot be identified as an option, a data block size specification, a path, or any other command modifier. Each plain number on the command line is assumed to specify a linear address and triggers a hex dump, starting at this address. Numbers are interpreted as decimal by default or hexadecimal if prefixed by "0x" or simply "x."

Complex command line option models like the one employed by w2k_mem.exe are much easier to grasp if some simple examples are provided. Here is a short compilation:

  • w2k_mem 0x80400000 displays the first 256 bytes of memory at linear address 0x80400000, yielding something that should look similar to Example 4-2. By the way, this is the DOS header of the ntoskrnl.exe module (note the "MZ" ID at the beginning).

  • w2k_mem #0x40 0x80400000 displays the same data block, but stops after 64 bytes, as demanded by the block size specification #0x40.

  • w2k_mem +d #0x40 0x80400000 is another variant, this time packing the bytes into 32-bit DWORD chunks because of the +d option. This option remains in effect until reset by —d or overridden by a competing option such as +w or +q.

  • w2k_mem +wz #0x40 0x10000 +d –z 0x20000 contains two data requests. First, the linear address range 0x10000 to 0x1003F is shown in 16-bit WORD format, followed by the range 0x20000 to 0x2003F in DWORD format (Example 4-3). The first request also includes the +z switch, which forces the numbers in the "Address" column to start at zero. In the second request, the zero-based display mode is turned off by adding a –z switch.

  • w2k_mem +rd #4096 0xC0300000 displays the system's page-directory at address 0xC0300000 in DWORD format. The +r option enables the display of physical RAM addresses in the "Address" column instead of linear ones.

By now, you should have a basic understanding of how the command line format works. In the following subsections, some of the more exotic options and features are discussed in more detail. Most of them alter the interpretation of the address parameter they precede. In default mode, the specified address is a linear base address where the memory dump starts. The options +t, +f, +u, +k, +h, +a, +s, and +p change this default interpretation in various ways.

Example 4-2. A Sample Data Request

E:\>w2k_mem 0x80400000

// w2k_mem.exe
// SBS Windows 2000 Memory Spy V1.00
// 08-27-2000 Sven B. Schreiber
// sbs@orgon.com

Loading "SBS Windows 2000 Spy Device" (w2k_spy) ...
Driver: "D:\Program Files\DevStudio\MyProjects\w2k_mem\Release\w2k_spy.sys"
Opening "\\.\w2k_spy" ...

SBS Windows 2000 Spy Device V1.00 ready

80400000..804000FF: 256 valid bytes

Address  | 00 01 02 03-04 05 06 07 : 08 09 0A 0B-0C 0D 0E 0F | 0123456789ABCDEF
---------|-------------------------:-------------------------|-----------------
80400000 | 4D 5A 90 00-03 00 00 00 : 04 00 00 00-FF FF 00 00 | MZ.........ÿÿ..
80400010 | B8 00 00 00-00 00 00 00 : 40 00 00 00-00 00 00 00 | ¸.......@.......
80400020 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
80400030 | 00 00 00 00-00 00 00 00 : 00 00 00 00-C8 00 00 00 | ............È...
80400040 | 0E 1F BA 0E-00 B4 09 CD : 21 B8 01 4C-CD 21 54 68 | ..º..´.Í!¸.LÍ!Th
80400050 | 69 73 20 70-72 6F 67 72 : 61 6D 20 63-61 6E 6E 6F | is program canno
80400060 | 74 20 62 65-20 72 75 6E : 20 69 6E 20-44 4F 53 20 | t be run in DOS
80400070 | 6D 6F 64 65-2E 0D 0D 0A : 24 00 00 00-00 00 00 00 | mode....$.......
80400080 | 50 7A C4 CE-14 1B AA 9D : 14 1B AA 9D-14 1B AA 9D | PzÄÎ..ª..ª..ª
80400090 | 14 1B AB 9D-53 1B AA 9D : 18 3B A4 9D-5B 1B AA 9D | ..«S.ª.;[.ª
804000A0 | 42 13 AC 9D-15 1B AA 9D : 14 1B AA 9D-1A 19 AA 9D | B.¬..ª..ª..ª
804000B0 | 4D 38 B9 9D-12 1B AA 9D : 52 69 63 68-14 1B AA 9D | M81..ªRich..ª
804000C0 | 00 00 00 00-00 00 00 00 : 50 45 00 00-4C 01 13 00 | ........PE..L...
804000D0 | 17 9B 4D 38-00 00 00 00 : 00 00 00 00-E0 00 0E 03 | .?M8........à...
804000E0 | 0B 01 05 0C-C0 2D 14 00 : 80 D6 04 00-00 00 00 00 | ....À-..?Ö......
804000F0 | 20 D1 00 00-C0 04 00 00 : 80 73 06 00-00 00 40 00 |  Ñ..À...?s....@.

       256 bytes requested
       256 bytes received

Closing the spy device ...

Example 4-3. Displaying Data in Special Formats

E:\>w2k_mem +wz #0x40 0x10000 +d -z 0x20000

// w2k_mem.exe
// SBS Windows 2000 Memory Spy V1.00
// 08-27-2000 Sven B. Schreiber
// sbs@orgon.com

Loading "SBS Windows 2000 Spy Device" (w2k_spy) ...Driver: "D:\Program Files\DevStudio\MyProjects\w2k_mem\Release\ w2k_spy.sys"
Opening "\\.\w2k_spy" ...
SBS Windows 2000 Spy Device V1.00 ready

00010000..0001003F: 64 valid bytes

Address  | 0000 0002-0004 0006 : 0008 000A-000C 000E | 00 02 04 06 08 0A 0C 0E
---------|---------------------:---------------------|------------------------
00000000 | 003D 0044-003A 003D : 0044 003A-005C 0050 | .= .D .: .= .D .: .\ .P
00000010 | 0072 006F-0067 0072 : 0061 006D-0020 0046 | .r .o .g .r .a .m .  .F
00000020 | 0069 006C-0065 0073 : 005C 0044-0065 0076 | .i .l .e .s .\ .D .e .v
00000030 | 0053 0074-0075 0064 : 0069 006F-005C 004D | .S .t .u .d .i .o .\ .M

00020000..0002003F: 64 valid bytes

Address  | 00000000 - 00000004 : 00000008 - 0000000C | 0000 0004 0008 000C
---------|---------------------:---------------------|--------------------
00020000 | 00001000 - 00000880 : 00000001 - 00000000 | .... ...? .... ....
00020010 | 02B20001 - 00000000 : 00000003 - 00000007 | .2.. .... .... ....
00020020 | 0000000B - 0208006C : 00020290 - 00000018 | .... ...l ... ....
00020030 | 02A0029E - 00020498 : 00840082 - 00020738 | . .? ...? .?.? ...8

       128 bytes requested
       128 bytes received

Closing the spy device ...

TEB-Relative Addressing

Each thread in a process has its own Thread Environment Block (TEB) where the system keeps frequently used thread-specific data. In user-mode, the TEB of the current thread is located in a separate 4-KB segment accessible via the processor's FS register. In kernel-mode, FS points to a different segment, as will be explained below. All TEBs of a process are stacked up in linear memory at linear address 0x7FFDE000, expanding down in 4-KB steps as needed. That is, the TEB of the second thread is found at address 0x7FFDD000, the TEB of the third thread at 0x7FFDC000, and so on. The contents of the TEBs and the Process Environment Block (PEB) address 0x7FFDF000 will be discussed in more detail in Chapter 7 (see Listings 7-18 and 7-19). Here it should suffice to take note that TEBs exist and that they are addressed by the FS register.

If the +t switch precedes an address on the command line, w2k_mem.exe adds the base address of the FS segment to it, effectively applying a bias of 0x7FFDE000 bytes. Example 4-4 shows the output of the command w2k_mem +dt #0x38 0 on my system. This time I have omitted the banner and status messages issued by w2k_mem.exe. The omissions are marked by [...].

Example 4-4. Displaying the first Thread Environment Block(TEB)

E:\>w2k_mem +dt #0x38 0
[...]
7FFDE000..7FFDE037: 56 valid bytes

Address  | 00000000 - 00000004 : 00000008 - 0000000C | 0000 0004 0008 000C
---------|---------------------:---------------------|--------------------
7FFDE000 | 0012FA58 - 00130000 : 0012E000 - 00000000 | ..úX .... ..à. ....
7FFDE010 | 00001E00 - 00000000 : 7FFDE000 - 00000000 | .... .... .´yà. ....
7FFDE020 | 000002C0 - 000002C8 : 00000000 - 00000000 | ...À ...È .... ....
7FFDE030 | 7FFDF000 - 00000000 :          -          | .´yô. ....
[...]

FS-Relative Addressing

I have already mentioned that the FS refers to different segments in user- and kernel-mode. Whereas the +t switch selects the user-mode FS address as the reference point, the +f switch uses the FS base address that is in effect in kernel-mode. Of course, a Win32 application has no way to get at this value, so once again the spy device is required. w2k_mem.exe calls the IOCTL function SPY_IO_CPU_INFO, introduced in the previous section, to read CPU status information that includes the kernel-mode values of all segment registers. From there, everything goes on just the same as with the +t switch.

The kernel-mode FS points to another thread-specific structure frequently accessed by the Windows 2000 kernel, named the Kernel's Processor Control Region (KPCR). This structure has already been mentioned in the course of the discussion of the IOCTL function SPY_IO_OS_INFO and will be revisited in Chapter 7 (see Listing 7-16). Again, suffice it to note for now that this structure exists at linear address 0xFFDFF000, and that the +f switch gives easy access to it. In Example 4-5, I have issued the command w2k_mem +df #0x54 0 to demonstrate that the +f switch in fact applies a bias of 0xFFDFF000 bytes to the specified memory address.

Example 4-5. Displaying the Kernel's Processor Control Region (KPCR)

E:\>w2k_mem +df #0x54 0
[...]
FFDFF000..FFDFF053: 84 valid bytes

Address  | 00000000 - 00000004 : 00000008 - 0000000C | 0000 0004 0008 000C
---------|---------------------:---------------------|--------------------
FFDFF000 | BECD9CF0 - BECD9DF0 : BECD6000 - 00000000 | 3/4Í?Ô 3/4ÍÕ 3/4Í´. ....
FFDFF010 | 00000000 - 00000000 : 7FFDE000 - FFDFF000 | .... .... .´yà. ÿßÕ.
FFDFF020 | FFDFF120 - 00000000 : 00000000 - 00000000 | ÿßñ  .... .... ....
FFDFF030 | FFFF20C0 - 00000000 : 80036400 - 80036000 | ÿÿ À .... ?.d. ?.´.
FFDFF040 | 80244000 - 00010001 : 00000001 - 000000C9 | ?$@. .... .... ...É
FFDFF050 | 00000000 -          :          -          | ....
[...]

FS:[<base>] Addressing

When examining Windows 2000 kernel code, you will frequently come across instructions such as MOV EAX, and FS:[18h]. These instructions retrieve member values of the TEB, KPCR, or other structures contained in the FS segment. Many of them are pointers to other internal structures. The command line switches +u and +k allow you to follow this indirection with ease. +u retrieves a pointer from the user-mode FS segment; +k does the same in kernel-mode. For example, the command w2k_mem +du #0x1E8 0x30 (see Example 4-6) dumps 488 bytes of the memory block addressed by FS:[30h] in user-mode, which happens to be a pointer to the Process Environment Block (PEB) of w2k_mem.exe. The command w2k_mem +dk #0x1C 0x20 (see Example 4-7) displays the first 28 bytes of memory pointed to by FS:[20h] in kernel-mode, which is a pointer to the Kernel's Processor Control Block (KPRCB), briefly mentioned earlier in the discussion of the IOCTL function SPY_IO_OS_INFO and also discussed in Chapter 7 (see Listing 7-15). Don't worry if you don't know what a PEB or KPRCB is—you will know it after having read this book.

Example 4-6. Displaying the Process Environment Block (PEB)

E:\>w2k_mem +du #0x1E8 0x30
[...]
7FFDF000..7FFDF1E7: 488 valid bytes

Address  | 00000000 - 00000004 : 00000008 - 0000000C | 0000 0004 0008 000C
---------|---------------------:---------------------|--------------------
7FFDF000 | 00000000 - FFFFFFFF : 00400000 - 00131E90 | .... ÿÿÿÿ .@.. ...
7FFDF010 | 00020000 - 00000000 : 00130000 - 77FCD170 | .... .... .... wüÑp
7FFDF020 | 77F8AA4C - 77F8AA7D : 00000001 - 77E33E58 | wøªL wøª} .... wã>X
7FFDF030 | 00000000 - 00000000 : 00000000 - 00000000 | .... .... .... ....
7FFDF040 | 77FCD1A8 - 0000007F : 00000000 - 7F6F0000 | wüѨ .... .... .o..
7FFDF050 | 7F6F0000 - 7F6F0688 : 7FFB0000 - 7FFC1000 | .o.. .o.? .û.. .ü..
7FFDF060 | 7FFD2000 - 00000001 : 00000000 - 00000000 | .´y . .... .... ....
7FFDF070 | 079B8000 - FFFFE86D : 00100000 - 00002000 | .??. ÿÿèm .... .. .
7FFDF080 | 00010000 - 00001000 : 00000003 - 00000010 | .... .... .... ....
7FFDF090 | 77FCE380 - 00410000 : 00000000 - 00000014 | wüã? .A.. .... ....
7FFDF0A0 | 77FCD348 - 00000005 : 00000000 - 00000893 | wüÓH .... .... ...?
7FFDF0B0 | 00000002 - 00000003 : 00000004 - 00000000 | .... .... .... ....
7FFDF0C0 | 00000000 - 00000000 : 00000000 - 00000000 | .... .... .... ....
7FFDF0D0 | 00000000 - 00000000 : 00000000 - 00000000 | .... .... .... ....
7FFDF0E0 | 00000000 - 00000000 : 00000000 - 00000000 | .... .... .... ....
7FFDF0F0 | 00000000 - 00000000 : 00000000 - 00000000 | .... .... .... ....
7FFDF100 | 00000000 - 00000000 : 00000000 - 00000000 | .... .... .... ....
7FFDF110 | 00000000 - 00000000 : 00000000 - 00000000 | .... .... .... ....
7FFDF120 | 00000000 - 00000000 : 00000000 - 00000000 | .... .... .... ....
7FFDF130 | 00000000 - 00000000 : 00000000 - 00000000 | .... .... .... ....
7FFDF140 | 00000000 - 00000000 : 00000000 - 00000000 | .... .... .... ....
7FFDF150 | 77FCDCC0 - 00000000 : 00000000 - 00000000 | wüÜÀ .... .... ....
7FFDF160 | 00000000 - 00000000 : 00000000 - 00000000 | .... .... .... ....
7FFDF170 | 00000000 - 00000000 : 00000000 - 00000000 | .... .... .... ....
7FFDF180 | 00000000 - 00000000 : 00000000 - 00000000 | .... .... .... ....
7FFDF190 | 00000000 - 00000000 : 00000000 - 00000000 | .... .... .... ....
7FFDF1A0 | 00000000 - 00000000 : 00000000 - 00000000 | .... .... .... ....
7FFDF1B0 | 00000000 - 00000000 : 00000000 - 00000000 | .... .... .... ....
7FFDF1C0 | 00000000 - 00000000 : 00000000 - 00000000 | .... .... .... ....
7FFDF1D0 | 00000000 - 00000000 : 00000000 - 00020000 | .... .... .... ....
7FFDF1E0 | 7F6F06C2 - 00000000 :          -          | .o. ....
[...]

Example 4-7. Displaying the Kernel's Processor Control Block (KPRCB)

E:\>w2k_mem +dk #0x1C 0x20
[...]
FFDFF120..FFDFF13B: 28 valid bytes

Address  | 00000000 - 00000004 : 00000008 - 0000000C | 0000 0004 0008 000C
---------|---------------------:---------------------|--------------------
FFDFF120 | 00010001 - 86BBA820 : 00000000 - 8046BDF0 | .... ?»¨  .... ?F 1/2 ó
FFDFF130 | 00020000 - 00000001 : 05010106 -          | .... .... ....
[...]

Handle/Object Resolution

Suppose you have an object HANDLE and want to see what the corresponding object looks like in memory. This is an almost trivial task if you use the +h switch, which simply calls the spy device's SPY_IO_HANDLE_INFO function (Listing 4-26) to look up the object body of the given handle. The world of Windows 2000 objects is an amazing topic that will be treated in depth in Chapter 7. So let's forget about it for now.

Relative Addressing

Sometimes it might be useful to display a series of memory blocks that are spaced out by the same number of bytes. This might be, for example, an array of structures, like the stack of TEBs in a multithreaded application. The +a and +s switches enable this kind of relative addressing by changing the interpretation of the specified address to an offset. The difference between these options is that +a ("add bias") yields a positive offset, whereas +s ("subtract bias") yields a negative one. Example 4-8 shows the output of the command w2k_mem +d #32 0xC0000000 +a 4096 4096 on my system. It samples the first 32 bytes of three consecutive 4-KB pages, starting at address 0xC0000000, where the system's page-tables are located. Note the +a switch near the end of the command. It causes the following "4096" tokens to be interpreted as offsets

Example 4-8. Sampling Page-Tables

E:\>w2k_mem +d #32 0xC0000000 +a 4096 4096
 [...]
C0000000..C000001F: 32 valid bytes

Address  | 00000000 - 00000004 : 00000008 - 0000000C | 0000 0004 0008 000C
---------|---------------------:---------------------|--------------------
C0000000 | 00000000 - 00000000 : 00000000 - 00000000 | .... .... .... ....
C0000010 | 00000000 - 00000000 : 00000000 - 00000000 | .... .... .... ....

C0001000..C000101F: 32 valid bytes

Address  | 00000000 - 00000004 : 00000008 - 0000000C | 0000 0004 0008 000C
---------|---------------------:---------------------|-------------------- 
C0001000 | 037D1025 - 03324025 : 0329D025 - 04DDE025 | .}.% .2@% .)–D% .Y´à%
C0001010 | 06F17067 - 03297225 : 05115067 - 00000000 | .ñpg .)r% ..Pg ....

C0002000..C000201F: 0 valid bytes

Address  | 00000000 - 00000004 : 00000008 - 0000000C | 0000 0004 0008 000C
---------|---------------------:---------------------|--------------------
C0002000 |          -          :          -          |
C0002010 |          -          :          -          |

        96 bytes requested
        64 bytes received
[...]

to be added to the previous base address. The +a and +s switches remain in effect until switched off explicitly by specifying —a or –s or overridden by any of the other switches that change the interpretation of the address parameter.

Example 4-8 also shows what happens if an invalid linear address is passed in. Obviously, the first pair of page-tables referring to the 4-MB address ranges 0x00000000 to 0x003F0000 and 0x00400000 to 0x007F0000 were valid, and the third one was not. w2k_mem.exe reflects this fact by displaying an empty hex dump table. The program knows which address ranges are valid because the spy device's SPY_IO_MEMORY_DATA function puts this information into the resulting SPY_MEMORY_DATA structure (cf. Listing 4-25).

Indirect Addressing

One of my favorite command options is +p, because it saved a lot of typing while I was preparing this book. This option works similar to +u and +k, but doesn't use the FS segment as reference, but rather uses the previously displayed data block. This is a great feature if you want to chase down a linked list of objects, for example. Instead of displaying the first list member, reading out the address of the next member, typing a new command with this address, and so on, simply append +p to the command and a series of offsets that specify where the link to the next object is located in the previous hex dump panel.

In Example 4-9, I have used this option to walk down the list of active processes. First, I have asked the Kernel Debugger to give me the address of the internal variable PsActiveProcessHead, which is a LIST_ENTRY structure marking the beginning of the process list. A LIST_ENTRY consists of a Flink (forward link) member at offset 0 and a Blink (backward link) member at offset 4 (cf. Listing 2-7). The command w2k_mem #8 +d 0x8046a180 +p 0 0 0 0 first dumps the LIST_ENTRY of PsActiveProcessHead, and then it switches to indirect addressing on behalf of the +p switch. The four zeros tell w2k_mem.exe to extract the value at offset zero of the previous data block, which is, of course, the Flink member of each LIST_ENTRY. Note that the Blink members in Example 4-9, located at offset 4, do in fact point back to the previous LIST_ENTRY, as expected.

If enough zero-valued parameters would be appended to the command, the hex dump would eventually return to PsActiveProcessHead, which marks the beginning and the end of the process list. As explained in Chapter 2, the doubly-linked lists maintained by Windows 2000 are usually circular; that is, the Flink of the last list member points to the first one, and the Blink of the first list member points to the last one.

Example 4-9. Walking Down the Active-Process List

E:\>w2k_mem #8 +d 0x8046a180 +p 0 0 0 0
[...]
8046A180..8046A187: 8 valid bytes

Address  | 00000000 - 00000004 : 00000008 - 0000000C | 0000 0004 0008 000C
---------|---------------------:---------------------|--------------------
8046A180 | 8149D900 - 840D2BE0 :          -          | IÙ.  ?.+à

8149D900..8149D907: 8 valid bytes

Address  | 00000000 - 00000004 : 00000008 - 0000000C | 0000 0004 0008 000C
---------|---------------------:---------------------|--------------------
8149D900 | 8131A4A0 - 8046A180 :          -          |  1 ?F¡?

8131A4A0..8131A4A7: 8 valid bytes

Address  | 00000000 - 00000004 : 00000008 - 0000000C | 0000 0004 0008 000C
---------|---------------------:---------------------|--------------------
8131A4A0 | 812FFDE0 - 8149D900 :          -          | /´yà IÙ.

812FFDE0..812FFDE7: 8 valid bytes
Address  | 00000000 - 00000004 : 00000008 - 0000000C | 0000 0004 0008 000C
---------|---------------------:---------------------|--------------------
812FFDE0 | 812FA460 - 8131A4A0 :          -          | /´ 1

812FA460..812FA467: 8 valid bytes

Address  | 00000000 - 00000004 : 00000008 - 0000000C | 0000 0004 0008 000C
---------|---------------------:---------------------|--------------------
812FA460 | 812E30C0 - 812FFDE0 :          -          | .0À /´yà
[...]

Loading Modules on the Fly

Sometimes you might want to dump the memory image of a module, but the module is not mapped into the linear address space of the w2k_mem.exe process. This problem can be solved by loading the module explicitly using the /<path> and +x command options. Every command token prefixed by a slash character is interpreted as a module path, and w2k_mem.exe attempts to load this module from this path using the Win32 API function LoadLibraryEx(). By default, the load option DONT_RESOLVE_ DLL_REFERENCES is used, causing the module to be loaded without initializing it. For a DLL, this means that its DllMain() entry point is not called. Also, none of the dependent modules specified in the import section is loaded. However, if you specify the +x switch before the path, the module is loaded and fully initialized. Note that some modules might refuse initialization in the context of the w2k_mem.exe process. For example, kernel-mode device drivers should not be loaded with this option turned on.

Loading and displaying a module is typically a two-step operation, as shown in Example 4-10. First you should load the module without displaying any data, to find out the base address assigned to it by the system. Fortunately, load addresses are deterministic as long as no other modules are added to the process in the meantime, so the next attempt to load the module will yield the same base address. In Example 4-10, I have loaded the kernel-mode device driver nwrdr.sys, which is the Microsoft's NetWare redirector. I'm not using IPX/SPX on my machine, so this driver is not yet loaded. Obviously, LoadLibraryEx() succeeds, and the hex dumps of the reported load address 0x007A0000 preceding and following this API call prove that this memory region is initially unused but contains a DOS header afterward.

Example 4-10. Loading and Displaying a Module Image

 E:\>w2k_mem /e:\winnt\system32\drivers\nwrdr.sys
 [...]
You didn't request any data!

LoadLibrary (e:\winnt\system32\drivers\nwrdr.sys) = 0x007A0000
[...]
E:\>w2k_mem 0x007A0000 /e:\winnt\system32\drivers\nwrdr.sys 0x007A0000
[...]
007A0000..007A00FF: 0 valid bytes

Address  | 00 01 02 03-04 05 06 07 : 08 09 0A 0B-0C 0D 0E 0F | 0123456789ABCDEF
---------|-------------------------:-------------------------|-----------------
007A0000 |            -            :            -            |
007A0010 |            -            :            -            |
007A0020 |            -            :            -            |
007A0030 |            -            :            -            |
007A0040 |            -            :            -            |
007A0050 |            -            :            -            |
007A0060 |            -            :            -            |
007A0070 |            -            :            -            |
007A0080 |            -            :            -            |
007A0090 |            -            :            -            |
007A00A0 |            -            :            -            |
007A00B0 |            -            :            -            |
007A00C0 |            -            :            -            |
007A00D0 |            -            :            -            |
007A00E0 |            -            :            -            |
007A00F0 |            -            :            -            |

LoadLibrary (e:\winnt\system32\drivers\nwrdr.sys) = 0x007A0000

007A0000..007A00FF: 256 valid bytes

Address  | 00 01 02 03-04 05 06 07 : 08 09 0A 0B-0C 0D 0E 0F | 0123456789ABCDEF
---------|-------------------------:-------------------------|-----------------
007A0000 | 4D 5A 90 00-03 00 00 00 : 04 00 00 00-FF FF 00 00 | MZ.........ÿÿ..
007A0010 | B8 00 00 00-00 00 00 00 : 40 00 00 00-00 00 00 00 | ¸.......@.......
007A0020 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
007A0030 | 00 00 00 00-00 00 00 00 : 00 00 00 00-D0 00 00 00 | ............–D...
007A0040 | 0E 1F BA 0E-00 B4 09 CD : 21 B8 01 4C-CD 21 54 68 | ..º..´.Í!¸.LÍ!Th
007A0050 | 69 73 20 70-72 6F 67 72 : 61 6D 20 63-61 6E 6E 6F | is program canno
007A0060 | 74 20 62 65-20 72 75 6E : 20 69 6E 20-44 4F 53 20 | t be run in DOS
007A0070 | 6D 6F 64 65-2E 0D 0D 0A : 24 00 00 00-00 00 00 00 | mode....$.......
007A0080 | 61 14 4B C1-25 75 25 92 : 25 75 25 92-25 75 25 92 | a.KÁ%u%?%u%?%u%?
007A0090 | 29 55 2B 92-27 75 25 92 : 7C 56 36 92-22 75 25 92 | )U+?'u%?|V6?"u%?
007A00A0 | 25 75 24 92-BF 75 25 92 : 0F 7D 23 92-24 75 25 92 | %u$?¿u%?.}#?$u%?
007A00B0 | 25 75 25 92-14 75 25 92 : 52 69 63 68-25 75 25 92 | %u%?.u%?Rich%u%?
007A00C0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
007A00D0 | 50 45 00 00-4C 01 09 00 : 66 EC 08 38-00 00 00 00 | PE..L...fì.8....
007A00E0 | 00 00 00 00-E0 00 0E 03 : 0B 01 05 0C-00 2D 02 00 | ....à........-..
007A00F0 | 40 3A 00 00-00 00 00 00 : 3E 14 01 00-40 03 00 00 | @:......>...@...
[...]

Oddly, you can even load the .exe file of another application into memory using the /<path> option. However, this module probably will be loaded to an unusual address, because its preferred load address is usually occupied by w2k_mem.exe. Moreover, you cannot get the loaded application to run—the +x switch applies to DLLs only and has no effect on other module types.

Demand-Paging in Action

In the discussion of the spy device function SPY_IO_MEMORY_DATA, I mentioned that this function is able to read the contents of memory pages that are flushed out to a pagefile. Now is the time to prove this claim. First, it is necessary to maneuver the system into a severe low-memory situation, forcing it to swap to the pagefiles anything that isn't urgently needed. My favorite method goes as follows:

  1. Copy the Windows 2000 desktop to the clipboard by pressing the Print key.

  2. Paste this bitmap into a graphics application.

  3. Inflate the bitmap to an enormous size.

Now watch out what the command w2k_mem +d #16 0xC0280000 0xA0000000 0xA0001000 0xA0002000 0xC0280000 yields on the screen. You might wonder what this command is supposed to do. Well, it simply takes a snapshot of some PTEs before and after touching the pages they refer to. The four PTEs found at address 0xC0280000 are associated with the linear address range 0xA0000000 to 0xA0003FFF, which is part of the image of the kernel module win32k.sys. As Example 4-11 shows, this address range has been swapped out because of the bitmap operation I had performed just before. How do I know? Because the four DWORDs at address 0xC0280000 are even numbers, meaning that their least significant bit—the P bit of a PTE—is zero, indicating a nonpresent page. The next three hex dump panels belong to the command parameters 0xA0000000, 0xA0001000, and 0xA0002000, requesting data from three of the four pages currently under examination. As it turns out, w2k_mem.exe has no problems accessing these pages—the system simply swaps them in on demand. However, the final test is still to come: What do the four PTEs look like afterward? The answer is given by the last panel of Example 4-11: The first three PTEs have the P bit set, and the fourth still indicates "not present."

Example 4-11. Watching PTEs Change Their States

E:\>w2k_mem +d #16 0xC0280000 0xA0000000 0xA0001000 0xA0002000 0xC0280000
[...]
C0280000..C028000F: 16 valid bytes

Address  | 00000000 - 00000004 : 00000008 - 0000000C | 0000 0004 0008 000C
---------|---------------------:---------------------|--------------------
C0280000 | 056A14E0 - 056A14E2 : 056A14E4 - 056A14E6 | .j.à .j. .j.ä .j.æ

A0000000..A000000F: 16 valid bytes

Address  | 00000000 - 00000004 : 00000008 - 0000000C | 0000 0004 0008 000C
---------|---------------------:---------------------|--------------------
A0000000 | 00905A4D - 00000003 : 00000004 - 0000FFFF | .ZM .... .... ..ÿÿ

A0001000..A000100F: 16 valid bytes

Address  | 00000000 - 00000004 : 00000008 - 0000000C | 0000 0004 0008 000C
---------|---------------------:---------------------|--------------------
A0001000 | 000000A6 - FF0C75FF : 1738B415 - F8458BA0 | ...|| ÿ.uÿ .8´. øE? 

A0002000..A000200F: 16 valid bytes

Address  | 00000000 - 00000004 : 00000008 - 0000000C | 0000 0004 0008 000C
---------|---------------------:---------------------|--------------------
A0002000 | 89A018E0 - F685D875 : 468D1A74 - 458D5020 | ? .à ö?Øu F.t EP

C0280000..C028000F: 16 valid bytes

Address  | 00000000 - 00000004 : 00000008 - 0000000C | 0000 0004 0008 000C
---------|---------------------:---------------------|--------------------
C0280000 | 0556B123 - 028C2121 : 05AD1121 - 056A14E6 | .V±# .?!! .-.! .j.æ
[...]

Before stepping to the next section, please study the first hex dump panel of Example 4-11 once more. The four PTEs at address 0xC0280000 all look quite similar. In fact, they differ only in the three least-significant bits. If you examine more of these PNPES that refer to pages in the pagefiles, you find that they all have bit #10 set. That's why I assigned the name PageFile to this bit in Listing 4-3. If it is set, the remaining bits—except for the P flag, of course—apparently specify the location of this page in the pagefiles.

More Command Options

Some of the most interesting command options listed in Example 4-1 have not yet been explained. For example the "System status options" +o, +c, +g, +i, and +b are missing, although they sound promising. I will return to them in the last section of this chapter, where several secrets of the Windows 2000 memory system will be revealed.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020