PE文件格式详解(五-2)――Improt Table(引入表)

现在我们知道如何找到引入表了。Data Directory数组第二项的VirtualAddress包含引入表地址。引入表实际上是一个 IMAGE_IMPORT_DESCRIPTOR 结构数组。每个结构包含PE文件引入函数的一个相关DLL的信息。比如,如果该PE文件从10个不同的DLL中引入函数,那么这个数组就有10个成员。该数组以一个全0的成员结尾。下面详细研究结构组成:

IMAGE_IMPORT_DESCRIPTOR STRUCT
union
    Characteristics dd ?
    OriginalFirstThunk dd ?
ends
TimeDateStamp dd ?
ForwarderChain dd ?
Name1 dd ?
FirstThunk dd ?
IMAGE_IMPORT_DESCRIPTOR ENDS

    结构第一项是一个union子结构。事实上,这个union子结构只是给 OriginalFirstThunk 增添了个别名,您也可以称其为"Characteristics"。 该成员项是指向一个指向一个DWORD 数组的RVA。数组里的每一个DWORD 事实上是一个IMAGE_THUNK_DATA union。那么,什么 IMAGE_THUNK_DATA又是什么呢? 每个IMAGE_THUNK_DATA union对应于一个输入函数,这个DWORD(即IMAGE_THUNK_DATA union)的内容视文件被加载与否(即:加载前后内容不同,原因后面会解释),以及函数被以名称输入或以序号输入而定(即:输入方式不同,内容不同)。以名称输入是比较共同的方式。当一个函数以序号输入,EXE 文件的IMAGE_THUNK_DATA DWORD 中的最高位(0x80000000)设立。例如,考虑一个IMAGE_THUNK_DATA,其值为0x80000112,放在GDI32.DLL 数组中。表示这IMAGE_THUNK_DATA 将输入GDI32.DLL 中的第112号输出(exported)函数。如果函数以名称输入,IMAGE_THUNK_DATA DWORD 就内含一个RVA(Relative Virtual Address),指向IMAGE_IMPORT_BY_NAME 结构,由于一个输入函数对应一个IMAGE_THUNK_DATA union,而当函数以名称输入的时候IMAGE_THUNK_DATA又指向一个IMAGE_IMPORT_BY_NAME 结构,所以此时一个输入函数对应一个IMAGE_IMPORT_BY_NAME 结构。现在让我们看看IMAGE_IMPORT_BY_NAME 结构里面有些什么东东,我们希望里面存有一个引入函数的相关信息。奥,原来它真的如我们所愿:

IMAGE_IMPORT_BY_NAME STRUCT
Hint dw ?
Name1 db ?
IMAGE_IMPORT_BY_NAME ENDS

    Hint 指示本函数在其所驻留DLL的引出表中的索引号。该域被PE装载器用来在DLL的引出表里快速查询函数。
Name1 含有引入函数的函数名。函数名是一个ASCIIZ字符串。现在请看这里: 假设程序中调用了N个输入函数,那么就对应着有N个 IMAGE_IMPORT_BY_NAME 结构,我们收集起这些结构的RVA 放在IMAGE_THUNK_DATA结构中组成一个数组,并以0结尾,然后再将此数组的RVA放入 OriginalFirstThunk。 这样一来我们就可以利用OriginalFirstThunk这条线把从某一个DLL中调用的函数全部給揪出来。

    奥,刚才我们被IMAGE_IMPORT_BY_NAME 结构给中断了一下,现在让我们返回IMAGE_IMPORT_DESCRIPTOR结构,继续看里面的其他域。为了和上面的讨论保持连贯性先让我们来看一下最后一个域FirstThunk,FirstThunk 与 OriginalFirstThunk 非常相似,也是一个RVA,它也是指向一个 IMAGE_THUNK_DATA 结构数组(当然这是另外一个IMAGE_THUNK_DATA 结构数组,不过这个IMAGE_THUNK_DATA结构数组和OriginalFirstThunk指向的IMAGE_THUNK_DATA结构数组内容是完全一样的)。好的让我们理顺一下:现在有几个 IMAGE_IMPORT_BY_NAME 结构,同时您又创建了两个结构数组,并同样存入指向那些 IMAGE_IMPORT_BY_NAME 结构的RVA,这样两个数组就包含相同数值了(可谓相当精确的复制啊)。最后您决定将第一个数组的RVA赋给 OriginalFirstThunk,第二个数组的RVA赋给 FirstThunk,这样一切都很清楚了。如果你对上面一堆的RVA和结构数组的关系感到头晕的话那么请往下看,或许下面这个图解能让你清醒一些:

OriginalFirstThunk

IMAGE_IMPORT_BY_NAME

FirstThunk

|

|

IMAGE_THUNK_DATA

IMAGE_THUNK_DATA

IMAGE_THUNK_DATA

IMAGE_THUNK_DATA

...

IMAGE_THUNK_DATA

--->

--->

--->

--->

--->

--->

Function 1

Function 2

Function 3

Function 4

...

Function n

<---

<---

<---

<---

<---

<---

IMAGE_THUNK_DATA

IMAGE_THUNK_DATA

IMAGE_THUNK_DATA

IMAGE_THUNK_DATA

...

IMAGE_THUNK_DATA

    现在您应该明白我的意思。不要被IMAGE_THUNK_DATA这个名字弄糊涂: 当以名字引入函数时,它仅是指向 IMAGE_IMPORT_BY_NAME 结构的RVA。 如果将 IMAGE_THUNK_DATA 字眼想象成RVA,就更容易明白了。OriginalFirstThunk 和 FirstThunk 所指向的这两个数组大小取决于PE文件从DLL中引入函数的数目。比如,如果PE文件从kernel32.dll中引入10个函数,那么IMAGE_IMPORT_DESCRIPTOR 结构的 Name1域包含指向字符串"kernel32.dll"的RVA,同时每个IMAGE_THUNK_DATA 数组有10个元素。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值