首页
社区
课程
招聘
[求助][求助]求高人解释一下究竟为什么某些壳脱壳后需要修复IAT?
发表于: 2012-6-10 13:29 11189

[求助][求助]求高人解释一下究竟为什么某些壳脱壳后需要修复IAT?

2012-6-10 13:29
11189
修复的一头雾水,
壳究竟对IAT做了什么,dump前的IAT和dump后的IAT位置不一样吗?还是壳怎么了IAT,有详细点的解说吗,百度了一天找不到壳和IAT之间的关系。无效指针又是什么?。。。。

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (27)
雪    币: 73
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
就是搞不懂为什么要修复IAT,到底修复的是主程序代码段中跳向IAT指针的指令还是修改IAT内的表项内容,还是要调整IAT在PE或者内存中的位置。
2012-6-10 13:32
0
雪    币: 166
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
首先声明我也是新手,不过我稍微比楼主要懂的多点。输入表=IAT
1、每个可执行文件(后缀名是.exe的)都是PE文件格式的,PE文件格式中有个数据结构叫输入表,因为大部分的程序都需要调用其他DLL文件里的函数,所以输入表就是记录PE文件到底需要调用哪些DLL的哪些函数。
2、一般来说,加壳软件(这里特指加密壳而非压缩壳)对PE文件的输入表进行加密,主要是为了防止该程序被破解。但是运行该加密后的程序,在程序的代码运行以前,壳代码会对加密后的输入表进行还原操作,待程序的输入表还原操作完成后,程序才能正常执行。
3、DUMP的原理我是不清楚的,但是dump前后的输入表的指针是否有变化,取决于加密壳。
4、所谓无效指针,是因为dump后,输入表中某些项的指针指向了如0x00000000h等非法操作地址,这时就需要手动修复这些指针。
2012-6-10 15:20
0
雪    币: 73
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
那么按你的意思就是说,ImportREC需要将IAT修复成可执行的状态?
还是要自己重建一张正常的导入表?
还是ImportREC可以得到壳对导入表的算法,并进行计算,得到解密的导入表后修复?
2012-6-10 16:38
0
雪    币: 615
活跃值: (172)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
5
为什么要修复IAT?

首先得说一下程序调用DLL导出函数的原理,
PE调用DLL里的函数,一般是先加载这个DLL模块到它的进程地址空间,
然后在加载后的地址范围内找到每个调用函数的地址,
在程序中你可以使用LoadLibrary()这个系统API去动态去加载某个DLL,
再通过GetProcAddress()系统API来找到DLL导出的某个函数地址,
得到函数地址了你才能使用这个函数。
用户DLL被加载后的基址可发生变化,导入的函数地址不是固定的,你不能使用固定的地址。
系统DLL虽然基址固定,函数地址固定,但是一般不会直接使用函数硬地址,
还是要GetProcAddress()这个API来得到地址,因为XP、win7等每个系统的这些地址
是不一样的,会导致兼容性问题。

关于导入表,
而为了开发更方便和更人性化,编译器提供了这个静态导入函数的功能,
也就是说你在编程的时候不需要LoadLibrary(),不必每次调用一个函数都GetProcAddress(),
你只需要在源代码中写函数名和参数即可,编译器会将你使用的<函数名>和函数所在的<DLL文件名>
两个信息填写到输入表里,当程序启动运行时由操作系统根据这两个信息给程序加载
所需的DLL,并将所需要的函数地址写入IAT。
    IAT是指PE导入地址表,每个IAT就对应了一个DLL文件导入函数的地址表,
你的程序里调用的地址不是直接调用DLL里函数的地址,因为你不知道地址是多少,
而是直接调用了IAT里的地址。程序启动时操作系统加载所需的DLL并填充导入名称表INT对应的
函数地址到地址表IAT对应PIMAGE_THUNK_DATA结构里,然后程序就可以正常调用IAT中这些函数地址了。

