Back to blog
Dec 09, 2024
3 min read

PEB

Process Environment Block

Process Environment Block

The Process Environment Block (PEB) is a user-mode data structure that each user-mode process possesses. It minimizes user-to-kernel transitions when a process needs information about itself.

Accessing the PEB

Accessing the PEB is typically done through the NtCurrentPeb() macro:

#define NtCurrentPeb()(NtCurrentTeb()->ProcessEnvironmentBlock)

This macro locates the PEB by utilizing the current Thread Environment Block (TEB).

What is the TEB?

The Thread Environment Block (TEB) is the user-mode representation of a thread. It contains detailed information about the thread in kernel mode and at the lower level in user mode. If there is no user-mode footprint, there is no TEB.

In essence, the TEB is also a structure, but it specifically holds information about the currently running thread. It is preferred because thread-related information can be obtained without calling API functions.

The TEB can be accessed through:

  • The GS register on x64 architectures.
  • The FS register on x86 architectures.

Accessing the PEB of Another Process

To access the PEB of another process, you need to call the NtQueryInformationProcess function with the _PROCESS_BASIC_INFORMATION parameter.

So yeah TEB is also a structure but it hold information about the current running thread. Being used because information can be obtained without calling API functions.

TEB is available by accessing the GS register(x64) or FS register(x86).

  ReadProcessMemory(hProc, pbi.PebBaseAddress, &peb, sizeof(PEB), nullptr);

pbi - _PROCESS_BASIC_INFORMATION

peb - _PEB

Getting access to the PEB of another process requires calling #NtQueryInformationProcess with _PROCESS_BASIC_INFORMATION.

Let’s say we have the PEB address, and we would like to read one of its components, such as BeingDebugged. We should use ReadProcessMemory because the PEB points to a memory address in the target process, which we cannot directly access.

ReadProcessMemory(hProc, &pebaddr->BeingDebugged, &BDebgged, sizeof(BDebgged), nullptr));

BDebgged being just a variable to store the value of BeingDebugged. WinDbg:

(!peb / !teb) - shows the content 

(dt _PEB / dt _TEB) - inspecting the structure

As for accessing the address of the PEB internally, you can use:

PEB* peb = (PEB*)__readgsqword(0x60);

This is equivalent to the macro NtCurrentPeb(). But what does it do? It’s quite simple: it reads the value of the GS register and adds 0x60 to it, which is the offset of the PEB in the TEB structure.


References

https://github.com/winsiderss/phnt


Would you like to support me?

If you find my content helpful and would like to support my work, consider visiting my Patreon page.
Your support means the world to me and helps keep this work going!