1、数据目录表第二个成员指向导入表 IMAGE_DATA_DIRECTORY[1] -> IMAGE_DIRECTORY_ENTRY_IMPORT。
2、导入表以一个IMAGE_IMPORT_DESCRIPTOR(IID)数组开始。并且一个DLL文件对应一个IID结构,最后以一个全0的IID结构作为结尾。有多少个IID就有多少个DLL被导入。
1 struct _IMAGE_IMPORT_DESCRIPTOR 2 { 3 0x00 union 4 { 5 0x00 DWORD Characteristics; 6 0x00 PIMAGE_THUNK_DATA OriginalFirstThunk; //INT导入名称表Rva 7 } u; 8 0x04 DWORD TimeDateStamp; 9 0x08 DWORD ForwarderChain; 10 0x0c DWORD Name; //DLL名称字符串指针Rva 11 0x10 PIMAGE_THUNK_DATA FirstThunk; //IAT导入地址表Rva 12 };
3、INT和IAT均指向一个IMAGE_THUNK_DATA 结构体数组,数组以一个全0元素结尾。每个IMAGE_THUNK_DATA 结构体都指向一个IMAGE_IMPORT_BY_NAME结构体。有多少个IMAGE_THUNK_DATA 结构体该DLL就有多少个函数被导入。
当IMAGE_THUNK_DATA 结构体最高位为1时,表示函数以序号导入,此时低31位被看成函数序号使用。
当IMAGE_THUNK_DATA 结构体最高位为0时,表示函数以名称导入,此时AddressOfData是一个指向IMAGE_IMPORT_BY_NAME结构体的Rva。
PE文件加载前:INT和IAT均指向不同的IMAGE_THUNK_DATA 结构体数组,但它们都保存着导入函数的序号和名称信息。
PE文件加载后:IAT指向导入函数的实际调动地址。
1 struct _IMAGE_THUNK_DATA 2 { 3 union 4 { 5 0x00 LPBYTE ForwarderString; 6 0x00 PDWORD Function; 7 0x00 DWORD Ordinal; //导入函数序号 8 0x00 PIMAGE_IMPORT_BY_NAME AddressOfData; //IMAGE_IMPORT_BY_NAME 结构Rva 9 } u1; 10 }; //占用4字节
1 struct _IMAGE_IMPORT_BY_NAME 2 { 3 0x00 WORD Hint; //1字节 4 0x02 BYTE Name[1]; //n字节 函数名称字符串 5 };