导入模块数组
导入表是一个IMAGE_IMPORT_DESCRIPTOR数组, 长度是14h,并且以14h字节的“0”作为数组结尾。每个模块对应一个IMAGE_IMPORT_DESCRIPTOR结构。( WinNt.h)。
struct _IMAGE_IMPORT_DESCRIPTOR {
+0h union {
DWORD Characteristics;
DWORD OriginalFirstThunk; //IMAGE_THUNK_DATA数组的RVA,导入函数数组
} DUMMYUNIONNAME;
+4h DWORD TimeDateStamp; //一般为空
+8h DWORD ForwarderChain;
+ch DWORD Name; //导入模块名的RVA
+10h DWORD FirstThunk;
} IMAGE_IMPORT_DESCRIPTOR;
FirstThunk在磁盘中它指向的位置跟OriginalFirstThunk是一样的,同样是指向IMAGE_THUNK_DATA数组。如果PE文件被加载进内存,FirstThunk指向的IMAGE_THUNK_DATA数组中的Function保存的就是真实内存中的函数地址,OriginalFirstThunk指向的同样是IMAGE_THUNK_DATA数组,但是保存的并不是真实内存中的函数地址,而是IMAGE_IMPORT_BY_NAME数组的RVA,保存的是导入函数的函数名。
加载前:
加载后:
导入函数数组
长度4h,以4h字节的0作为数组结尾。
struct _IMAGE_THUNK_DATA32{
union {
DWORD ForwarderString //只有当IMAGE_IMPORT_DESCRIPTOR中的ForwarderChain有值时,它才有效
DWORD Function //被输入的函数的内存地址,只有在载入内存中时才有效
DWORD Ordinal //导入函数的序号,只有当IMAGE_THUNK_DATA的最高位是1的时候才有效
DWORD AddressOfData //当IMAGE_THUNK_DATA的最高位为0的时候有效,高位为0则指向IMAGE_IMPORT_BY_NAME结构体数组
}u1;
}IMAGE_THUNK_DATA32;
x64系统内结构为:
struct _IMAGE_THUNK_DATA64{
union {
ULONGLONG ForwarderString //只有当IMAGE_IMPORT_DESCRIPTOR中的ForwarderChain有值时,它才有效
ULONGLONGFunction //被输入的函数的内存地址,只有在载入内存中时才有效
ULONGLONGOrdinal //导入函数的序号,只有当IMAGE_THUNK_DATA的最高位是1的时候才有效
ULONGLONGAddressOfData //当IMAGE_THUNK_DATA的最高位为0的时候有效,高位为0则指向IMAGE_IMPORT_BY_NAME结构体数组
}u1;
}IMAGE_THUNK_DATA64;
函数名数组
struct _IMAGE_IMPORT_BY_NAME {
WORD Hint; //函数在所在的dll的输出表中的序号
BYTE Name[1]; //要输入的函数的函数名
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
———————————————————————————————————————————
欢迎关注我的微博:大雄_RE。专注软件逆向,分享最新的好文章、好工具,追踪行业大佬的研究成果。