PEB WinDBG analysis and process manipulation

The Process Environment Block is a Windows user-mode memory management data structure that is used for storing a lot of information about loaded modules, process arguments, heap addresses, base addresses, and more.

Why is the PEB important to us?

As an attacker, the PEB can hold a lot of vital information for us that may be used later on while conducting exploit-development or malware analysis. This article also covers a technique for modifying and manipulating PEB entries, which in previous years has been used by multiple malware samples to evade AV detection and to impersonate other processes.


First, open up a notepad instance and then in WinDBG attach it as a currently running process, from the selection menu, the most previously opened process is usually on the bottom of the list.

After connecting notepad to our WinDBG debugger, it will break the running process automatically to allow us to run analysis commands on the process. Open up a command window under View > Command.

Let’s start by checking what members and information that the PEB holds. We can use the dt command in WinDBG to display information about the PEB data structure. The syntax is as follows dt _peb.

0:002> dt _peb
ntdll!_PEB
   +0x000 InheritedAddressSpace : UChar
   +0x001 ReadImageFileExecOptions : UChar
   +0x002 BeingDebugged    : UChar
   +0x003 BitField         : UChar
   +0x003 ImageUsesLargePages : Pos 0, 1 Bit
   +0x003 IsProtectedProcess : Pos 1, 1 Bit
   +0x003 IsLegacyProcess  : Pos 2, 1 Bit
   +0x003 IsImageDynamicallyRelocated : Pos 3, 1 Bit
   +0x003 SkipPatchingUser32Forwarders : Pos 4, 1 Bit
   +0x003 SpareBits        : Pos 5, 3 Bits
   +0x004 Mutant           : Ptr32 Void
   +0x008 ImageBaseAddress : Ptr32 Void
   +0x00c Ldr              : Ptr32 _PEB_LDR_DATA
   +0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
   +0x014 SubSystemData    : Ptr32 Void
   +0x018 ProcessHeap      : Ptr32 Void
   +0x01c FastPebLock      : Ptr32 _RTL_CRITICAL_SECTION
   +0x020 AtlThunkSListPtr : Ptr32 Void

Some of the more interesting information that we can get from the PEB is information like the ProcessParameters, and ImageBaseAddress. The information from these different members of the PEB can help us as an exploit developer or someone whos debugging a process.

If you look at the information that the dt command gave us, you’ll see that the addresses are listing as Ptr32 Void, we can fix that by overlaying the memory pointed by the PEB so we can see what the values are of the different members.

We can use the dt _peb @$peb command to have the PEB populated with the values we want.

0:002> dt _peb @$peb
ntdll!_PEB
   +0x000 InheritedAddressSpace : 0 ''
   +0x001 ReadImageFileExecOptions : 0 ''
   +0x002 BeingDebugged    : 0x1 ''
   +0x003 BitField         : 0x8 ''
   +0x003 ImageUsesLargePages : 0y0
   +0x003 IsProtectedProcess : 0y0
   +0x003 IsLegacyProcess  : 0y0
   +0x003 IsImageDynamicallyRelocated : 0y1
   +0x003 SkipPatchingUser32Forwarders : 0y0
   +0x003 SpareBits        : 0y000
   +0x004 Mutant           : 0xffffffff Void
   +0x008 ImageBaseAddress : 0x00b80000 Void
   +0x00c Ldr              : 0x77348880 _PEB_LDR_DATA
   +0x010 ProcessParameters : 0x00371100 _RTL_USER_PROCESS_PARAMETERS
   +0x014 SubSystemData    : (null) 
   +0x018 ProcessHeap      : 0x00370000 Void
   +0x01c FastPebLock      : 0x77348380 _RTL_CRITICAL_SECTION
   +0x020 AtlThunkSListPtr : (null) 

We can get the PEB address of the process with r $peb, this returns the address of the PEB.

0:002> r $peb
$peb=7ffde000

