目录
[INT表(INT-OriginalFirstThunk) 名称表](#INT表(INT-OriginalFirstThunk) 名称表)
[IAT表(IAT-FirstThunk ) 地址表](#IAT表(IAT-FirstThunk ) 地址表)
[导入表 作用与总体布局](#导入表 作用与总体布局)
[IMAGE_IMPORT_DESCRIPTOR 结构体](#IMAGE_IMPORT_DESCRIPTOR 结构体)

导入表作用
-
导入表(Import Directory)告诉加载器这个模块需要哪些外部 DLL 及哪些符号;
-
导出表(Export Directory)列出模块向外暴露的函数/变量和序号(ordinal),以供其他模块链接或运行时解析
-
导入表(Import Directory)告诉加载器这个模块需要哪些外部 DLL 及哪些符号(DLL);
-
导入表记录了外部的调用的DLL 记录了这个程序需要用到哪些外部DLL。

- 延迟加载 程序不需要在启动的时候加载DLL
定位导入表(工具定位)
-
第二个也就是数据目录项的第二个结构也就是导入表的结构。
-
这个结构又要转换成FOA找到真正的导入表。

导入表结构体
数据目录项目的第二个结构导入表结构
g_opHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;//导入表RVA
DWORD Size;//导入表大小
}
IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
RVA转换成FOA
-
输入RVA转换成FOA 这个位置就是我们导入表的结构
-
也就是内存模式转换成磁盘模式也就是需要从RVA转换FOA

导入表结构体
_IMAGE_IMPORT_DESCRIPTOR
-
DWORD OriginalFirstThunk; //RVA 指向名称表 INT
-
Name // RVA //指向DLL的名字
-
FirstThunk // RVA 地址表 ==== 占位符 IAT
//导入表的结构
//由于一个执行模块需要的外部函数通常是多个的,所以导入表是多份的。typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics; // 0 for terminating null import descriptor
DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
} DUMMYUNIONNAME;DWORD TimeDateStamp; // 0 DWORD ForwarderChain; // 0 DWORD Name; DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
INT表(INT-OriginalFirstThunk) 名称表
-
OriginalFirstThunk也就是这个字段指向的是这个结构体 ---> PIMAGE_THUNK_DATA
-
那么指向这个参数也就是4个字节一个单位
typedef PIMAGE_THUNK_DATA64 PIMAGE_THUNK_DATA;
typedef struct _IMAGE_THUNK_DATA32 {
union {
DWORD ForwarderString; // PBYTE 这个也就是四个字节
DWORD Function; // PDWORD
DWORD Ordinal;
DWORD AddressOfData; // PIMAGE_IMPORT_BY_NAME
} u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;
案例
unsigned char data[32] = { // INT表名称表
0x4B, 0x0C, 0x00, 0x80,
0xBB, 0x0C, 0x00, 0x80,
0x71, 0x11, 0x00, 0x80,
0x40, 0x0C, 0x00, 0x80,
0xBE, 0x0C, 0x00, 0x80,
0xA9, 0x0B, 0x00, 0x80,
0x09, 0x0C, 0x00, 0x80,
0xA0, 0x0B, 0x00, 0x80
};
IAT表(IAT**-FirstThunk**) 地址表
unsigned char data[32] = { // IAT表地址表
0x4B, 0x0C, 0x00, 0x80,
0xBB, 0x0C, 0x00, 0x80,
0x71, 0x11, 0x00, 0x80,
0x40, 0x0C, 0x00, 0x80,
0xBE, 0x0C, 0x00, 0x80,
0xA9, 0x0B, 0x00, 0x80,
0x09, 0x0C, 0x00, 0x80,
0xA0, 0x0B, 0x00, 0x80
};
导入表 作用与总体布局
-
导入表是一个
IMAGE_IMPORT_DESCRIPTOR数组(以全零项终止),每个元素对应一个被导入的 DLL。-
每个 descriptor 的关键字段包括 OriginalFirstThunk、Name、FirstThunk 等;
-
加载器通过这些信息去加载 DLL,并把实际函数地址写入到 FirstThunk 指向的位置(IAT,Import Address Table)。
-
简单说:磁盘上的"名字与签名" → 加载器在内存里把函数地址填到 IAT → 程序通过 IAT 调用外部函数。
-
IMAGE_IMPORT_DESCRIPTOR 结构体
OriginalFirstThunk(RVA)
-
指向 Import Lookup Table(ILT,又称 Import Name Table/INT)
-
它列出每个导入条目的 Hint/Name 或按序号导入的 ordinal。IL T 在文件加载前通常保存函数名信息。
Name(RVA)
-
指向被导入 DLL 的 ASCII 名称(如 "KERNEL32.dll")
-
加载器先根据这个名称加载目标模块。
FirstThunk(RVA)
- 指向 Import Address Table(IAT)。程序运行时通过 FirstThunk 对应的内存地址阵列直接调用函数;加载器把实际函数指针写到这里(从 ILT/lookup 得到地址并写入 IAT)。在磁盘映像中 IAT 初始通常与 ILT 相同,加载后被替换为实际地址。