加载器读取一个PE文件的过程如下:
1. 先读入PE文件的DOS头,PE头和Section头。
2. 然后根据PE头里的ImageBase所定义的加载地址是否可用,如果已被其他模块占用,则重新分配一块空间。
3. 根据Section头部的信息,把文件的各个Section映射到分配的空间,并根据各个Section定义的数据来修改所映射的页的属性。
4. 如果文件被加载的地址不是ImageBase定义的地址,则重新修正ImageBase。
5. 根据PE文件的输入表加载所需要的DLL到进程空间。
6. 然后替换IAT表内的数据为实际调用函数的地址。
7. 根据PE头内的数据生成初始化的堆和栈。
8. 创建初始化线程,开始运行进程。
这里要提的是加载PE文件所需DLL的过程是建立在六个底层的API上。
LdrpCheckForLoadedDll:检查要加载的模块是否已经存在。
LdrpMapDll:映射模块和所需信息到内存。
LdrpWalkImportDescriptor:遍历模块的输入表来加载其所需的其他模块。
LdrpUpdateLoadCount:计数模块的使用次数。
LdrpRunInitializeRoutines:初始化模块。
LdrpClearLoadInProgress:清除某些标志,表明加载已经完成。