TEB — структура которая используется для хранения информации о потоках в текущем процессе, каждый поток имеет свой TEB. Wow64 процессы в Windows имеют два Process Environment Blocks и два Thread Environment Blocks. TEB создается функцией MmCreateTeb, PEB создается функцией MmCreatePeb, если интересен процесс создания, то можно посмотреть исходники ReactOS, или взять WinDBG и исследовать самостоятельно.
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 PEB описывается следующим образом для 32 битного процесса:
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;
//автор структуры - 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, такие api функции как GetModuleHandleEx и EnumProcessModules, QueryFullProcessImageName не будут выдавать нужный результат, так как они вызывают ReadProcessMemory для чтения PEB. Кода много, поэтому манипуляции с PEB оформлены в виде простого тестового класса, который можно найти тут.
ссылка на оригинал статьи http://habrahabr.ru/post/187226/
Добавить комментарий