Windows:PE格式之输入表

前文是 Windows:32位PE文件结构

数据目录表

位置:ImageNtHeaders->OptionalHeader->DataDirectory
描述:由NumberOfRvaAndSizesIMAGE_DATA_DIRECTORY结构体组成的数组
包含有:输入表、输出表、资源表、重定位表等数据目录项的RVA和大小

输入表、输出表又称导入表、导出表

在这里插入图片描述

输入表

输入函数

输入函数就是在程序中被调用,但是其代码不在程序中的函数,这些函数的代码位于DLL中。在调用输入函数的程序中,只保留了如函数名及其所在的DLL名等相关信息。对于磁盘上的PE文件来说,输入函数在内存中的地址是多少,这是无法知道的,只有PE文件被装载到内存之后,Windows装载器才将相关的DLL装入,并将调用了输入函数的指令和此函数的地址联系起来。

数据结构

输入表的数据结构是一个IMAGE_IMPORT_DESCRIPTOR结构体的数组,每个被链接到此PE文件的DLL都分别对应于一个IID结构体,整个数组以一个NULL的IID作为结束标志。

IID结构体的定义如下:
在这里插入图片描述

OriginalFirstThunk和FirstThunk

在这里插入图片描述
在这里插入图片描述

OriginalFirstThunk是一个DWORD类型(4B)的变量,实质是一个RVA值,指向一个名为INT(ImportNameTable,导入名称表)的结构。
FirstThunk同理,指向IAT(ImportAddressTable,导入地址表)结构。
IATINT都是IMAGE_THUNK_DATA结构体的数组,每一个IMAGE_THUNK_DATA结构体都定义了一个导入函数的信息,以一个空结构体作为数组结束标志。

IMAGE_THUNK_DATA定义如下:
在这里插入图片描述
它是一个union结构,共占用4B
IMAGE_THUNK_DATA最高位为1时,表示函数是以序号方式输入的,此时,低31位被看作是函数序号。
IMAGE_THUNK_DATA最高位为0时,表示函数以字符串型的函数名方式输入,此时,整个DWORD的值是一个RVA,指向一个IMAGE_IMPORT_BY_NAME结构。

IMAGE_IMPORT_BY_NAME结构体定义如下:
在这里插入图片描述
此结构体存放着输入函数的相关信息,Hint表示函数序号,Name字段定义了导入函数的名称字符串。

小总结

名称意义
IMAGE_DATA_DIRECTORY存放数据目录项(如导入表)的RVA和Size等信息的结构体
IMAGE_IMPORT_DESCRIPTOR每个此结构体都对应于一个被链接到此PE文件的DLL
OriginalFirstThunkDWORD型变量,实质是一个指针,指向导入名称表INT
FirstThunkDWORD型变量,实质是一个指针,指向导入地址表IAT
IMAGE_THUNK_DATAINT和IAT使用的结构体,每个此结构体都直接描述或间接指向了来源于DLL的一个导入函数
IMAGE_IMPORT_BY_NAME函数以字符串类型的函数名方式输入时,其IMAGE_THUNK_DATA指向一个此结构体,此结构体内存着函数序号和导入函数的名称字符串

导入地址表IAT

由上所述,有两个并行的指针数组同时指向IMAGE_IMPORT_BY_NAME结构,第一个是OriginalFirstThunk指向的导入名称表INT,第二个是FirstThunk指向的导入地址表IAT。
之所以有两个,其实是因为在PELoader装载PE文件到内存后,IAT中原本的IMAGE_THUNK_DATA将会被重写为导入函数的地址,如图:
在这里插入图片描述
装载过程简单叙述为:
PELoader首先搜索OriginalFirstThunk,然后迭代搜索其指向的INT中所有的IMAGE_THUNK_DATA,进而找到每个IMAGE_IMPORT_BY_NAME结构所指向的输入函数的名称或序号,然后获得输入函数的RVA,再用所有的函数RVA覆盖原来IAT中的IMAGE_THUNK_DATA。覆盖完成后,输入表中其余部分就不重要了,有IAT足以让程序正常运作。
在这里插入图片描述

实例演示

文件

#include <windows.h>
int main(){
    MessageBox(NULL, "hello", "world", MB_OK);
}

注意以32位方式编译
用LordPE打开
看到输入表的RVA是00006000H
在这里插入图片描述
查看节表,发现此RVA在.idata节
在这里插入图片描述
输入表的RVA相对于.idata节起始位置的偏移量为0,则此节的FileOffset00002400H即为输入表的FileOffset。

换成C32ASM打开PE文件,Ctrl+G跳到此位置,即为输入表的起始位置。
在这里插入图片描述

一个IID结构体是五个DWORD,即20B
此PE文件共有三个IID结构体和一个结束标志,如下

50 60 00 00 00 00 00 00 00 00 00 00 FC 64 00 00 18 61 00 00
A0 60 00 00 00 00 00 00 00 00 00 00 78 65 00 00 68 61 00 00
10 61 00 00 00 00 00 00 00 00 00 00 88 65 00 00 D8 61 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

以第一个IID为例
再来回顾一下其结构
在这里插入图片描述
找到其OriginalFirstThunk值为00006050HFirstThunk值为00006118H
注意是小端方式存储。
将RVA转FileOffset知
INT的FO:2450H
IAT的FO:2518H

先跟踪一下INT
INT的第一个IMAGE_THUNK_DATA如图为000061E0H
在这里插入图片描述
IMAGE_THUNK_DATA最高位为0时,表示函数以字符串型的函数名方式输入,此时,整个DWORD的值是一个RVA,指向一个IMAGE_IMPORT_BY_NAME结构。
将此RVA转FileOffset得25E0H,跟踪下去
在这里插入图片描述
此结构体内,前一个WORD为函数序号,图中为00D4H。然后是函数名,直到遇到一个0x00截止符结束,图中是44 65 6C 65 74 65 43 72 69 74 69 63 61 6C 53 65 63 74 69 6F 6E 00

然后看看IAT,其第一个IMAGE_THUNK_DATA也是61E0H,顺理成章,静态的文件中,INT和IAT指向的是同一个IMAGE_IMPORT_BY_NAME结构体数组
在这里插入图片描述

镜像

这个版本的LordPE在win10下无法显示进程,所以放到xp下做了
先运行此exe
在这里插入图片描述
然后打开LordPE,dump一下,实际相当于保存此exe被加载到内存后的状态
在这里插入图片描述
在这里插入图片描述
使用LordPE打开dump后的dumped_delete.exe,输入表RVA:6000H。
在这里插入图片描述转FileOffset还是6000H
在这里插入图片描述
C32ASM打开,跳到此处
在这里插入图片描述
第一个IID的FirstThunk6118H,则IAT的FO:6118H,跟进,这部分就是IAT了
在这里插入图片描述
与文件中的IAT相比
其内容不再是IMAGE_THUNK_DATA结构体数组,而是被覆盖为导入函数地址了。
用LordPE验证一下,完全符合
在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值