PEBおよびTEBと連携する

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ビットに次の構造を使用
 //  - http://blog.rewolf.pl/blog/?p=573 #pragma pack(push) #pragma pack(1) template <class T> struct LIST_ENTRY_T { T Flink; T Blink; }; template <class T> struct UNICODE_STRING_T { union { struct { WORD Length; WORD MaximumLength; }; T dummy; }; T _Buffer; }; template <class T, class NGF, int A> struct _PEB_T { union { struct { BYTE InheritedAddressSpace; BYTE ReadImageFileExecOptions; BYTE BeingDebugged; BYTE _SYSTEM_DEPENDENT_01; }; T dummy01; }; T Mutant; T ImageBaseAddress; T Ldr; T ProcessParameters; T SubSystemData; T ProcessHeap; T FastPebLock; T _SYSTEM_DEPENDENT_02; T _SYSTEM_DEPENDENT_03; T _SYSTEM_DEPENDENT_04; union { T KernelCallbackTable; T UserSharedInfoPtr; }; DWORD SystemReserved; DWORD _SYSTEM_DEPENDENT_05; T _SYSTEM_DEPENDENT_06; T TlsExpansionCounter; T TlsBitmap; DWORD TlsBitmapBits[2]; T ReadOnlySharedMemoryBase; T _SYSTEM_DEPENDENT_07; T ReadOnlyStaticServerData; T AnsiCodePageData; T OemCodePageData; T UnicodeCaseTableData; DWORD NumberOfProcessors; union { DWORD NtGlobalFlag; NGF dummy02; }; LARGE_INTEGER CriticalSectionTimeout; T HeapSegmentReserve; T HeapSegmentCommit; T HeapDeCommitTotalFreeThreshold; T HeapDeCommitFreeBlockThreshold; DWORD NumberOfHeaps; DWORD MaximumNumberOfHeaps; T ProcessHeaps; T GdiSharedHandleTable; T ProcessStarterHelper; T GdiDCAttributeList; T LoaderLock; DWORD OSMajorVersion; DWORD OSMinorVersion; WORD OSBuildNumber; WORD OSCSDVersion; DWORD OSPlatformId; DWORD ImageSubsystem; DWORD ImageSubsystemMajorVersion; T ImageSubsystemMinorVersion; union { T ImageProcessAffinityMask; T ActiveProcessAffinityMask; }; T GdiHandleBuffer[A]; T PostProcessInitRoutine; T TlsExpansionBitmap; DWORD TlsExpansionBitmapBits[32]; T SessionId; ULARGE_INTEGER AppCompatFlags; ULARGE_INTEGER AppCompatFlagsUser; T pShimData; T AppCompatInfo; UNICODE_STRING_T<T> CSDVersion; T ActivationContextData; T ProcessAssemblyStorageMap; T SystemDefaultActivationContextData; T SystemAssemblyStorageMap; T MinimumStackCommit; }; typedef _PEB_T<DWORD, DWORD64, 34> PEB32; typedef _PEB_T<DWORD64, DWORD, 30> PEB64; #pragma pack(pop)
      
      







PEBは次のようにして取得できます。



 //  intrinsics ,    12     64  . //  PEB -      . #if defined _M_IX86 int offset = 0x30; DWORD peb __readfsdword(PEB) //mov eax, fs:[0x30] #elif defined _M_X64 // 64  windows   GS    PEB  GS:[0x60] int offset = 0x60; DWORD64 peb =__readgsqword(PEB); //mov rax, gs:[0x60]
      
      





kernel32ベースとGetProcAddressアドレスの取得:



 //64, ,     xp x64 sp2   win 8. typedef FARPROC (WINAPI * GetProcAddress_t) (HMODULE, const char *); struct LDR_MODULE { LIST_ENTRY e[3]; HMODULE base; void *entry; UINT size; UNICODE_STRING dllPath; UNICODE_STRING dllname; }; int offset = 0x60; int ModuleList = 0x18; int ModuleListFlink = 0x18; int KernelBaseAddr = 0x10; INT_PTR peb =__readgsqword(offset); INT_PTR mdllist=*(INT_PTR*)(peb+ ModuleList); INT_PTR mlink =*(INT_PTR*)(mdllist+ ModuleListFlink); INT_PTR krnbase=*(INT_PTR*)(mlink+ KernelBaseAddr); LDR_MODULE *mdl=(LDR_MODULE*)mlink; do { mdl=(LDR_MODULE*)mdl->e[0].Flink; if(mdl->base!=NULL) { if(!lstrcmpiW(mdl->dllname.Buffer,L"kernel32.dll")) //       { break; } } } while (mlink!=(INT_PTR)mdl); kernel32base = (HMODULE)mdl->base; ULONG_PTR base = (ULONG_PTR) kernel32base; IMAGE_NT_HEADERS * pe = PIMAGE_NT_HEADERS(base + PIMAGE_DOS_HEADER(base)->e_lfanew); IMAGE_EXPORT_DIRECTORY * exportDir = PIMAGE_EXPORT_DIRECTORY(base + pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); DWORD * namePtr = (DWORD *) (base + exportDir->AddressOfNames); //   . WORD * ordPtr = (WORD *) (base + exportDir->AddressOfNameOrdinals); //   . for(;_stricmp((const char *) (base +*namePtr), "GetProcAddress"); ++namePtr, ++ordPtr); DWORD funcRVA = *(DWORD *) (base + exportDir->AddressOfFunctions + *ordPtr * 4); auto myGetProcAddress = (GetProcAddress_t) (base + funcRVA); //  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を使用した操作(プロセスからの読み取り、変更、書き込み)は、単純なテストクラスの形式で配置されます



All Articles