PE文件结构
导入表

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics; // 0 for terminating null import descriptor
DWORD OriginalFirstThunk; // RVA 指向 INT (PIMAGE_THUNK_DATA结构数组)
} DUMMYUNIONNAME;
DWORD TimeDateStamp; // 0 if not bound,
// -1 if bound, and real date\time stamp
// in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
// O.W. date/time stamp of DLL bound to (Old BIND)
DWORD ForwarderChain; // -1 if no forwarders
DWORD Name; //RVA指向dll名字,以0结尾
DWORD FirstThunk; // RVA 指向 IAT (PIMAGE_THUNK_DATA结构数组)
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
typedef struct _IMAGE_IMPORT_BY_NAME {
WORD Hint; //可能为空,编译器决定,如果不为空,是函数在导出表的索引
BYTE Name[1]; //函数名称,以0结尾
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
导入表是一个数组,每一个元素都是一个IMAGE_IMPORT_DESCRIPTOR(最后一个元素为空来表示数组的结束,后面的数组都是这样的),每一个IMAGE_IMPORT_DESCRIPTOR都代表了一个dll,Name存放着dll名称的地址,OriginalFirstThunk存放着INT的地址,FirstThunk存放着IAT的地址。
INT也是一个数组,每一个元素都是一个ULONGLONG AddressOfData;,AddressOfData存放着IMAGE_IMPORT_BY_NAME的地址。
IAT也是一个数组,每一个元素都是一个ULONGLONG Function;,Function存放着导入函数的地址。
INT和IAT的元素是根据索引一一对应的
IAT填充
下面介绍在PE加载过程中操作系统如何对IAT进行填充
- 获取模块句柄
通过IMAGE_IMPORT_DESCRIPTOR的成员Name获取dll名称地址调用GetModuleHandle(dll函数名称),获取该dll模块句柄
- 获取函数地址
首先通过OriginalFirstThunk,找到INT,通过INT的元素AddressOfData找到IMAGE_IMPORT_BY_NAME,若IMAGE_IMPORT_BY_NAME.Name不为空,则通过调用GetProcAddress(IMAGE_IMPORT_BY_NAME.Name)获取该函数地址,若IMAGE_IMPORT_BY_NAME.Name为空,则通过调用GetProcAddress(IMAGE_IMPORT_BY_NAME.Hint)获取该函数地址
- 填充
IAT
通过INT的元素AddressOfData的索引,找到IAT中对应的元素Function,将获取到的函数地址填充到Function中

浙公网安备 33010602011771号