IMAGE_IMPORT_DESCRIPTOR struct
union {
DWORD OriginalFirstThunk; 4Byte
};
TimeDateStamp DWORD ;04h 4Byte
ForwarderChain DWORD ;08h 4Byte
Name DWORD ;0Ch; 4Byte
FirstThunk DWORD ;10h; 4Byte
IMAGE_IMPORT_DESCRIPTOR ends
以上是输入表结构,5个部分,由这5个部分引出导入地址表(IAT)和导入名称表(INT)。。。。
首先明白函数名和DLL名的在程序中的排列:
WORD String
HINT号 函数名
……
……
模块名1
HINT号 函数名
……
……
模块名2
……
//---------------------------------------------------------------------------
也就是说2个字节代表HINT号,后面紧跟的就是函数名,函数名以0x00结尾。在所有函数都罗列完毕后,紧跟的就是这些函数所在的模块名。然后又是函数名,又是模块名……
第一个IID成员:OriginalFirstThunk,是一个RVA,以例子形式表现,假如OriginalFirstThunk存放的是地址1111,我去地址1111处看一下是什么;
地址1111:地址2222,也就是说在地址1111里面放的是地址2222,那再去地址2222里面看看放的是什么;
地址2222:0001 GetModuleHandleA,也就是说地址2222中放和是Hint和函数名称字符串,这个Hint是指函数在某DLL中和次序;值得说明的是这个函数是某个DLL中导入本程序的第一个函数,其他是**** 函数名2 。。。。一直到DLL名字字符串结束,这时从这个DLL中导入程序的函数就完全了; 其他DLL的函数导入也是这样。
第二个IID成员和第三个IID成员一般用不上,为00000000(DWORD)。
第四个IID成员:Name,是一个RVA,Name中存放的是地址3333,那去看一下地址3333中存放的内容,
地址3333:kernel32.DLL,显然是一个DLL名字符串,,和第一个成员解释中对应
第五个IID成员:FirstThunk ,是一个RVA,FirstThunk 中存放的是地址有两种情况,1111(和OriginalFirstThunk中相同)或者4444,出现第一种情况是标准程序中见到的,这是Windows导入函数的一种方式,出现第二种情况是在脱壳程序中看到,我讨论4444这种情况,看一下地址4444中的内容,
地址4444:BD 2F 81 7C,倒过来看就是一个函数地址。。。这是另一种导入库函数的方式,当第一种方式失效时就用第二种方式。
切入正题。。。。。。。。。。。
手动修复输入表时,我把得到 的API地址单独放置在6E50处,这些API地址有在kernel32.DLL中的,还有Shell32.DLL中的,有user32.DLL等各种不确定DLL中的,反正不是 一个DLL中的,都说在IAT中不同的DLL中的函数地址要放在一起,问题是这种说法对吗?我得到的结论是否定这种说法。。。
只要DLL中有一个函数导入了,DLL中其他函数地址也能被程序找到就OK了,正是如此的!
手动修复过程中遇到初始化失败问题,最后出现了,一个是IAT地址和大小没有写,另一个是OriginalFirstThunk中的值写的不对,假如OriginalFirstThunk中的值是地址5555,那么地址5555处的数据是地址6666,那么地址6666处的数据一定要是0才行,如果不是0会有两种错误出现:
第一种,6666没有超过程序的最大偏移,并且地址6666里的数据为该DLL中的一个函数名比如user32中的MessageBoxA(相应6666处为 00 00(不能少了序号) MessageBoxA),不会提示错误,
第二种,如果地址6666处是另一个DLL中的函数名或者其他数据,会显示如下错误
第三种,如果地址5555(OriginalFirstThunk)处的数据不是6666,而是一个很大的地址,比如00900000,900000这个地址超过程序的范围了,会出现如下错误
结论,总共两点:
第一点,OriginalFirstThunk的内容问题
第二点,DLL导入和API调用问题