阅读 LdrInitializeThunk
生活随笔
收集整理的這篇文章主要介紹了
阅读 LdrInitializeThunk
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
參考:
http://blog.csdn.net/hw_henry2008/article/details/6568255
Windows 的 DLL 裝入(除 ntdll.dll 外)和連接是通過 ntdll.dll 中的一個函數LdrInitializeThunk()實現的.
在進入這個函數之前,目標 EXE 映像已經被映射到當前進程的用戶空間,系統(tǒng) DLL ntdll.dll 的映像也已經被映射, 但是并沒有在 EXE 映像與 ntdll.dll 映像之間建立連接(實際上EXE 映像未必就直接調用 ntdll.dll 中的函數)。、
LdrInitializeThunk()是 ntdll.dll 中不經連接就可進入的函數,實質上就是 ntdll.dll 的入口。除 ntdll.dll 以外,別的 DLL 都還沒有被裝入(映射)。此外,當前進程(除內核中的“進程控制塊”EPROCESS 等數據結構外)在用戶空間已經有了一個“進程環(huán)境塊”PEB,以及該進程的第一個“線程環(huán)境塊”TEB。這就是進入 __true_LdrInitializeThunk()前的“當前形勢”。
VOID STDCALL __true_LdrInitializeThunk (ULONG Unknown1, ULONG Unknown2,ULONG Unknown3, ULONG Unknown4) {. . . . . .DPRINT("LdrInitializeThunk()/n");if (NtCurrentPeb()->Ldr == NULL || NtCurrentPeb()->Ldr->Initialized == FALSE){ Peb = (PPEB)(PEB_BASE); //進程環(huán)境塊DPRINT("Peb %x/n", Peb); ImageBase = Peb->ImageBaseAddress; //EXE 映像在用戶空間的起點 . . . ./* Initialize NLS data * //語言本地化有關RtlInitNlsTables (Peb->AnsiCodePageData, Peb->OemCodePageData,Peb->UnicodeCaseTableData, &NlsTable);RtlResetRtlTranslations (&NlsTable);NTHeaders = (PIMAGE_NT_HEADERS)(ImageBase + PEDosHeader->e_lfanew);. . . . . ./* create process heap */ //創(chuàng)建一個堆、 及其第一個區(qū)塊,其初始的大小來自映像頭部的建議值,其中 SizeOfHeapReserve 是估計的最大值,SizeOfHeapCommit是初始值,這是在編譯/連接時確定的。 RtlInitializeHeapManager(); Peb->ProcessHeap = RtlCreateHeap(HEAP_GROWABLE, NULL, NTHeaders->OptionalHeader.SizeOfHeapReserve, NTHeaders->OptionalHeader.SizeOfHeapCommit, NULL, NULL); /* create loader information */ //PEB 中的 ProcessHeap 字段指向本進程用戶空間可動態(tài)分配的內存區(qū)塊“堆”
Peb->Ldr = (PPEB_LDR_DATA)RtlAllocateHeap (Peb->ProcessHeap,0,sizeof(PEB_LDR_DATA));. . . . . .
/* PEB 中的另一個字段 Ldr是個 PEB_LDR_DATA 結構指針,所指向的數據結構用來為本進程維持三個“模塊”隊列、即 InLoadOrderModuleList、InMemoryOrderModuleList、InInitializationOrderModuleList。所謂“模塊”就是 PE 格式的可執(zhí)行映像,包括 EXE映像和 DLL 映像 兩個模塊隊列的不同之處在于排列的次序,一個是按裝入的先后,一個是按裝入的位置(實際上目前ReactOS的代碼中并未使用這個隊列)。每當為本進程裝入一個模塊、即.exe 映像或 DLL 映像時,就要為其分配/創(chuàng)建一個LDR_MODULE 數據結構,并將其掛入 InLoadOrderModuleList。然后,完成對這個模塊的動態(tài)連接以后,就把它掛入InInitializationOrderModuleList 隊列.LDR_MODULE 數據結構中有三個隊列頭,因而可以同時掛在三個隊列中。
Peb->Ldr->Length = sizeof(PEB_LDR_DATA);Peb->Ldr->Initialized = FALSE;Peb->Ldr->SsHandle = NULL;InitializeListHead(&Peb->Ldr->InLoadOrderModuleList);InitializeListHead(&Peb->Ldr->InMemoryOrderModuleList); InitializeListHead(&Peb->Ldr->InInitializationOrderModuleList); . . . . . . /* add entry for ntdll */ NtModule = (PLDR_MODULE)RtlAllocateHeap (Peb->ProcessHeap, 0, sizeof(LDR_MODULE)); . . . . . . InsertTailList(&Peb->Ldr->InLoadOrderModuleList, &NtModule->InLoadOrderModuleList); InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, &NtModule->InInitializationOrderModuleList); . . . . . . /* add entry for executable (becomes first list entry) */ ExeModule = (PLDR_MODULE)RtlAllocateHeap (Peb->ProcessHeap, 0, sizeof(LDR_MODULE)); . . . . . . InsertHeadList(&Peb->Ldr->InLoadOrderModuleList, &ExeModule->InLoadOrderModuleList); . . . . . .
/*當 CPU從 LdrPEStartup()返回時,EXE 對象需要直接或間接引入的所有 DLL 均已映射到用戶空間并已完成連接,對 EXE 模塊的“啟動” 、即初始化也已完成。注意在調用 LdrPEStartup()時的參數 ImageBase 是目標 EXE 映像在用戶空間的位置EntryPoint = LdrPEStartup((PVOID)ImageBase, NULL, NULL, NULL);. . . . . .}
/* attach the thread */RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock); //目的是調用各個 DLL 的初始化過程,以及對 TLS、即“線程本地存儲(Thread Local Storage)”的初始化 //TLS:有時候又確實需要讓每個線程都對于同一個全局變量有一份自己的拷貝,TLS就是為此而設的 LdrpAttachThread(); RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock); }
?
//注意在調用 LdrPEStartup()時的參數 ImageBase 是目標 EXE 映像在用戶空間的位置 PEPFUNC LdrPEStartup (PVOID ImageBase, HANDLE SectionHandle,PLDR_MODULE* Module, PWSTR FullDosName) {//PE 映像的 NtHeader 中有個指針,指向一個 OptionalHeader。說是“Optional”,實際上卻是關鍵性的。在 //OptionalHeader中有個字段 ImageBase,是具體映像建議、或者說希望被裝入的地址 . . . . . .DosHeader = (PIMAGE_DOS_HEADER) ImageBase;NTHeaders = (PIMAGE_NT_HEADERS) (ImageBase + DosHeader->e_lfanew);/** If the base address is different from the* one the DLL is actually loaded, perform any* relocation.*/if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase){DPRINT("LDR: Performing relocations/n");//ImageBase 是目標 EXE 映像在用戶空間的位置Status = LdrPerformRelocations(NTHeaders, ImageBase);. . . . . .}if (Module != NULL){*Module = LdrAddModuleEntry(ImageBase, NTHeaders, FullDosName);(*Module)->SectionHandle = SectionHandle;}else{Module = &tmpModule;Status = LdrFindEntryForAddress(ImageBase, Module);. . . . . .}. . . . . ./** If the DLL's imports symbols from other* modules, fixup the imported calls entry points.*/ //它所處理的就是當前模塊所需DLL模塊的裝入(如果尚未裝入的話)和連接。如前所述,這個函數遞歸地施行于所有的模塊,直至最底層的“葉節(jié)點”ntdll.dll為止。DPRINT("About to fixup imports/n");Status = LdrFixupImports(NULL, *Module);if (!NT_SUCCESS(Status)){DPRINT1("LdrFixupImports() failed for %wZ/n", &(*Module)->BaseDllName);return NULL;}DPRINT("Fixup done/n");. . . . . .Status = LdrpInitializeTlsForProccess();. . . . . ./** Compute the DLL's entry point's address.*/. . . . . .if (NTHeaders->OptionalHeader.AddressOfEntryPoint != 0){EntryPoint = (PEPFUNC) (ImageBase + NTHeaders->OptionalHeader.AddressOfEntryPoint);}DPRINT("LdrPEStartup() = %x/n",EntryPoint);return EntryPoint; }?
//調用關系[__true_LdrInitializeThunk > LdrPEStartup() > LdrPerformRelocations()] typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size; } IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;//每個 IMAGE_BASE_RELOCATION 數據結構代表著一個“重定位塊” ,每個重定位塊的(容器)大小是兩個頁面(8KB),而 SizeOfBlock 則說明具體重定位塊的實際大小。這實際的大小中包括了這 IMAGE_BASE_RELOCATION數據結構本身。 typedef struct _IMAGE_BASE_RELOCATION { DWORD VirtualAddress; DWORD SizeOfBlock; } IMAGE_BASE_RELOCATION,*PIMAGE_BASE_RELOCATION;static NTSTATUS LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders, PVOID ImageBase) { . . . . . . //PE 映像的 OptionalHeader 中有個大小為 16 的數組 DataDirectory[],其元素都是“數據目錄” 、即IMAGE_DATA_DIRECTORY 數據結構:其中之一(下標為 5)就是“重定位目錄” ,這是一個IMAGE_BASE_RELOCATION結構數組。 RelocationDDir =&NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; . . . . . .ProtectSize = PAGE_SIZE; //所謂重定位,就是計算出實際裝入地址與建議裝入地址間的位移 Delta,然后調整每個重定位塊中的每一個重定位項、即指針,具體就是在指針上加 DeltaDelta = (ULONG_PTR)ImageBase - NTHeaders->OptionalHeader.ImageBase; //IMAGE_BASE_RELOCATION結構數組 RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)ImageBase + RelocationDDir->VirtualAddress); RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)ImageBase + RelocationDDir->VirtualAddress + RelocationDDir->Size);while (RelocationDir < RelocationEnd && RelocationDir->SizeOfBlock > 0){Count = (RelocationDir->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);Page = ImageBase + RelocationDir->VirtualAddress;TypeOffset = (PUSHORT)(RelocationDir + 1);/* Unprotect the page(s) we're about to relocate. */ProtectPage = Page;Status = NtProtectVirtualMemory(NtCurrentProcess(), &ProtectPage,&ProtectSize, PAGE_READWRITE, &OldProtect);. . . . . .if (RelocationDir->VirtualAddress + PAGE_SIZE < NTHeaders->OptionalHeader.SizeOfImage){ProtectPage2 = ProtectPage + PAGE_SIZE;Status = NtProtectVirtualMemory(NtCurrentProcess(), &ProtectPage2,&ProtectSize, PAGE_READWRITE, &OldProtect2);. . . . . .}else{ProtectPage2 = NULL;} //具體的指針調整是由 LdrProcessRelocationBlock() 完成的,此前和此后的NtProtectVirtualMemory()只是為了先去除這些指針所在頁面的寫保護,而事后加以恢復。RelocationDir = LdrProcessRelocationBlock(Page, Count, TypeOffset, Delta);. . . . . ./* Restore old page protection. */NtProtectVirtualMemory(NtCurrentProcess(),&ProtectPage,&ProtectSize, OldProtect, &OldProtect);if (ProtectPage2 != NULL){NtProtectVirtualMemory(NtCurrentProcess(), &ProtectPage2,&ProtectSize, OldProtect2, &OldProtect2);}}return STATUS_SUCCESS; }?
轉載于:https://www.cnblogs.com/predator-wang/p/4819012.html
總結
以上是生活随笔為你收集整理的阅读 LdrInitializeThunk的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 问题解决:使用angularjs、ion
- 下一篇: 创建加密应用程序