一个PE文件的导入表,简单说的说就是存放了其所调用的函数的地址和相关信息。
数据目录表的第1项(从0开始)就存放了导入表
导入表的结构
struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics;
DWORD OriginalFirstThunk;
} DUMMYUNIONNAME;
DWORD TimeDateStamp;
DWORD ForwarderChain;
DWORD Name;
DWORD FirstThunk;
} IMAGE_IMPORT_DESCRIPTOR;
其中最重要的三个参数
OriginalFirstThunk; //指向INT
Name; //导入的dll的名称
FirstThunk; //指向IAT
其中OriginalFirstThunk 和 FirstThunk 就是著名的双桥结构。在没有被加载时,两个变量指向的空间内容一样,结构为
struct _IMAGE_THUNK_DATA32{
union {
DWORD ForwarderString
DWORD Function ; //被输入的函数的内存地址
DWORD Ordinal ; //被输入的API的序数值
DWORD AddressOfData ; //高位为0则指向IMAGE_IMPORT_BY_NAME
}u1;
}IMAGE_THUNK_DATA32;
typedef struct _IMAGE_IMPORT_BY_NAME{
WORD Hint; //序号
BYTE NAME[1]; //函数名
}IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME;
双桥结构:
但是在PE加载的时候,双桥结构会断裂,IAT 会被PE加载器重写,PE加载器先搜索INT,PE加载器迭代搜索INT数组中的每个指针,找出 INT所指向的IMAGE_IMPORT_BY_NAME结构中的函数在内存中的真正的地址,并把它替代原来IAT中的值。此时IAT中存放的就是函数的真实地址。