Appearance
Analysis of Process Environment Block and Thread Environment Block
The Process Environment Block (PEB) and Thread Environment Block (TEB) are key data structures in the Windows operating system, used to store the running environment and state information of processes and threads, respectively. PEB contains process related information, such as startup parameters, module loading information, etc., while TEB contains thread context, local storage, and other information. They provide interfaces to access the running status of processes and threads, which are crucial for program execution and system resource management.
Analysis of PEB structure
This code obtains the PEB structure of the process by accessing the debugger and provides a series of functions to obtain the values of various fields in the PEB, such as whether the process has been debugged, process heap address, LDR address, process base address, system version information, etc. By calling these functions, it is convenient to obtain the running environment and status information of the process, which is helpful for process analysis and debugging.
python
from x32dbg import Debugger
import struct
class _PEB():
def __init__(self, dbg):
# Get the PEB address of the process
self.base = dbg.get_peb_address(dbg.get_process_id())
self.PEB = bytearray()
# Fill the first 488 bytes of PEB
for index in range(0, 488):
readbyte = dbg.get_memory_byte(self.base + index)
self.PEB.append(readbyte)
# Initialize various fields in PEB
index = 0x000
# Inherit address space or not
self.InheritedAddressSpace = self.PEB[index]
index = 0x001
# Read image file execution options
self.ReadImageFileExecOptions = self.PEB[index]
index = 0x002
# Is it being debugged
self.BeingDebugged = self.PEB[index]
index = 0x003
# Backup Boolean
self.SpareBool = self.PEB[index]
index = 0x004
# mutex
self.Mutant = self.PEB[index:index + 4]
index = 0x008
# Image base address
self.ImageBaseAddress = self.PEB[index:index + 4]
index = 0x00c
# loader
self.Ldr = self.PEB[index:index + 4]
index = 0x010
# Process parameters
self.ProcessParameters = self.PEB[index:index + 4]
index = 0x014
# Subsystem data
self.SubSystemData = self.PEB[index:index + 4]
index = 0x018
# Process Heap
self.ProcessHeap = self.PEB[index:index + 4]
index = 0x01c
# Fast PEB lock
self.FastPebLock = self.PEB[index:index + 4]
index = 0x020
# Quick PEB lock routine
self.FastPebLockRoutine = self.PEB[index:index + 4]
index = 0x024
# Quick PEB unlocking routine
self.FastPebUnlockRoutine = self.PEB[index:index + 4]
index = 0x028
# Environment update count
self.EnviromentUpdateCount = self.PEB[index:index + 4]
index = 0x02c
# Kernel callback table
self.KernelCallbackTable = self.PEB[index:index + 4]
index = 0x030
self.SystemReserved = []
for i in range(0, 2):
# System retention
self.SystemReserved.append(self.PEB[index:index + 4])
index += 4
index = 0x038
# free list
self.FreeList = self.PEB[index:index + 4]
index = 0x03c
# TLS extension counter
self.TlsExpansionCounter = self.PEB[index:index + 4]
index = 0x040
# TLS Bitmap
self.TlsBitmap = self.PEB[index:index + 4]
index = 0x044
self.TlsBitmapBits = []
for i in range(0, 2):
# TLS Bitmap Bit
self.TlsBitmapBits.append(self.PEB[index:index + 4])
index += 4
index = 0x04c
# Read only shared memory base address
self.ReadOnlySharedMemoryBase = self.PEB[index:index + 4]
index = 0x050
# Read only shared memory heap
self.ReadOnlySharedMemoryheap = self.PEB[index:index + 4]
index = 0x054
# Read only static server data
self.ReadOnlyStaticServerData = self.PEB[index:index + 4]
index = 0x058
# ANSI code page data
self.AnsiCodePageData = self.PEB[index:index + 4]
index = 0x05c
# OEM code page data
self.OemCodePageData = self.PEB[index:index + 4]
index = 0x060
# Unicode capitalization table data
self.UnicodeCaseTableData = self.PEB[index:index + 4]
index = 0x064
# Number of processors
self.NumberOfProcessors = self.PEB[index:index + 4]
index = 0x068
# Nt Global Flag
self.NtGlobalFlag = self.PEB[index:index + 4]
index = 0x070
# Critical section timeout low section
self.CriticalSectionTimeout_LowPart = self.PEB[index:index + 4]
index = 0x074
# Key parts timeout high part
self.CriticalSectionTimeout_HighPart = self.PEB[index:index + 4]
index = 0x078
# Stockpile reserve
self.HeapSegmentReserve = self.PEB[index:index + 4]
index = 0x07c
# Segment submission
self.HeapSegmentCommit = self.PEB[index:index + 4]
index = 0x080
# Total idle threshold for heap cancellation
self.HeapDeCommitTotalFreeThreshold = self.PEB[index:index + 4]
index = 0x084
# Free block threshold for heap cancellation
self.HeapDeCommitFreeBlockThreshold = self.PEB[index:index + 4]
index = 0x088
# Number of piles
self.NumberOfHeaps = self.PEB[index:index + 4]
index = 0x08c
# Maximum number of piles
self.MaximumNumberOfHeaps = self.PEB[index:index + 4]
index = 0x090
# Process Heap
self.ProcessHeaps = self.PEB[index:index + 4]
index = 0x094
# GDI Shared Handle Table
self.GdiSharedHandleTable = self.PEB[index:index + 4]
index = 0x098
# Process Launcher Assistant
self.ProcessStarterHelper = self.PEB[index:index + 4]
index = 0x09c
# GDI DC attribute list
self.GdiDCAttributeList = self.PEB[index:index + 4]
index = 0x0a0
# Loader lock
self.LoaderLock = self.PEB[index:index + 4]
index = 0x0a4
# Operating system major version number
self.OSMajorVersion = self.PEB[index:index + 4]
index = 0x0a8
# Operating system minor version number
self.OSMinorVersion = self.PEB[index:index + 4]
index = 0x0ac
# Operating system generation number
self.OSBuildNumber = self.PEB[index:index + 2]
index = 0x0ae
# Operating System CSD Version
self.OSCSDVersion = self.PEB[index:index + 2]
index = 0x0b0
# Operating System Platform ID
self.OSPlatformId = self.PEB[index:index + 4]
index = 0x0b4
# Image subsystem
self.ImageSubsystem = self.PEB[index:index + 4]
index = 0x0b8
# Image subsystem main version number
self.ImageSubsystemMajorVersion = self.PEB[index:index + 4]
index = 0x0bc
# Image subsystem sub version number
self.ImageSubsystemMinorVersion = self.PEB[index:index + 4]
index = 0x0c0
# Image process association mask
self.ImageProcessAffinityMask = self.PEB[index:index + 4]
index = 0x0c4
# uint32 GdiHandleBuffer[34]
self.GdiHandleBuffer = []
for i in range(0, 34):
# GDI Handle Buffer
self.GdiHandleBuffer.append(self.PEB[index:index + 4])
index += 4
index = 0x14c
# Post processing initialization routine
self.PostProcessInitRoutine = self.PEB[index:index + 4]
index = 0x150
# TLS Extended Bitmap
self.TlsExpansionBitmap = self.PEB[index:index + 4]
index = 0x154
# uint32 TlsExpansionBitmapBits[32]
self.TlsExpansionBitmapBits = []
for i in range(0, 32):
# TLS Extended Bitmap Bit
self.TlsExpansionBitmapBits.append(self.PEB[index:index + 4])
index += 4
index = 0x1d4
# Session ID
self.SessionId = self.PEB[index:index + 4]
index = 0x1d8
# Compatibility information
self.AppCompatInfo = self.PEB[index:index + 4]
index = 0x1dc
# struct _UNICODE_STRING CSDVersion
# CSD version string length
self.CSDVersion_Length = self.PEB[index:index + 2]
index += 2
# CSD version string maximum length
self.CSDVersion_MaximumLength = self.PEB[index:index + 2]
index += 2
# CSD version string buffer address
self.CSDVersion_Buffer = self.PEB[index:index + 2]
index += 2
def get_BeingDebugged(self):
return self.BeingDebugged
def get_ProcessHeaps(self):
pack = struct.unpack('<L', bytes(self.ProcessHeap))
return hex(pack[0])
def get_Ldr(self):
pack = struct.unpack('<L', bytes(self.Ldr))
return hex(pack[0])
def get_NumberOfHeaps(self):
pack = struct.unpack('<L', bytes(self.NumberOfHeaps))
return pack[0]
def get_ImageBaseAddress(self):
pack = struct.unpack('<L', bytes(self.ImageBaseAddress))
return hex(pack[0])
def get_NumberOfProcessors(self):
pack = struct.unpack('<L', bytes(self.NumberOfProcessors))
return pack[0]
def get_OSVersion(self):
major_version = struct.unpack('<L', bytes(self.OSMajorVersion))
minor_version = struct.unpack('<L', bytes(self.OSMinorVersion))
build_number = struct.unpack('<H', bytes(self.OSBuildNumber))
csd_version = struct.unpack('<H', bytes(self.OSCSDVersion))
return f"{major_version}.{minor_version}.{build_number}.{csd_version}"
def get_GdiHandleBuffer(self):
handle_buffer = []
for handle in self.GdiHandleBuffer:
handle_value = struct.unpack('<L', bytes(handle))
handle_buffer.append(hex(handle_value[0]))
return handle_buffer
def get_FastPebLock(self):
pack = struct.unpack('<L', bytes(self.FastPebLock))
return hex(pack[0])
def get_HeapSegmentReserve(self):
pack = struct.unpack('<L', bytes(self.HeapSegmentReserve))
return hex(pack[0])
def get_GdiSharedHandleTable(self):
pack = struct.unpack('<L', bytes(self.GdiSharedHandleTable))
return hex(pack[0])
def get_AppCompatInfo(self):
pack = struct.unpack('<L', bytes(self.AppCompatInfo))
return hex(pack[0])
def get_CSDVersion(self):
length = struct.unpack('<H', bytes(self.CSDVersion_Length))
maximum_length = struct.unpack('<H', bytes(self.CSDVersion_MaximumLength))
buffer_address = struct.unpack('<H', bytes(self.CSDVersion_Buffer))
return f"Length: {length}, Maximum Length: {maximum_length}, Buffer Address: {buffer_address}"
if __name__ == "__main__":
dbg = Debugger(address="127.0.0.1", port=6589)
if dbg.connect() == True:
# Initialize PEB structure
peb_struct = _PEB(dbg)
# Has the process been debugged
is_debug = peb_struct.get_BeingDebugged()
print("Has the process been debugged = {}".format(is_debug))
# Get the entry address of the heap in the process
heap_address = peb_struct.get_ProcessHeaps()
print("Process heap address = {}".format(heap_address))
# Process LDR address
ldr_address = peb_struct.get_Ldr()
print("Process LDR address = {}".format(ldr_address))
# Get process base address
base_address = peb_struct.get_ImageBaseAddress()
print("Process base address = {}".format(base_address))
# Obtain system version number information
version = peb_struct.get_OSVersion()
print("System version = {}".format(version))
dbg.close_connect()
After the program runs successfully, it will output the following content:
python
Has the process been debugged = 1
Process heap address = 0xfd0000
Process LDR address = 0x77bf0c40
Process base address = 0xe80000
System version = (10,).(0,).(17763,).(0,)
Analysis of TEB structure
This code defines a class called TEB to retrieve information about the Thread Environment Block (TEB). By communicating with the debugger, it can access the TEB of the current thread in the process and provide a series of methods to obtain the values of various fields in the TEB, such as thread ID, last error value, current region setting, etc. In the main program, it first connects to the debugger, then instantiates the TEB class and calls its methods to obtain the current region setting information of the thread and print it out.
python
from x32dbg import Debugger
import struct
class _TEB():
def __init__(self, dbg):
# Get the base address of the Thread Environment Block (TEB)
self.base = dbg.get_teb_address(dbg.get_thread_id())
# Create a byte array to store the content of TEB
self.TEB = bytearray()
# Read the content of TEB
for index in range(0, 512):
readbyte = dbg.get_memory_byte(self.base + index)
self.TEB.append(readbyte)
# Initialize the various fields of the TEB structure
index = 0x000
# The NtTib pointer points to the address of the thread environment block
self.NtTib = self.TEB[index:index+4]
index = 0x004
# EnvironmentPointer points to the address of the environment block
self.EnvironmentPointer = self.TEB[index:index+4]
index = 0x008
# ClientId represents the thread ID
self.ClientId = self.TEB[index:index+8]
# ActiveRpcHandle represents the RPC handle of the current thread
index = 0x010
self.ActiveRpcHandle = self.TEB[index:index+4]
# ThreadLocalStoragePointer pointer to the thread's local storage
index = 0x014
self.ThreadLocalStoragePointer = self.TEB[index:index+4]
# ProcessEnvironmentBlock points to the address of the process environment block
index = 0x018
self.ProcessEnvironmentBlock = self.TEB[index:index+4]
# LastErrorValue represents the last error value of the thread
index = 0x01c
self.LastErrorValue = self.TEB[index:index+4]
# CountOfOwnedCriticalSections represents the number of critical sections owned by a thread
index = 0x020
self.CountOfOwnedCriticalSections = self.TEB[index:index+4]
# CsrClientThread represents a CSRSS thread
index = 0x024
self.CsrClientThread = self.TEB[index:index+4]
# Win32ThreadInfo pointer to the information of the Win32 thread
index = 0x028
self.Win32ThreadInfo = self.TEB[index:index+4]
# User32Reserved is a field reserved for user space
index = 0x02c
self.User32Reserved = self.TEB[index:index+4]
# UserReserved is a field reserved for users
index = 0x030
self.UserReserved = self.TEB[index:index+4]
# WOW32Reserved is a field reserved for WOW64 threads
index = 0x034
self.WOW32Reserved = self.TEB[index:index+4]
# Current Locale
index = 0x038
self.CurrentLocale = self.TEB[index:index+4]
# FpSoftwareStatusRegister floating-point software status register
index = 0x03c
self.FpSoftwareStatusRegister = self.TEB[index:index+4]
# SystemReserved1 is a field reserved by the system
index = 0x040
self.SystemReserved1 = self.TEB[index:index+4]
# ExceptionCode represents the current exception code of the thread
index = 0x044
self.ExceptionCode = self.TEB[index:index+4]
# ActivationContextStackPointer represents the pointer to the activated context stack
index = 0x048
self.ActivationContextStackPointer = self.TEB[index:index+4]
# SpareBytes1 is a reserved field
index = 0x04c
self.SpareBytes1 = self.TEB[index:index+36]
# TxFsContext Transaction File System (TxF) Context
index = 0x070
self.TxFsContext = self.TEB[index:index+4]
# GdiTebBatch for TEB in GDI batch processing
index = 0x074
self.GdiTebBatch = self.TEB[index:index+124]
# RealClientId
index = 0x0f0
self.RealClientId = self.TEB[index:index+8]
# GDI process handle cached by GdiCachedProcessHandle
index = 0x0f8
self.GdiCachedProcessHandle = self.TEB[index:index+4]
# GdiClientPID GDI client process ID
index = 0x0fc
self.GdiClientPID = self.TEB[index:index+4]
# GdiClientTID GDI client thread ID
index = 0x100
self.GdiClientTID = self.TEB[index:index+4]
# GdiThreadLocalInfo GDI thread local information
index = 0x104
self.GdiThreadLocalInfo = self.TEB[index:index+4]
# Win32ClientInfo
index = 0x108
self.Win32ClientInfo = self.TEB[index:index+36]
# GlDispatchTable OpenGL's scheduling table
index = 0x12c
self.glDispatchTable = self.TEB[index:index+488]
# GlReserved1 is a field reserved for OpenGL
index = 0x324
self.glReserved1 = self.TEB[index:index+104]
# GlReserved2 is a field reserved for OpenGL
index = 0x394
self.glReserved2 = self.TEB[index:index+8]
# GlSectionInfo OpenGL Section Information
index = 0x39c
self.glSectionInfo = self.TEB[index:index+4]
# GlSection OpenGL
index = 0x3a0
self.glSection = self.TEB[index:index+4]
# GlTable OpenGL Table
index = 0x3a4
self.glTable = self.TEB[index:index+4]
# GlCurrentRC's current OpenGL context
index = 0x3a8
self.glCurrentRC = self.TEB[index:index+4]
# GlContext OpenGL Context
index = 0x3ac
self.glContext = self.TEB[index:index+4]
# The last status value of LastStatusValue
index = 0x3b0
self.LastStatusValue = self.TEB[index:index+4]
# StaticUnicode String
index = 0x3b4
self.StaticUnicodeString = self.TEB[index:index+68]
# StaticUnicode Buffer
index = 0x3f8
self.StaticUnicodeBuffer = self.TEB[index:index+68]
# Padding is used to fill in fields
index = 0x43c
self.padding = self.TEB[index:index+8]
def get_ThreadId(self):
pack = struct.unpack('<LL', bytes(self.ClientId))
return pack[0]
def get_LastErrorValue(self):
pack = struct.unpack('<L', bytes(self.LastErrorValue))
return pack[0]
def get_CurrentLocale(self):
pack = struct.unpack('<L', bytes(self.CurrentLocale))
return hex(pack[0])
def get_GdiTebBatch(self):
return self.GdiTebBatch
def get_glDispatchTable(self):
return self.glDispatchTable
if __name__ == "__main__":
dbg = Debugger(address="127.0.0.1", port=6589)
if dbg.connect() == True:
# Initialize TEB structure
teb_struct = _TEB(dbg)
# Read thread ID
thread_id = teb_struct.get_ThreadId()
print("ThreadID = {}".format(hex(thread_id)))
# Read get_LastErrorValue
lasterror_value = teb_struct.get_LastErrorValue()
print("LastErrorValue = {}".format(lasterror_value))
dbg.close_connect()
After the program runs successfully, it will output the following content:
python
ThreadID = 0xf8c000
LastErrorValue = 0