壳的工作原理,
某些加壳程序加壳后会修改了原来导入目录表的位置为壳的导入表,
这样默认的导入表指向壳部分的导入表,你就看不到原来的导入表的内容了。
程序启动后,操作系统为壳的导入表加载,
在壳代码运行完成之后,壳代码会跳到原程序的入口点OEP,壳模拟操作系统填充
原来导入表IAT,这样保证代码段能正常调用函数。
一般壳的工作原理也就是这样了,随着现在加壳加密技术的进步,不是所有加壳软件都会这样。

脱壳原理,
首先修改被加壳程序的入口点到程序原来的OEP,
然后修改PE程序导入表目录地址为原来导入表地址,或者新建一个节,
将这个新节作为导入表节,并将原导入表内容写入新节导入表。

脱壳过程,
OD跟踪,让壳运行到原程序OEP(不一定非得OEP,程序领空导入表一般都是处于还原状态,
OEP要知道),这时候可以用PE DUMP脱壳插件或者用LordPe等工具脱壳,
程序当前的内存映像被dump出来,里面IAT结构完整很容易被发现。
dump后程序不能正常运行很可能是导入表位置错误(也可能是程序有自校验),
因为dump出来的只是内存中的映像快照,导入表目录还是指向壳的导入表,
这时,需要用导入表修复软件查找dump出的PE文件原导入表首地址,
然后修正导入表目录中导入表的位置,或重建导入表。
Import Fix导入表修复软件会新建一个节来保存原导入表数据,并将导入表目录指向新节导入表位置。
在搜索导入表时可能导入表被破坏,Import Fix会识别出一些无效的IAT项,可以将其剔除掉。

by 小覃 2012,06,10 看雪论坛
http://www.qinrihong.com/
http://www.weibo.com/qinrihong

以上是个人的描述,如有不正确之处欢迎大牛们指正!
2012-6-10 18:19
0
雪    币: 73
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
我看好你哦,回复,接下来慢慢理解。
2012-6-10 18:44
0
雪    币: 73
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
意思就是某些壳会将原程序的导入目录指针替换成壳程序的导入表,而其实原来的导入表是在内存中存在的?

那么dump后,我们得到的难道不是原程序的导入表指针吗?
2012-6-10 18:55
0
雪    币: 615
活跃值: (172)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
8
dump出来的只是内存中的映像,导入表目录还是指向壳的导入表。
dump出来的那块IAT区域被填充了地址,INT和dll名称完整,Import Fix等修复程序
能很快找到原导入表首地址和内容,然后重建导入表。
2012-6-10 19:10
0
雪    币: 73
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
你的意思是说,加壳后导入表目录指针指向壳的导入表。壳代码运行后,将根据原来的导入表填充壳的导入表IAT?若是这种情况我们dump下来应该也能用啊。毕竟IAT被填充了正确的函数地址。
2012-6-10 21:25
0
雪    币: 73
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
我们dump的位置是OEP,在OEP之前壳就应该填充好了IAT。这时候抓下来的映像应该可以运行啊,因为IAT在OEP之前已经恢复了。
2012-6-10 21:28
0
雪    币: 615
活跃值: (172)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
11
请认真看我的回复。。
2012-6-10 21:39
0
雪    币: 73
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
好了我有点明白了,在OEP以后的代码默认在编译后使用的是原IAT表内的地址,这个IAT表是由壳来填充的,因为原程序编译后的代码已经指明将使用旧的IAT,所以也就没必要将数据目录指向原来的导入表。或者向壳的导入表填入原程序所需要的IAT,因为在OEP以后这张壳的IAT表基本是没用了。
2012-6-10 21:40
0
雪    币: 615
活跃值: (172)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
13
8楼回复讲的已经很明白了,自己再慢慢理解下吧~
2012-6-10 21:42
0
雪    币: 73
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
脱壳后文件是存在两张导入表的。
一张是壳的也就是被指向的。一张是旧的也就是原程序的。
旧的导入表由于没有壳代码来填充,并且它不被指向,loader将不会对这张表进行填充。
2012-6-10 21:47
0
雪    币: 615
活跃值: (172)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
15
嗯,就是这么个原理。

