PEB结构(Process Envirorment Block Structure)
其中文名是进程环境块信息,进程环境块内部包含了进程运行的详细参数信息,每一个进程在运行后都会存在一个特有的PEB结构,通过附加进程并遍历这段结构即可得到非常多的有用信息。
在应用层下,如果想要得到PEB的基地址只需要取fs:[0x30]
即可,TEB线程环境块则是fs:[0x18]
,如果在内核层想要得到应用层进程的PEB信息我们需要调用特定的内核函数来获取。
在内核层要获取应用层进程的PEB结构,可以通过以下步骤实现:
- 1.调用内核函数
PsGetCurrentProcess
获取当前进程的EPROCESS
结构。
- 2.调用内核函数
KeStackAttachProcess
,附加到目标进程。
- 3.调用内核函数
PsGetProcessWow64Process
,获取目标进程的PEB结构信息。
- 4.通过
PEB
结构的Ldr
成员可以访问到该进程加载的所有模块,遍历整个Ldr
链表即可得到需要的模块信息。
- 5.遍历完成后,通过调用
KeUnstackDetachProcess
函数脱离进程空间。
首先在开始写代码之前需要先定义好PEB
进程环境快结构体,用于对内存指针解析,新建peb.h
文件并保存如下代码,这些是微软的结构定义分为32位与64位,官方定义规范而已不需要费工夫。
#pragma once #include <ntifs.h>
typedef struct _CURDIR // 2 elements, 0x18 bytes (sizeof) { struct _UNICODE_STRING DosPath; VOID* Handle; }CURDIR, *PCURDIR;
typedef struct _RTL_DRIVE_LETTER_CURDIR // 4 elements, 0x18 bytes (sizeof) { UINT16 Flags; UINT16 Length; ULONG32 TimeStamp; struct _STRING DosPath; }RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;
typedef enum _SYSTEM_DLL_TYPE // 7 elements, 0x4 bytes { PsNativeSystemDll = 0 , PsWowX86SystemDll = 1 , PsWowArm32SystemDll = 2 , PsWowAmd64SystemDll = 3 , PsWowChpeX86SystemDll = 4 , PsVsmEnclaveRuntimeDll = 5 , PsSystemDllTotalTypes = 6 }SYSTEM_DLL_TYPE, *PSYSTEM_DLL_TYPE;
typedef struct _EWOW64PROCESS // 3 elements, 0x10 bytes (sizeof) { VOID* Peb; UINT16 Machine; UINT8 _PADDING0_[0x2]; enum _SYSTEM_DLL_TYPE NtdllType; }EWOW64PROCESS, *PEWOW64PROCESS;
typedef struct _RTL_USER_PROCESS_PARAMETERS // 37 elements, 0x440 bytes (sizeof) { ULONG32 MaximumLength; ULONG32 Length; ULONG32 Flags; ULONG32 DebugFlags; VOID* ConsoleHandle; ULONG32 ConsoleFlags; UINT8 _PADDING0_[0x4]; VOID* StandardInput; VOID* StandardOutput; VOID* StandardError; struct _CURDIR CurrentDirectory; struct _UNICODE_STRING DllPath; struct _UNICODE_STRING ImagePathName; struct _UNICODE_STRING CommandLine; VOID* Environment; ULONG32 StartingX; ULONG32 StartingY; ULONG32 CountX; ULONG32 CountY; ULONG32 CountCharsX; ULONG32 CountCharsY; ULONG32 FillAttribute; ULONG32 WindowFlags; ULONG32 ShowWindowFlags; UINT8 _PADDING1_[0x4]; struct _UNICODE_STRING WindowTitle; struct _UNICODE_STRING DesktopInfo; struct _UNICODE_STRING ShellInfo; struct _UNICODE_STRING RuntimeData; struct _RTL_DRIVE_LETTER_CURDIR CurrentDirectores[32]; UINT64 EnvironmentSize; UINT64 EnvironmentVersion; VOID* PackageDependencyData; ULONG32 ProcessGroupId; ULONG32 LoaderThreads; struct _UNICODE_STRING RedirectionDllName; struct _UNICODE_STRING HeapPartitionName; UINT64* DefaultThreadpoolCpuSetMasks; ULONG32 DefaultThreadpoolCpuSetMaskCount; UINT8 _PADDING2_[0x4]; }RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
typedef struct _PEB_LDR_DATA // 9 elements, 0x58 bytes (sizeof) { ULONG32 Length; UINT8 Initialized; UINT8 _PADDING0_[0x3]; VOID* SsHandle; struct _LIST_ENTRY InLoadOrderModuleList; struct _LIST_ENTRY InMemoryOrderModuleList; struct _LIST_ENTRY InInitializationOrderModuleList; VOID* EntryInProgress; UINT8 ShutdownInProgress; UINT8 _PADDING1_[0x7]; VOID* ShutdownThreadId; }PEB_LDR_DATA, *PPEB_LDR_DATA;
typedef struct _PEB64 { UCHAR InheritedAddressSpace; UCHAR ReadImageFileExecOptions; UCHAR BeingDebugged; UCHAR BitField; ULONG64 Mutant; ULONG64 ImageBaseAddress; PPEB_LDR_DATA Ldr; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; ULONG64 SubSystemData; ULONG64 ProcessHeap; ULONG64 FastPebLock; ULONG64 AtlThunkSListPtr; ULONG64 IFEOKey; ULONG64 CrossProcessFlags; ULONG64 UserSharedInfoPtr; ULONG SystemReserved; ULONG AtlThunkSListPtr32; ULONG64 ApiSetMap; } PEB64, *PPEB64;
#pragma pack(4) typedef struct _PEB32 { UCHAR InheritedAddressSpace; UCHAR ReadImageFileExecOptions; UCHAR BeingDebugged; UCHAR BitField; ULONG Mutant; ULONG ImageBaseAddress; ULONG Ldr; ULONG ProcessParameters; ULONG SubSystemData; ULONG ProcessHeap; ULONG FastPebLock; ULONG AtlThunkSListPtr; ULONG IFEOKey; ULONG CrossProcessFlags; ULONG UserSharedInfoPtr; ULONG SystemReserved; ULONG AtlThunkSListPtr32; ULONG ApiSetMap; } PEB32, *PPEB32;
typedef struct _PEB_LDR_DATA32 { ULONG Length; BOOLEAN Initialized; ULONG SsHandle; LIST_ENTRY32 InLoadOrderModuleList; LIST_ENTRY32 InMemoryOrderModuleList; LIST_ENTRY32 InInitializationOrderModuleList; ULONG EntryInProgress; } PEB_LDR_DATA32, *PPEB_LDR_DATA32;
typedef struct _LDR_DATA_TABLE_ENTRY32 { LIST_ENTRY32 InLoadOrderLinks; LIST_ENTRY32 InMemoryOrderModuleList; LIST_ENTRY32 InInitializationOrderModuleList; ULONG DllBase; ULONG EntryPoint; ULONG SizeOfImage; UNICODE_STRING32 FullDllName; UNICODE_STRING32 BaseDllName; ULONG Flags; USHORT LoadCount; USHORT TlsIndex; union { LIST_ENTRY32 HashLinks; ULONG SectionPointer; }u1; ULONG CheckSum; union { ULONG TimeDateStamp; ULONG LoadedImports; }u2; ULONG EntryPointActivationContext; ULONG PatchInformation; } LDR_DATA_TABLE_ENTRY32, *PLDR_DATA_TABLE_ENTRY32;
#pragma pack()
|
接着就来实现对PEB的获取操作,以64位
为例,我们需要调用PsGetProcessPeb()
这个内核函数,因为该内核函数没有被公开所以调用之前需要头部导出,该函数需要传入用户进程的EProcess
结构,该结构可用PsLookupProcessByProcessId
函数动态获取到,获取到以后直接KeStackAttachProcess()
附加到应用层进程上,即可直接输出进程的PEB结构信息,如下代码。
#include "peb.h" #include <ntifs.h>
NTKERNELAPI PVOID NTAPI PsGetProcessPeb(_In_ PEPROCESS Process);
VOID UnDriver(PDRIVER_OBJECT driver) { DbgPrint(("Uninstall Driver Is OK \n")); }
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath) { DbgPrint("hello lyshark \n");
NTSTATUS status = STATUS_UNSUCCESSFUL; PEPROCESS eproc = NULL; KAPC_STATE kpc = { 0 };
PPEB64 pPeb64 = NULL;
__try { status = PsLookupProcessByProcessId((HANDLE)4656, &eproc);
pPeb64 = (PPEB64)PsGetProcessPeb(eproc);
DbgPrint("PEB64 = %p \n", pPeb64);
if (pPeb64 != 0) { ProbeForRead(pPeb64, sizeof(PEB32), 1);
KeStackAttachProcess(eproc, &kpc);
DbgPrint("进程基地址: 0x%p \n", pPeb64->ImageBaseAddress); DbgPrint("ProcessHeap = 0x%p \n", pPeb64->ProcessHeap); DbgPrint("BeingDebugged = %d \n", pPeb64->BeingDebugged);
KeUnstackDetachProcess(&kpc); } } __except (EXCEPTION_EXECUTE_HANDLER) { Driver->DriverUnload = UnDriver; return STATUS_SUCCESS; }
Driver->DriverUnload = UnDriver; return STATUS_SUCCESS; }
|
PEB64代码运行后,我们加载驱动即可看到如下结果:
而相对于64位进程来说,获取32位
进程的PEB信息可以直接调用PsGetProcessWow64Process()
函数得到,该函数已被导出可以任意使用,获取PEB代码如下。
#include "peb.h" #include <ntifs.h>
NTKERNELAPI PVOID NTAPI PsGetProcessPeb(_In_ PEPROCESS Process);
VOID UnDriver(PDRIVER_OBJECT driver) { DbgPrint(("Uninstall Driver Is OK \n")); }
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath) { DbgPrint("hello lyshark \n");
NTSTATUS status = STATUS_UNSUCCESSFUL; PEPROCESS eproc = NULL; KAPC_STATE kpc = { 0 };
PPEB32 pPeb32 = NULL;
__try { status = PsLookupProcessByProcessId((HANDLE)6164, &eproc);
pPeb32 = (PPEB32)PsGetProcessWow64Process(eproc);
DbgPrint("PEB32 = %p \n", pPeb32);
if (pPeb32 != 0) { ProbeForRead(pPeb32, sizeof(PEB32), 1);
KeStackAttachProcess(eproc, &kpc);
DbgPrint("进程基地址: 0x%p \n", pPeb32->ImageBaseAddress); DbgPrint("ProcessHeap = 0x%p \n", pPeb32->ProcessHeap); DbgPrint("BeingDebugged = %d \n", pPeb32->BeingDebugged);
KeUnstackDetachProcess(&kpc); } } __except (EXCEPTION_EXECUTE_HANDLER) { Driver->DriverUnload = UnDriver; return STATUS_SUCCESS; }
Driver->DriverUnload = UnDriver; return STATUS_SUCCESS; }
|
PEB32代码运行后,我们加载驱动即可看到如下结果: