阅读 LdrInitializeThunk

参考:

http://blog.csdn.net/hw_henry2008/article/details/6568255

Windows 的 DLL 装入(除 ntdll.dll 外)和连接是通过 ntdll.dll 中的一个函数LdrInitializeThunk()实现的.

在进入这个函数之前,目标 EXE 映像已经被映射到当前进程的用户空间,系统 DLL ntdll.dll 的映像也已经被映射, 但是并没有在 EXE 映像与 ntdll.dll 映像之间建立连接(实际上EXE 映像未必就直接调用 ntdll.dll 中的函数)。、

LdrInitializeThunk()是 ntdll.dll 中不经连接就可进入的函数,实质上就是 ntdll.dll 的入口。除 ntdll.dll 以外,别的 DLL 都还没有被装入(映射)。此外,当前进程(除内核中的“进程控制块”EPROCESS 等数据结构外)在用户空间已经有了一个“进程环境块”PEB,以及该进程的第一个“线程环境块”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);            //进程环境块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 */ //创建一个堆、 及其第一个区块,其初始的大小来自映像头部的建议值,其中 SizeOfHeapReserve 是估计的最大值,SizeOfHeapCommit是初始值,这是在编译/连接时确定的。 RtlInitializeHeapManager(); Peb->ProcessHeap = RtlCreateHeap(HEAP_GROWABLE, NULL, NTHeaders->OptionalHeader.SizeOfHeapReserve, NTHeaders->OptionalHeader.SizeOfHeapCommit, NULL, NULL); /* create loader information */ //PEB 中的 ProcessHeap 字段指向本进程用户空间可动态分配的内存区块“堆”
Peb->Ldr = (PPEB_LDR_DATA)RtlAllocateHeap (Peb->ProcessHeap,0,sizeof(PEB_LDR_DATA));. . . . . . 
 
 /*    PEB 中的另一个字段 Ldr是个 PEB_LDR_DATA 结构指针,所指向的数据结构用来为本进程维持三个“模块”队列、即 InLoadOrderModuleList、InMemoryOrderModuleList、InInitializationOrderModuleList。所谓“模块”就是 PE 格式的可执行映像,包括 EXE映像和 DLL 映像
两个模块队列的不同之处在于排列的次序,一个是按装入的先后,一个是按装入的位置(实际上目前ReactOS的代码中并未使用这个队列)。每当为本进程装入一个模块、即.exe 映像或 DLL 映像时,就要为其分配/创建一个LDR_MODULE 数据结构,并将其挂入 InLoadOrderModuleList。然后,完成对这个模块的动态连接以后,就把它挂入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模块的装入(如果尚未装入的话)和连接。如前所述,这个函数递归地施行于所有的模块,直至最底层的“叶节点”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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/491783.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

反对量子计算的理由

来源&#xff1a; 悦智网量子计算如今十分流行。几乎每天都有新闻媒体发布相关新闻。其实人类研究量子计算已经长达几十年&#xff0c;却未得出任何实用的结果&#xff0c;大多数评论员都忘记或者掩饰了这一事实。 IBM指出量子计算机能够“使很多学科领域取得突破性进展&#x…

吴恩达《机器学习》学习笔记一——初识机器学习

吴恩达《机器学习》学习笔记一一、 什么是机器学习&#xff1f;二、监督学习三、无监督学习初识机器学习这是个人学习吴恩达《机器学习》课程的一些笔记&#xff0c;供自己和大家学习提升。第一篇内容较少&#xff0c;日后继续加油。课程链接&#xff1a;https://www.bilibili.…

Python存储生成的决策树——pickle模块

假设通过训练样本生成的决策树为&#xff1a; {no surfacing: {0: no, 1: {flippers: {0: no, 1: yes}}}} 利用pickle模块可以存储和加载该决策树 tree {no surfacing: {0: no, 1: {flippers: {0: no, 1: yes}}}}def storeTree(inputTree, filename):import picklefw open…

让引擎不再是你的唯一,对百度再见

信息的传播是人的本性&#xff0c;特别是&#xff0c;对于自己的喜恶事事务。华斯康技术已经做了一项调查&#xff0c;在空调、身体、洗发水、房屋及其他产品的购买过程&#xff0c;分别为&#xff0c;53%、49%、35%和32%消费者&#xff0c;新产品信息。而且分别有35%、28%、15…

院士张钹:AI奇迹短期难再现 深度学习技术潜力已近天花板

来源&#xff1a;软件定义世界&#xff08;SDX&#xff09;在Alphago与韩国围棋选手李世石对战获胜三年过后&#xff0c;一些迹象逐渐显现&#xff0c;张钹院士认为到了一个合适的时点&#xff0c;并接受了此次的专访。张钹&#xff0c;计算机科学与技术专家&#xff0c;俄罗斯…

Python获得某个范围的的随机整数

numpy.random.randint(low, highNone, sizeNone, dtypel) 产生[low~high)范围内的整数&#xff0c;不包括high import numpy as npa np.random.randint(0, 2, 10) print(a) # [0 0 1 1 0 0 1 0 0 0]

吴恩达《机器学习》学习笔记二——单变量线性回归

吴恩达《机器学习》学习笔记二——单变量线性回归一、 模型描述二、 代价函数1.代价函数和目标函数的引出2.代价函数的理解&#xff08;单变量&#xff09;3.代价函数的理解&#xff08;两个参数&#xff09;三、 梯度下降——求解最优参数1.梯度下降的步骤2.梯度下降的数学表达…

吴恩达《机器学习》学习笔记三——多变量线性回归

吴恩达《机器学习》学习笔记三——多变量线性回归一、 多元线性回归问题介绍1.一些定义2.假设函数二、 多元梯度下降法1. 梯度下降法实用技巧&#xff1a;特征缩放2. 梯度下降法的学习率三、 特征选择与多项式回归四、 正规方程法1. 一些定义2. 正规方程解的公式3. 梯度下降法和…

五大核心构成的AIoT,正在遭遇三大挑战,两条突破口外还有什么?

来源&#xff1a;物联网智库随着IoT与AI逐步走向融合&#xff0c;AIoT正将以全新的方式改变人们的生活。一、新业务需求近年来&#xff0c;物联网呈现突飞猛进的发展态势。根据中商情报网的数据&#xff0c;2018年全球物联网设备已经达到70亿台&#xff1b;到2020年&#xff0c…

机器学习中防止过拟合的方法总结

来自机器学习成长之路公众号 在对模型进行训练时&#xff0c;有可能遇到训练数据不够&#xff0c;即训练数据无法对整个数据的分布进行估计的时候&#xff0c;或者在对模型进行过度训练&#xff08;overtraining&#xff09;时&#xff0c;常常会导致模型的过拟合&#xff08;…

iOS:面向对象的思想使用sqlite数据库

SQLite支持的常见数据类型如下所示。–INTEGER 有符号的整数类型–REAL 浮点类型–TEXT 字符串类型,采用UTF-8和UTF-16字符编码–BLOB 二进制大对象类型,能够存放任何二进制数据(C语言中)使用步骤&#xff1a;1.新建项目时,先导入系统框架(C语言). &#xff08;libsqlite3&…

吴恩达《机器学习》学习笔记四——单变量线性回归(梯度下降法)代码

吴恩达《机器学习》学习笔记四——单变量线性回归&#xff08;梯度下降法&#xff09;代码一、问题介绍二、解决过程及代码讲解三、函数解释1. pandas.read_csv()函数2. DataFrame.head()函数3. Dataframe.insert()函数课程链接&#xff1a; https://www.bilibili.com/video/BV…

从IoT World 2019看全球IoT九大发展趋势

来源&#xff1a;全球物联网观察美国时间5月14日&#xff0c;IoT World2019在美国硅谷圣克拉拉会议中心举行&#xff0c;今年的主题是“工业与IOT的交互”&#xff0c;从大会主题演讲内容和现场产品展示来看&#xff0c;随着5G的商用和人工智能技术的大面积落地&#xff0c;IoT…

TensorFlow实现单隐层神经网络

这里使用MNIST数据集&#xff0c;MNIST数据集的下载地址http://yann.lecun.com/exdb/mnist/ from tensorflow.examples.tutorials.mnist import input_data import tensorflow as tf mnist input_data.read_data_sets(r"D:\PycharmProjects\tensorflow\MNIST_data"…

美国一箭投放60颗卫星 马斯克组互联网“星链”

来源&#xff1a;新华网美国太空探索公司当地时间23日晚在美国佛罗里达州一处空军基地发射火箭&#xff0c;将60颗小卫星送入近地轨道。这标志着企业家埃隆马斯克组建互联网卫星群的“星链”项目迈出实质性一步&#xff0c;抢在电子商务巨头亚马逊公司创始人杰夫贝索斯的“柯伊…

Ubuntu 中Mysql 操作

一、mysql服务操作 0、查看数据库版本 sql-> status; 1、net start mysql //启动mysql服务 2、net stop mysql //停止mysql服务  3、mysql -h主机地址 -u用户名 &#xff0d;p用户密码 //进入mysql数据库 4、quit //退出mysql操作 5、mysqladmin -u用户名 -p旧密码 passwor…

吴恩达《机器学习》学习笔记五——逻辑回归

吴恩达《机器学习》学习笔记五——逻辑回归一、 分类&#xff08;classification&#xff09;1.定义2.阈值二、 逻辑&#xff08;logistic&#xff09;回归假设函数1.假设的表达式2.假设表达式的意义3.决策界限三、 代价函数1.平方误差函数的问题2.logistic回归的代价函数四、梯…

协方差与相关系数

定义&#xff1a; 协方差用于衡量两个变量的总体误差。而方差是协方差的一种特殊情况&#xff0c;即当两个变量是相同的情况。 期望值分别为E[X]与E[Y]的两个实随机变量X与Y之间的协方差Cov(X,Y)定义为&#xff1a; 如果两个变量的变化趋势一致&#xff0c;也就是说如果其中一…

吴恩达《机器学习》学习笔记六——过拟合与正则化

吴恩达《机器学习》学习笔记六——过拟合与正则化一、 过拟合问题1.线性回归过拟合问题2.逻辑回归过拟合问题3.过拟合的解决二、 正则化后的代价函数1.正则化思想2.实际使用的正则化三、 正则化的线性回归1.梯度下降的情况2.正规方程的情况四、 正则化的逻辑回归1.梯度下降的情…

Swift - 数组排序方法(附样例)

下面通过一个样例演示如何对数组元素进行排序。数组内为自定义用户对象&#xff0c;最终要实现按用户名排序&#xff0c;数据如下&#xff1a; 1234var userList [UserInfo]()userList.append(UserInfo(name: "张三", phone: "4234"))userList.append(Use…