Exploring Process Environment Block
Exploring a couple of interesting members of the PEB memory structure fields
A very brief look into the PEB memory structure found, aiming to get a bit more comfortable with WinDBG and walking memory structures.

Basics

First of, checking what members the _PEB structure actually entails:
1
dt _peb
Copied!
There are many fields in the structure among which there are ImageBaseAddresss and ProcessParameters which are interesting to us for this lab:
Getting the PEB address of the process:
1
0:001> r $peb
2
$peb=000007fffffd5000
Copied!
The _PEB structure can now be overlaid on the memory pointed to by the $peb to see what values the structure members are holding/pointing to:
1
0:001> dt _peb @$peb
Copied!
_PEB structure is now populated with the actual data pulled from the process memory:
Let's check what's in memory at address 0000000049d40000 - pointed to by the ImageBaseAddress member of the _peb structure:
1
0:001> db 0000000049d40000 L100
Copied!
Exactly! This is the actual binary image of the running process:
Another way of finding the ImageBaseAddress is:
1
0:001> dt _peb
2
ntdll!_PEB
3
//snip
4
+0x010 ImageBaseAddress : Ptr64 Void
5
//snip
6
7
0:001> dd @$peb+0x010 L2
8
000007ff`fffd5010 49d40000 00000000
9
10
// 49d40000 00000000 is little-endian byte format - need to invert
11
0:001> db 0000000049d40000 L100
Copied!

Convenience

We can forget about all of the above and just use:
1
!peb
Copied!
This gets us a nicely formatted PEB information of some of the key members of the structure:

Finding Commandline Arguments

One of the interesting fields the PEB holds is the process commandline arguments. Let's find them:
1
dt _peb @$peb processp*
2
ntdll!_PEB
3
+0x020 ProcessParameters : 0x00000000`002a1f40 _RTL_USER_PROCESS_PARAMETERS
4
5
dt _RTL_USER_PROCESS_PARAMETERS 0x00000000`002a1f40
Copied!
We can be more direct and ask the same question like so:
1
0:001> dt _UNICODE_STRING 0x00000000`002a1f40+70
2
ntdll!_UNICODE_STRING
3
""C:\Windows\system32\cmd.exe" "
4
+0x000 Length : 0x3c
5
+0x002 MaximumLength : 0x3e
6
+0x008 Buffer : 0x00000000`002a283c ""C:\Windows\system32\cmd.exe" "
Copied!
or even this:
1
0:001> dd 0x00000000`002a1f40+70+8 L2
2
00000000`002a1fb8 002a283c 00000000
3
0:001> du 00000000002a283c
4
00000000`002a283c ""C:\Windows\system32\cmd.exe" "
Copied!
Since we now know where the commandline arguments are stored - can we modify them? Of course.

Forging Commandline Arguments

1
0:001> eu 00000000002a283c "cmdline-logging? Are You Sure?"
Copied!

_PEB_LDR_DATA

Getting a list of loaded modules (exe/dll) by the process:
1
// get the first _LIST_ENTRY structure address
2
0:001> dt _peb @$peb ldr->InMemoryOrderModuleList*
3
ntdll!_PEB
4
+0x018 Ldr :
5
+0x020 InMemoryOrderModuleList : _LIST_ENTRY [ 0x00000000`002a2980 - 0x00000000`002a1e40 ]
6
7
8
// walking the list manually and getting loaded module info
9
dt _LIST_ENTRY 0x00000000`002a2980
10
// cmd module
11
dt _LDR_DATA_TABLE_ENTRY 0x00000000`002a2980
12
13
dt _LIST_ENTRY 0x00000000`002a2980
14
// ntdll module
15
dt _LDR_DATA_TABLE_ENTRY 0x00000000`002a2a70
16
17
dt _LIST_ENTRY 0x00000000`002a2a70
18
// kernel32 module
19
dt _LDR_DATA_TABLE_ENTRY 0x00000000`002a2df0
20
21
...loop...
Copied!
If we check the loaded modules with !peb, it shows we were walking the list correctly:
Here is another way to find the first _LDR_DATA_TABLE_ENTRY:
1
dt _peb @$peb
2
dt _PEB_LDR_DATA 0x00000000`774ed640
Copied!
1
dt _LDR_DATA_TABLE_ENTRY 0x00000000`002a2980
Copied!
A nice way of getting a list of linked-list structure addresses is by providing address of the first list_entry structure to the command dl and specifying how many list items it should print out:
1
0:001> dl 0x00000000`002a2980 6
2
00000000`002a2980 00000000`002a2a70 00000000`774ed660
3
00000000`002a2990 00000000`00000000 00000000`00000000
4
00000000`002a2a70 00000000`002a2df0 00000000`002a2980
5
00000000`002a2a80 00000000`002a2f70 00000000`774ed670
6
00000000`002a2df0 00000000`002a2f60 00000000`002a2a70
7
00000000`002a2e00 00000000`002a3cb0 00000000`002a2f70
8
00000000`002a2f60 00000000`002a3ca0 00000000`002a2df0
9
00000000`002a2f70 00000000`002a2e00 00000000`002a2a80
10
00000000`002a3ca0 00000000`002a41f0 00000000`002a2f60
11
00000000`002a3cb0 00000000`002defc0 00000000`002a2e00
12
00000000`002a41f0 00000000`002a3ff0 00000000`002a3ca0
13
00000000`002a4200 00000000`002e1320 00000000`002a4000
Copied!
Another way of achieving the same would be to use the !list command to list through the list items and dump the info:
1
!list -x "dt _LDR_DATA_TABLE_ENTRY" 0x00000000`002a2980
Copied!
Continuing further:

Abusing PEB

It is possible to abuse the PEB structure and masquerade one windows processes with another process. See this lab for more:

References

https://docs.microsoft.com/en-us/windows/desktop/api/winternl/ns-winternl-_peb_ldr_data
docs.microsoft.com
Common WinDbg Commands (Thematically Grouped)
PEB LDR DATA - aldeid
list (WinDbg) - Windows drivers
docsmsft
https://docs.microsoft.com/en-us/windows/desktop/api/winternl/ns-winternl-_peb_ldr_data
docs.microsoft.com
WinDbg : the !peb Command
Jump$
Last modified 2yr ago