PEBはWindowsのプロセス構造であり、プロセス作成の段階でローダーによって埋められます。これには、環境、ロードされたモジュール(LDR_DATA)、現在のモジュールの基本情報、およびプロセスが機能するために必要なその他の重要なデータに関する情報が含まれます。 プロセス内のモジュール(ライブラリ)に関する情報を受け取る多くのシステムウィンドウAPIは、ReadProcessMemoryを呼び出して、目的のプロセスのPEBから情報を読み取ります。
TEB-現在のプロセスのスレッドに関する情報を保存するために使用される構造。各スレッドには独自のTEBがあります。 Windows上のWow64プロセスには、2つのプロセス環境ブロックと2つのスレッド環境ブロックがあります。 TEBはMmCreateTeb関数によって作成され、PEBはMmCreatePeb関数によって作成されます。作成プロセスが興味深い場合は、ReactOSソースを確認するか、WinDBGを取得して自分で調べることができます。 目標は、別のプロセスのPEBを変更することでした。
TEBの形式は次のとおりです。
typedef struct _CLIENT_ID { DWORD UniqueProcess; DWORD UniqueThread; } CLIENT_ID, *PCLIENT_ID; typedef struct _THREAD_BASIC_INFORMATION { typedef PVOID KPRIORITY; NTSTATUS ExitStatus; PVOID TebBaseAddress; CLIENT_ID ClientId; KAFFINITY AffinityMask; KPRIORITY Priority; KPRIORITY BasePriority; } THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;
[TEB+0] SEH . [TEB+4] , . [TEB+8] , . [TEB+18] TEB. [TEB+30] PEB.
特定のスレッドのTEBを取得するには、NtQueryInformationThreadを使用できます。
#include <Windows.h> #include <stdio.h> #pragma comment(lib,"ntdll.lib") typedef struct _CLIENT_ID { DWORD UniqueProcess; DWORD UniqueThread; } CLIENT_ID, *PCLIENT_ID; typedef struct _THREAD_BASIC_INFORMATION { typedef PVOID KPRIORITY; NTSTATUS ExitStatus; PVOID TebBaseAddress; CLIENT_ID ClientId; KAFFINITY AffinityMask; KPRIORITY Priority; KPRIORITY BasePriority; } THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION; typedef enum _THREADINFOCLASS { ThreadBasicInformation, ThreadTimes, ThreadPriority, ThreadBasePriority, ThreadAffinityMask, ThreadImpersonationToken, ThreadDescriptorTableEntry, ThreadEnableAlignmentFaultFixup, ThreadEventPair_Reusable, ThreadQuerySetWin32StartAddress, ThreadZeroTlsCell, ThreadPerformanceCount, ThreadAmILastThread, ThreadIdealProcessor, ThreadPriorityBoost, ThreadSetTlsArrayAddress, ThreadIsIoPending, ThreadHideFromDebugger, ThreadBreakOnTermination, MaxThreadInfoClass } THREADINFOCLASS; THREADINFOCLASS ThreadInformationClass; extern "C" { NTSTATUS WINAPI NtQueryInformationThread( _In_ HANDLE ThreadHandle, _In_ THREADINFOCLASS ThreadInformationClass, _Inout_ PVOID ThreadInformation, _In_ ULONG ThreadInformationLength, _Out_opt_ PULONG ReturnLength ); } THREAD_BASIC_INFORMATION ThreadInfo; DWORD ntstatus = NtQueryInformationThread( GetCurrentThread(), // ThreadBasicInformation, &ThreadInfo, //ThreadInfo.TebBaseAddress . sizeof(THREAD_BASIC_INFORMATION), 0 ); // teb , __readfsdword(0x18) 32 __readgsqword(0x30) 64.
MSDNでは、32ビットプロセスのPEBは次のように記述されています。
typedef struct _PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; PVOID Reserved3[2]; PPEB_LDR_DATA Ldr; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; BYTE Reserved4[104]; PVOID Reserved5[52]; PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine; BYTE Reserved6[128]; PVOID Reserved7[1]; ULONG SessionId; } PEB, *PPEB;
および64ビットの場合:
typedef struct _PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[21]; PPEB_LDR_DATA LoaderData; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; BYTE Reserved3[520]; PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine; BYTE Reserved4[136]; ULONG SessionId; } PEB;
私のプロジェクトは32ビットと64ビットに次の構造を使用 PEBは次のようにして取得できます。
kernel32ベースとGetProcAddressアドレスの取得:
特定のプロセスのベースPEBアドレスは、次のように取得されます。
typedef enum _PROCESSINFOCLASS { ProcessBasicInformation = 0 } PROCESSINFOCLASS; status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(PROCESS_BASIC_INFORMATION), &dwLength); if(status != 0x0) { printf("NtQueryInformationProcess Error 0x%x\n", status); exit(EXIT_FAILURE); } printf("PEB address : 0x%x\n", pbi.PebBaseAddress);
興味深い観察結果は、LDR_DATAを少し台無しにした場合、GetModuleHandleExやEnumProcessModulesなどのAPI関数は、QueryFullProcessImageNameがPEBを読み取るためにReadProcessMemoryを呼び出すため、望ましい結果を生成しないことです。 多くのコードがあるため、PEBを使用した操作(プロセスからの読み取り、変更、書き込み)は、単純なテストクラスの形式で配置され
ます 。