简述装载过程。

1.创建PDE,page directory entry,用来存放virtual memory <--> physical memory之间的映射关系

2.创建virtual memory跟可执行文件(.exe,.dll...)之间的映射关系,缺页的时候需要从文件里那数据放到内存里的

3.对CPU的PC寄存器设置为可执行文件入口地址

这样就ok了,后续用到什么memory,MMU会分配/释放相应的物理内存,并填写PTE(page directory entry).

装载过程中一个重要的步骤是配置IAT(Import Address Table).

PE文件Optional Header中有两个Directory Entry特别重要,IMAGE_DIRECTORY_ENTRY_EXPORT,IMAGE_DIRECTORY_ENTRY_IMPORT.

/************************* To get the exported API's RVA *******************************/

对于Export Entry,它提供了这个module想要export的API的RVA,我们可能希望知道怎么去拿到这些API对应的RVA.
1. Get RVA of IMAGE_DIRECTORY_ENTRY_EXPORT from optional header

1 struct data_directory
2  { 
3     long VirtualAddress;
4     long Size;
5  }

2. Parse the Export based on this structure

 1 struct IMAGE_EXPORT_DIRECTORY {
 2     DWORD Characteristics;
 3     DWORD TimeDateStamp;
 4     WORD MajorVersion;
 5     WORD MinorVersion;
 6     DWORD Name;
 7     DWORD Base;
 8     DWORD NumberOfFunctions;
 9     DWORD NumberOfNames;
10     DWORD *AddressOfFunctions;
11     DWORD *AddressOfNames;
12     DWORD *AddressOfNameOrdinals;
13 }

3. Get NumberOfNames, AddressOfNames, AddressOfNameOrdinals, AddressOfFunctions
compare function "xxxx" with *AddressOfNames, to get its index(hint).
Based on the index(hint) to get its ordinals (AddressOfNameOrdinals[hint])

based on the ordinals to get the function's address(AddressOfFunctions[ordinals]).

/********************************************************/
对于 Import Entry,我们可能会想知道怎么去拿到Imported API的地址。
1. Get RVA of IMAGE_DIRECTORY_ENTRY_IMPORT from optional header

1 struct data_directory
2  { 
3     long VirtualAddress;
4     long Size;
5  }

2. Parse the import array structure, it is an array ended by an Zero-Entry

1 struct IMAGE_IMPORT_DESCRIPTOR {
2     DWORD *OriginalFirstThunk;
3     DWORD TimeDateStamp;
4     DWORD ForwarderChain;
5     DWORD Name; // module name
6     DWORD *FirstThunk;
7 }

每个结构都会对应一个library,compare if name is the module we want.

3. 得到我们想了解的library对应的内容之后,有两个结构的内容特别重要*OriginalFirstThunk,*FirstThunk。

在loader填IAT之前,OriginalFirstThunk跟FirstThunk的内容是一样的,都是一个array ended by an Zero-Element.

每个值都对应一个结构体

1 struct IMAGE_IMPORT_BY_NAME {
2         short Hint;
3         char Name[1];
4 }

name是函数的名字,hint是这个name在library的Export Entry中很有可能的hint值,用来优化加载时间.如果hint对应的api name跟我们想要的不一样,那么就需要二分遍历它的name array。

4. Loader根据Name,Hint去对应的Library中可以拿到这个API相应的address.

    Loader会把这个address填写到FirstThunk指向的那个数组,于是,从此之后FirstThunk的内容就跟OriginalFirstThunk不一样了

5.  以后这个Module想要call相应的API的时候,就是个相对寻址, call ptr [FirstThunk]。

    所以FirstThunk指向的数组最终保存了import API的virtual address. 

如果想要做个hook在Module访问其他module的API时,只要在loader之后修改FirstThunk中的数据就能达到目的了:)

原文地址:https://www.cnblogs.com/zzSoftware/p/3414614.html