无论是在脱壳还是在PEDIY中,“输入表”这一概念总像阴魂一样缠绕在电脑屏幕前,令我等菜鸟彷徨叹息。遂于近日认真学习了一下PE格式,终于将此恶魔搞定。
  将实例PE.EXE载入LordPE中,依次点击“数据目录”,“输入表”旁的小点点,弹出以下窗口。我们勾选下面的"总是查看FirstThunk".

  


只见有两个dll:user32.dll和kernel32.dll以及各dll引出的诸函数.
可见每个dll有五个属性.
我们暂且只记住第一个dll的FirstThunk值如图:00002010,窗口下半部表明该值指向了名为DrawTextA的API函数.
我们用OD载入实例.下断 bpx DrawTextA ,F9运行被断下,如图:

 

到达程序对DrawTextA的调用处,F7跟进


 
双击一下,原来是直接跳转到[402010]的地方去了.
我们在数据窗口中d 402010看看402010到底是什么。
 
为方便查看,我们右键选择"长型","地址".


 

原来,402010地址里面的值是77D3C6CA那么jmp dwort ptr [402010]就是跳到77D3C6CA了.这个地址就是DrawTextA函数的入口地址。
现在我们大致知道输入表中这个First Thunk值的作用了,原来程序中对这些输入函数的调用都是jmp 402010 实现的。
为进一步理解,我们在16进制编辑器(如winhex)中查看输入表。


 

数据目录表第二项是 输入表的RVA:2050.将其转换成文件偏移650.该处就是输入表的开始。
蓝色部分是2个IID数组。每个数组有五个属性,对应着一个DLL。这就是lordpe中输入表五个属性的由来,可与lordpe对照:
OringinalFirstThunk TimeDateStamp  ForwarderChain  Name     FirstThunk
9C200000            00000000       00000000        CA210000 10200000
8C200000            00000000       00000000        0A220000 00200000
且看第一个IID。
他的OriginalFirstThunk 值为209C这是RVA值转化为文件偏移69C.便是图中淡黄色部分.
    FirstThunk值为2010转化为文件偏移610.便是图中深黄色部分.
明眼人已经看出来了,这两部分的数据是一模一样的。前者称为INT后者是IAT。
这部分数据也是指针,22210000 转换后是00002122再转化成文件偏移722.看772处是什么?
原来是DrawTextA这个字符串.再看2E210000转化文件偏移72e.看72e处是什么?原来是EndPaint字符串....后面再不一一看了:)------------请注意到并不是刚好指向函数的字符串前面还多了两个字节称为hint值 可为0,此处不详讨.
772,77e....是函数名的地址,这群地址组成的结构被称为IMAGE_IMPORT_BY_NAME.
为什么INT和IAT两个都指向这一结构呢?
系统在程序初始化时根据OrignalFirstThunk的值找到函数名,调用GetProcAddress函数(或类似功能的系统代码)且根据函数名取得函数的入口地址,
然后用函数入口地址取代FirstThunk指向的地址串的值IAT.

回顾本文开头时我们OD的一段跟踪,这段话便不难理解了.当我们在OD中查看00402010(RVA2010加上基址400000)时,里面已经是DrawTextA函数的入口地址。
因为系统已经用真正的函数入口地址取代IAT了。

为加强理解,我们针对以上理论做以下实验.

1.有时候程序不存在OrignalFirstThunk,我们将此程序的该值去掉以看效果.
将650处的9C20以0填充,保存文件.双击。。程序运行正常.可见,在没有OrignalFisrtThunk的情况下,系统直接以IAT中的的函数名得到函数入口地址并填充IAT。

2.OrignalFirstThunk值不变将INT以0填充以看效果.
按CTRL+Z数次恢复对文件的修改,把上图淡黄色部分用0填充,保存文件。双击.弹出程序运行错误窗口.
可见系统根据OrignalFirstThunk值只找到空的INT,程序便运行错误了.

3.依照理解IAT反正会被根据OrignalFirstThunk得到函数入口地址所取代,似乎IAT原始值没有存在的必要.
按CTRL+Z数次恢复对文件的修改.这次将610处即上图深黄色部分用0填充,保存文件.双击.弹出程序运行错误窗口.
按CTRL+Z数次恢复对文件的修改,程序又能运行了.由此可见即使OrignalFirst值正常,INT也正常,IAT的值仍然必不可少,由此可见IAT的重要性!

相信至此 读者已对输入表有了一定程度的认识,无论是ImportREC重建输入表还是手工重建输入表亦或是增加输入函数都已不再是难事.

上传的附件 PE.zip