具体ImportREC这款导入表修复的工具工作原理我还是不太明白,
反正之前用的时候发现它修复后会新建一个节做导入表。
其实我认为只要修改导入表目录指向原来导入表首地址就可以了,
重建导入表节的话可能还要搜索并重定位所有调用导入表地址的数据,容易出问题。
2012-6-10 21:56
0
雪    币: 23
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
谢谢深入详解。。。
2012-6-10 23:47
0
雪    币: 73
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
因为dump出来的IAT已经填充了,Import REC 为了让IAT的地址是被loader根据函数名和dll加载填充的,而不是需要直接使用的表。
话说如果我的理解是正确的话,你说我理解对了,可是dump下的文件内原IAT函数地址也已经被填充了啊,OEP后的代码为JMP [原IAT地址],如此应当不修复也能使用才对,因为系统dll加载的基址一样,就算数据目录指向了壳的导入表,脱壳后程序也并不使用这张表啊。难道程序经过OEP后这些api调用指令内的地址会重定位为数据目录指向的壳的导入表的地址?所以运行失败????
我们dump下来的原IAT,应该是可用的呀。
2012-6-11 07:00
0
雪    币: 73
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
额,貌似是需要修复的吧,
光有IAT没有输入表结构loader能同意加载????
。。。。
2012-6-11 07:33
0
雪    币: 73
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
不管最后的IAT内的地址是不是正确了,Loader在加载程序的时候都将读取输入表结构向IAT填充新的地址。
....
但若本次dump出来的原程序IAT已经被填充了正确的api地址,就算Loader启动的时候加载的是壳的输入表又有什么不可以,并不影响到原程序对原IAT的引用啊(这时候在dump文件已经静态的保存下了系统api函数地址)
2012-6-11 07:40
0
雪    币: 73
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
一头雾水....
2012-6-11 07:41
0
雪    币: 73
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
我个人觉得吧,壳模拟LoaderJ加载原程序IAT的方法是LoadLibrary和GetProcAddress,
当加壳后,输入表指针被替换成了壳的输入表,当程序执行到OEP的时候,IAT已经被填充完毕,这时候我们dump下来。
但是,壳只需要用到Kernel32.dll这个dll文件,你dump的时候,原程序的输入表也许使用了很多的dll文件,而且IAT已经被填充完毕并保存了这些dll文件内函数的正确地址。
但是一个已脱壳文件,运行的时候,若不将输入表目录指针指向原程序的完整输入表的话,那么将只加载壳的输入表,也就是只会加载Kernel32.dll这个dll文件。这个时候,当原程序的OEP得以执行,调用API的时候,虽然引用的是原IAT的地址,虽然这个地址上保存了正确的函数指针,但是这个函数所在的dll并没有被加载起来,所以仍然无法运行、

需要重建一张输入表,并将这些IAT函数指针还原成输入表的完整结构(即带有dll名和函数名的输入表结构)。
之后将数据目录指向该重建后的输入表。
2012-6-11 07:50
0
雪    币: 36
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
我觉得 如果不新建导入表的话,那DUMP下来的内存印象也是直接可以用了吧
2012-6-11 09:49
0
雪    币: 36
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
又想了一下 即使新建了也应该没有影响啊
2012-6-11 09:50
0
雪    币: 73
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
貌似是不可以的吧,
dump后的文件,输入表数据目录指向了壳的导入表。
PE文件执行的时候,loader加载壳的导入表所需要的dll(即一个Kernel32.dll),并将函数地址填充入IAT。
之后程序将从OEP处开始执行,虽然程序内的IAT是已经填充过的,但是那些需要的dll却并没有被加载,也就是你dump的时候那些dll是已经加载了,但是你运行的时候,虽然原IAT是已经填充好的,但是没有壳代码来LoadLibrary加载这些dll文件,也没有导入表数据目录指向原始的导入表,所以这些IAT固然正确,却指向了一些不存在的地址,也就是这些需要的dll并没有被加载到进程的地址空间内。
2012-6-11 10:45
0
雪    币: 73
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
以上是我的个人理解。
不知道正不正确,待会自己写个程序调试验证下。
2012-6-11 10:46
0
游客
登录 | 注册 方可回帖
返回
//