Now let’s start analyzing the notepad process we opened via looking at the ImageBaseAddress address via the db command.

0:002> db 0x00b80000
00b80000  4d 5a 90 00 03 00 00 00-04 00 00 00 ff ff 00 00  MZ..............
00b80010  b8 00 00 00 00 00 00 00-40 00 00 00 00 00 00 00  ........@.......
00b80020  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
00b80030  00 00 00 00 00 00 00 00-00 00 00 00 d8 00 00 00  ................
00b80040  0e 1f ba 0e 00 b4 09 cd-21 b8 01 4c cd 21 54 68  ........!..L.!Th
00b80050  69 73 20 70 72 6f 67 72-61 6d 20 63 61 6e 6e 6f  is program canno
00b80060  74 20 62 65 20 72 75 6e-20 69 6e 20 44 4f 53 20  t be run in DOS 
00b80070  6d 6f 64 65 2e 0d 0d 0a-24 00 00 00 00 00 00 00  mode....$.......

This will give us a memory dump from the address we provided, we can see the PE DOS header of the file. We can extend the size of the dump by provided L200 to the command, this will show us more information from the memory. We can now see information like the .text and .data sections of the program.

00b801a0  78 6d 00 00 40 00 00 00-70 02 00 00 28 01 00 00  xm..@...p...(...
00b801b0  00 10 00 00 04 04 00 00-00 00 00 00 00 00 00 00  ................
00b801c0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
00b801d0  2e 74 65 78 74 00 00 00-fc a6 00 00 00 10 00 00  .text...........
00b801e0  00 a8 00 00 00 04 00 00-00 00 00 00 00 00 00 00  ................
00b801f0  00 00 00 00 20 00 00 60-2e 64 61 74 61 00 00 00  .... ..`.data...

All of these commands can also be automated with WinDBG via the !peb command, which will give us a very structured and nicely constructed dump of the PEB structure.

0:000> !peb
PEB at 7ffdf000
    InheritedAddressSpace:    No
    ReadImageFileExecOptions: No
    BeingDebugged:            Yes
    ImageBaseAddress:         00870000
    Ldr                       77348880
    Ldr.Initialized:          Yes
    Ldr.InInitializationOrderModuleList: 002b1b58 . 002b46e0
    Ldr.InLoadOrderModuleList:           002b1ab8 . 002b46d0
    Ldr.InMemoryOrderModuleList:         002b1ac0 . 002b46d8

We can also view the command line arguments of the notepad process to get even more information about the process via the dt _peb @$peb processp* command, this will dump us the address of the ProcessParameters.

0:000> dt _peb @$peb processp*
ntdll!_PEB
   +0x010 ProcessParameters : 0x002b1228 _RTL_USER_PROCESS_PARAMETERS

From here we can query information from it with the dt command again, the syntax for that is dt _RTL_USER_PROCESS_PARAMETERS 0x002b1228

0:000> dt _RTL_USER_PROCESS_PARAMETERS 0x002b1228
ntdll!_RTL_USER_PROCESS_PARAMETERS
   +0x000 MaximumLength    : 0x7d2
   +0x004 Length           : 0x7d2
   +0x008 Flags            : 0x2001
   +0x00c DebugFlags       : 0
   +0x010 ConsoleHandle    : (null) 
   +0x014 ConsoleFlags     : 0
   +0x018 StandardInput    : (null) 
   +0x01c StandardOutput   : (null) 
   +0x020 StandardError    : (null) 
   +0x024 CurrentDirectory : _CURDIR
   +0x030 DllPath          : _UNICODE_STRING "C:\Windows\system32;;C:\Windows\system32;C:\Windows\system;C:\Windows;.;C:\Program Files\Debugging Tools for Windows (x86)\winext\arcade;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\Microsoft Windows Performance Toolkit\"
   +0x038 ImagePathName    : _UNICODE_STRING "C:\Windows\system32\notepad.exe"
   +0x040 CommandLine      : _UNICODE_STRING ""C:\Windows\system32\notepad.exe" "
   +0x048 Environment      : 0x002b0810 Void
   +0x04c StartingX        : 0
   +0x050 StartingY        : 0
   +0x054 CountX           : 0
   +0x058 CountY           : 0
   +0x05c CountCharsX      : 0
   +0x060 CountCharsY      : 0
   +0x064 FillAttribute    : 0
   +0x068 WindowFlags      : 0
   +0x06c ShowWindowFlags  : 0
   +0x070 WindowTitle      : _UNICODE_STRING "C:\Windows\system32\notepad.exe"
   +0x078 DesktopInfo      : _UNICODE_STRING "Winsta0\Default"
   +0x080 ShellInfo        : _UNICODE_STRING ""
   +0x088 RuntimeData      : _UNICODE_STRING ""
   +0x090 CurrentDirectores : [32] _RTL_DRIVE_LETTER_CURDIR
   +0x290 EnvironmentSize  : 0xa00
   +0x294 EnvironmentVersion : 1

Located at 0x40 we can see the CommandLine member indicates a Unicode string stating "C:\Windows\system32\notepad.exe", lets use WinDBG to modify this.

And instead of dumping all of the parameters we can specify dumping the memory of a specific member of this by using the syntax dt _UNICODE_STRING 0x002e1228+4, which is querying information including UNICODE STRINGS, at the memory address of the PEB process parameters but adding +40 to indicate the specific member located at 0x40.

0:002> dt _UNICODE_STRING 0x002e1228+40
ntdll!_UNICODE_STRING
 ""C:\Windows\system32\notepad.exe" "
   +0x000 Length           : 0x44
   +0x002 MaximumLength    : 0x46
   +0x004 Buffer           : 0x002e1952  ""C:\Windows\system32\notepad.exe" "

You could specify +70 for example if you wanted to query just the WindowTitle parameter.

ntdll!_UNICODE_STRING
 "C:\Windows\system32\notepad.exe"
   +0x000 Length           : 0x3e
   +0x002 MaximumLength    : 0x40
   +0x004 Buffer           : 0x002e1998  "C:\Windows\system32\notepad.exe"

We can also dump the memory from this address with db again.

0:002> db 0x002e1998
002e1998  43 00 3a 00 5c 00 57 00-69 00 6e 00 64 00 6f 00  C.:.\.W.i.n.d.o.
002e19a8  77 00 73 00 5c 00 73 00-79 00 73 00 74 00 65 00  w.s.\.s.y.s.t.e.
002e19b8  6d 00 33 00 32 00 5c 00-6e 00 6f 00 74 00 65 00  m.3.2.\.n.o.t.e.
002e19c8  70 00 61 00 64 00 2e 00-65 00 78 00 65 00 00 00  p.a.d...e.x.e...
002e19d8  57 00 69 00 6e 00 73 00-74 00 61 00 30 00 5c 00  W.i.n.s.t.a.0.\.
002e19e8  44 00 65 00 66 00 61 00-75 00 6c 00 74 00 00 00  D.e.f.a.u.l.t...
002e19f8  00 00 ab ab ab ab ab ab-ab ab ee fe ee fe ee fe  ................
002e1a08  00 00 00 00 00 00 00 00-3e e6 90 06 df 9a 00 1c  ........>.......

With the address of the specific command-line argument, let’s use the eu command to modify the memory of that location.

0:002> eu 0x002e1952 "This has been changed, pretty cool"
0:002> g

After running the process with g, we can view the notepad instances properties and indeed, the command-line description changed.

image of change


Conclusion

That about wraps it up, we learned a lot of information about what the PEB is, how to get information from it. Also how to change and forge arguments within the PEB to manipulate the running process using WinDBG to modify certain areas of memory that we found via the PEB.

Updated:

Leave a Comment