使用16进制编辑器,在PE文件种定位到导入表的过程。
1. 前64字节MZ文件头,最后的4个字节是PE文件头的位置。
2. 找到PE文件头。
3. PE文件头第24字节偏移处是可选头。
4. 可选头0x70偏移处是IMAGE_DATA_DIRECTORY数组
5. 该数组长64字节,第二个元素为导入表的IMAGE_DATA_DIRECTORY
6. 导入表的IMAGE_DATA_DIRECTORY的前32位是导入表的RVA
7. 查节表确定导入表在哪个节,然后利用节表获得导入表的文件偏移
8. 定位到导入表
9. 导入表为一个IMAGE_IMPORT_DESCRIPTOR数组,每个被导入的文件对应一项,定义如下:
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
DWORD OriginalFirstThunk;
DWORD TimeDateStamp;
DWORD ForwarderChain;
DWORD Name;
DWORD FirstThunk;
}IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR;
成员含义如下:
OriginalFirstThunk
它指向first thunk,IMAGE_THUNK_DATA,该thunk拥有Hint和Function name的地址。
TimeDateStamp
如果那里有绑定的话它包含时间/数据戳(time/data stamp)。如果它是0,就没有绑定在被导入的DLL中发生。在最近,它被设置为0xFFFFFFFF以表示绑定发生。
ForwarderChain
在老版的绑定中,它引用API的第一个forwarder chain(传递器链表)。它可被设置为0xFFFFFFFF以代表没有forwarder。
Name
它表示DLL 名称的相对虚地址(译注:相对一个用null作为结束符的ASCII字符串的一个RVA,该字符串是该导入DLL文件的名称,如:KERNEL32.DLL)。
FirstThunk
它包含由IMAGE_THUNK_DATA定义的 first thunk数组的虚地址,通过loader用函数虚地址初始化thunk。在Orignal First Thunk缺席下,它指向first thunk:Hints和The Function names的thunks。
10. 从Name成员可以得到被导入文件名的RVA,利用节表可以获得文件偏移,可以看到被导入文件的名称。
11. 从OriginalFirstThunk可以得到IMAGE_THUNK_DATA结构数组的RVA,利用节表得到其文件偏移。IMAGE_THUNK_DATA结构定义为:
typedef struct _IMAGE_THUNK_DATA32 {
PIMAGE_IMPORT_BY_NAME AddressOfData;
} IMAGE_THUNK_DATA32;
12. 从中得到IMAGE_IMPORT_BY_NAME结构的RVA,利用节表得到文件偏移。IMAGE_IMPORT_BY_NAME结构定义为:
typedef struct _IMAGE_IMPORT_BY_NAME {
WORD Hint;
BYTE Name[1];
}IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
成员含义如下:
Hint
指示本函数在其所驻留DLL的引出表中的索引号。该域被PE装载器用来在DLL的引出表里快速查询函数。该值不是必须的,一些连接器将此值设为0。
Name1
含有引入函数的函数名。函数名是一个ASCIIZ字符串。注意这里虽然将Name1的大小定义成字节,其实它是可变尺寸域,只不过我们没有更好方法来表示结构中的可变尺 寸域。