- 第一章 - OD 的各个窗口介绍
- 第二章 - 数值系统
- 第三章 - 寄存器
- 第四章 - 汇编指令
- 第五章 - 数学指令
- 第六章 - 比较和条件跳转
- 第七章 - call ret
- 第八章 - 循环 字符串指令和寻址方式
- 第九章 - 基本概念
- 第十章 - 断点
- 第十一章:硬件断点与条件断点
- 第十二章 - 消息断点
- 第十三章 - 硬编码序列号寻踪-Part1
- 第十四章 - 硬编码序列号寻踪-Part2
- 第十五章 - 硬编码序列号寻踪-Part3
- 第十六章 - 序列号生成算法分析-Part1
- 第十七章 - 序列号生成算法分析-Part2
- 第十八章 - 序列号生成算法分析-Part3
- 第十九章 - OllyDbg 反调试之 IsDebuggerPresent
- 第二十章 - OllyDbg 反调试之检测 OD 进程名
- 第二十一章 - OllyDbg 反调试之检测 OD 进程名,窗口类名,窗口标题名
- 第二十二章 - OllyDbg 反调试之 UnhandledExceptionFilter,ZwQueryInformationProcess
- 第二十三章 - OllyDbg 反调试之 ProcessHeap,NTGlobalFlag,OutputDebugStringA
- 第二十四章 - OllyDbg 反调试之综合 CrackMe
- 第二十五章 - 异常处理
- 第二十六章 - Visual Basic 程序的破解-Part1
- 第二十七章 - Visual Basic 程序的破解-Part2
- 第二十八章 - Visual Basic 程序的破解-Part3
- 第二十九章 - P-CODE-Part1
- 第三十章 - P-CODE-Part2
- 第三十一章 - 脱壳简介
- 第三十二章 - OEP 寻踪
- 第三十三章 - 神马是 IAT 如何修复
- 第三十四章 - 手脱 UPX,修复 IAT
- 第三十五章 - 手脱 ASPack V2.12
- 第三十六章 - IAT 重定向
- 第三十七章 - 论 IAT 重定向之修复
- 第三十八章 - 手脱 Yoda's Protector v1.3(Yoda's Crypter)
- 第三十九章 - 神马是 stolen bytes
- 第四十章 - OllyDbg 脚本的编写
- 第四十一章 - 神马是 AntiDump
- 第四十二章 - ACProtect V1.09 脱壳(寻找 OEP 绕过硬件断点的检测 修复 Stolen code)
- 第四十三章 - ACProtect V1.09 脱壳(编写脚本修复 IAT)
- 第四十四章 - ACProtect V1.09 脱壳(修复 AntiDump)
- 第四十五章补充章节-ReCrypt v0.80 脱壳(续)
- 第四十六章 - Patrick 的 CrackMe-Part1
- 第四十七章 - Patrick 的 CrackMe-Part2
- 第四十八章 - PeSpin V1.3.04 脱壳-Part1
- 第四十九章 - PeSpin V1.3.04 脱壳-Part2
- 第五十章 - 再谈 ReCrypt v.0.80 脱壳(调戏 OutputDebugString)
- 第五十一章 - ASProtect v2.3.04.26 脱壳-Part1
- 第五十二章 - ASProtect v2.3.04.26 脱壳-Part2
- 第五十三章 - TPPpack 脱壳
- 第五十四章 - EXECryptor v2.2.50.a 脱壳-Part1
- 第五十五章 - ExeCryptor v2.2.50.a-Part2
- 第五十六章 - EXECryptor v2.2.50.b 脱壳
- 第五十七章 - ExeCryptor v2.2.50.c/d/e/f/g 脱壳
- 第五十八章 - ExeCryptor v2.2.50
第三十六章 - IAT 重定向
本章我们继续增加壳的难度,将看两款壳,分别是 bitarts 5.0,telock 0.98,telock 0.98 会涉及到本章我们要讨论的 IAT 重定向的知识点。
我们先拿简单的 bitarts 5.0 开刀,用 OD 加载它。
第一行不是用 PUSHAD 保存寄存器环境,我们按 F7 键往下跟。
这里我们跟到 PUSHAD 指令处,按 F7 执行该指令,接着在寄存器窗口中定位到 ESP 寄存器的值,在其上面单击鼠标右键选择-Follow in Dump。
给前 4 个字节设置硬件访问断点。
按 F9 键运行起来(遇到异常忽略掉),断了下来。
往下单步跟几行就能到达 OEP 处。
大家也可以使用 OD 自带的功能选项定位 OEP,前面 OEP 章节中介绍的方法大家可以一一尝试。
OEP 命中在第一个区段。
第一个区段为代码段,OD 不会弹出入口点不在代码段的提示框。
这里我们可以看到调用的第一个 API 函数是 GetVersion,我们可以在一开始给 GetVersion 设置一个断点,运行起来,接着会断下来,看看返回地址是不是位于第一个区段,如果是就定位到返回地址处,上面就是 OEP 了。
定位 OEP 很容易,这里不再赘述了,下面我们来看下 IAT。
460ADC 是 IAT 中的一项,其中保存的是 GetVersion 的地址,我们在数据窗口中定位到 IAT。
这个 IAT 有点大,嘿嘿。
这个 IAT 项存放的是 GetVersion 的地址,属于 Kernel32.dll,我们也可以在区段列表窗口中看看 7Cxxxxxx 的地址属于哪个 DLL。
绿色标注的项大部分都是属于 Kernel32.dll 的,中间夹杂着几项 NTDLL.dll 的,这几项是用 Kernel32.dll 中的相应函数替换了,各个 DLL 的 IAT 项被零隔开了。
下面我们来看看 77xxxxx 这类是属于哪个 DLL 的,我们除了在区段列表中看,也可以在 770F48C0 这一项上面单击鼠标右键选择-Find references。
这里可以看到参考引用列表。
这里可以看到基本上都是在第一个区段中调用的 OleAut32.dll 中的 VariantClear 这个 API 函数。
区段列表窗口中我们也可以看到 770xxxxx 这类地址是属于 OleAut32.dll 的代码段的。
这里我们就不一一看其他 DLL 的 IAT 项了,直接定位到 IAT 的尾部。
这里用湛蓝色,粉红色,灰色分别标注了不同 DLL 的 IAT 项,分割的零用绿色标注出来,在最后一个 IAT 项上面单击鼠标右键选择-Find references。
我们可以看到最后一个 IAT 项是属于 oledlg.dll 中 OleUiBushA 这个 API 函数,我们在区段列表窗口中来验证一下。
下面的几项都不是 IAT 项了。
我们在 6C50000B 上面单击鼠标右键选择-Find references。
可以看到参考引用列表是空的,所以说 IAT 的最后一项的起始地址为 460F28。
我们再来看看哪里是 IAT 的起始位置。
这里可以看到 460810 里面的值是 80000008,明显不会属于任何一个 Dll,我们可以在查看一下其参考引用列表来验证一下,在其上面单击鼠标右键选择-Find references。
可以看到参考引用列表也是空的,说明 IAT 的第一项的起始地址为 406818。
现在我们知道了 IAT 的起始地址和结束位置,我们来计算一下 IAT 的大小:
IAT 大小 = 460F28 - 460818 = 710。
IMP REC 需要的三条数据:
OEP = 271B0(RVA)
IAT 起始地址 = 60818(RVA)
IAT 大小 = 710
下来我们用 OllyDump 插件来 dump。
这里不够选 Rebuild Import,仅仅 dump。
打开 IMP REC,定位到 bitarts 所在的进程,当前该进程处于 OEP 处。
将 OEP,RVA,Size 的值都设置上。
单击 Get Imports。
可以看到该壳在 IAT 中添加垃圾数据,修复的 IAT 项都是有效的,单击 Fix Dump,选择刚刚 dump 出来的文件修复之。
修复过的程序被命名为 unpacked_.exe,运行一下看看效果。
完美运行,没有 AntiDump,比之前介绍的壳稍微复杂一点点。
下面我们来看看 telock 0.98 这款壳,该壳涉及到了我们将要介绍的 IAT 重定向的知识点。
这里我们依然用 ESP 定律来定位 OEP,单步跟几步就能看到 PUSHAD 指令。
按 F7 键执行 PUSHAD 指令,接着在寄存器窗口中定位到 ESP 寄存器的值,在其上面单击鼠标右键选择-Follow in Dump。
给前 4 个字节设置硬件访问断点,运行起来。
单击鼠标右键选择-Analysis-Remove analysis from module 删除掉 OD 的分析结果。
我们可以看到断在了这里。
这说明 ESP 定律不起作用,有可能该壳会检测硬件断点,我们继续运行的话会提示错误,所以我们暂时先把硬件断点删除掉。
重启 OD。
ESP 定律行不通,我们来尝试一下最后一次异常法,首先清空日志窗口。
忽略异常的选项都不勾选,运行起来,可以看到壳的解密例程产生的最后一处异常是 4666F1 处。
运行起来,遇到异常直接 Shift + F9 忽略掉,直到断在 4666F1 处为止。
给第一个区段设置内存访问断点。
接着 Shift + F9 运行起来,遇到异常就 Shift + F9,不一会儿就会断在位于第一个区段中的 OEP 处。
因此 OEP 是 4271B0,这里的原程序和上一个例子的原程序是一样的,加的壳不一样而已。
我们知道上一例子原程序调用的第一个 API 函数是 GetVersion,但是这个例子我们并没有看到 GetVersion 的提示信息,被重定向过了。
我们来看看调用了哪些 API 函数,在反汇编窗口中单击鼠标右键选择-Search for-All intermodular calls。
我们可以看到这些 CALL 都被重定向到了其他区段。
这些间接 CALL 并不是去调用系统 DLL 的中 API 函数,而是转向了 9Fxxxx 这类地址的一个区段,这里在我的机器上是 9Fxxxx,大家的机器上不一定是这个地址。
如果大家往下看的话,会发现还是有一些直接调用 API 函数的,但是大部分还是 CALL 9Fxxxx 这类指令。
这里这些直接调用 API 函数的项我用湛蓝色标注出来了。
这里我们定位到 435FA5 这处,这里是 CALL 435CDE,OD 提示是一个间接跳转到 API 函数的入口处,我们在这条指令上单击鼠标右键选择-Follow。
我们可以看到是一些间接跳转去调用 API 函数,很明显这里是 IAT 中的一些项,我们在数据窗口中定位到 460ED4 这一项。
这里我们可以看到 IAT 中的最后一部分是正确的,跟上一个例子一样,IAT 的结束地址为 460F28,下面全是零了。
往上看,这里用湛蓝色标注出来的这一部分,这一组里面的其他项形式跟 76B1A8F7 这一项形式不一样,我们在 76B1A8F7 这一项上面单击鼠标右键选择-Find references。
我们可以看到调用的是 WINMM.dll 中的 PlaySoundA 这个 API 函数,我们再来看看其他项的参考引用。
这里我们可以看到参考引用的一些项,但是都是一些指针,并不是调用某个系统 DLL 中的 API 函数,我这里是 Axxxxx 的形式(换一台机器这类数值可能不一样),这类数值是什么呢?
这些就是 IAT 中重定向的一些项,当程序运行起来时,壳的解密例程会覆盖掉 IAT 中的某些项,将这些项重定向到解密例程中,我们拿 4038A6 这处为例:
这里并不是直接调用 API 函数,壳将这一项覆盖为了自己所在区段中的一个地址。
为了更好的理解这一点,我们来看看 GetVersion 这个 API 函数,在 OEP 的下面。
其实,这里原本我们并不知道是调用的 GetVersion,但是该原程序跟上一个例子是相同的,所以可以断定这里是调用 GetVersion,这里是一个间接 CALL,我们按 F7 键跟进,看看里面是什么。
我们到了 9F06F7 处。
这里我的机器上是 9F06F7,大家的机器上这个地址可能会不一样,该地址不属于原程序的区段。
这里我们可以看到区段列表窗口,湛蓝色标注出来的是原程序区段,9F06F7 命中在下面这个没有标注名称起始地址为 9F0000 的区段。
如果我们重启 OD 断在入口点处时,会发现这个时候该区段并不存在。
因此,这个内存块是在壳解密例程运行过程中创建的,我们来看看它是什么时候被创建的。
我们给 VirtualAlloc 这个 API 函数设置一个断点,这个函数是用来申请内存空间的。
忽略异常的选项都勾选上,按 shift + F9 运行起来,程序直接结束了,很明显该壳会检测我们设置的 API 断点,我们将断点设置 VirtualAlloc 的 RET 处。
运行起来。
断了下来,EAX 的值为 3C0000,继续运行。
这里我们可以在区段列表窗口中看看刚刚创建的这个内存块。
我们可以看到该内存块被标记为了 Priv(私有的),也就是说该内存块是壳自己创建的。
这里我们删除之前设置的断点,按前面介绍的步骤利用最后一次异常法再次定位到 OEP 处。
我们再次定位到 OEP 处,来看看区段列表窗口。
可能看到起始地址为 9F0000 这块内存空间也被标记为了 Priv,IAT 项中的值会被重定向到这里,我们按 F7 键单步到 9F06F7 处。
定位到了 9F06F7 处。
往下跟几步,可以看到这里的 PUSH 指令将 GetVersion 的地址压入到堆栈中,接着 RET 将会返回到 GetVersion 的入口处,这样就可以达到间接调用 API 函数的目的。
也就是说,壳会将 GetVersion 的 IAT 项替换成自己创建的内存单元中的地址,起到了一个重定向的作用。
因此我们在定位 IAT 的起始和结束位置的时候,不仅仅要判断是否为系统 DLL 中的地址,还是需要判断其是否为重定向过的地址。
下面我们继续来定位 IAT 的起始和结束位置。
湛蓝色标注出来的这部分形式为 Axxxxxx 的地址是被重定向过的,被重定向到了壳的代码中,我们继续往上定位 IAT 的起始位置。
这部分湛蓝色标注出来的,有几项是属于系统 DLL,其他项形式为 9Fxxxx,指向了壳创建的内存单元中。
我们来看看 460AC0 这一项参考引用,的确是重定向到壳刚刚创建的内存块中,我们继续往上看。
这里用橙色标注出来的项,其中形式为 A1xxxx 的地址属于壳创建的另一个内存块。
我们看看 460894 这一项的参考引用。
我们继续往下,我们看到这里:
这几项用橙色标注出来的是属于系统 DLL 的。
再往下就是零了,左边一项是 80000000,明显不属于任何一个内存单元。
所以 IAT 的起始地址为 460818,长度为 710,OEP 为 4271B0。
OEP = 271B0(RVA)
IAT 起始地址 = 60818(RVA)
IAT 长度 = 710
我们打开 IMP REC,定位到 telock0.98 所在的进程。
将 OEP,IAT 起始地址,长度的值都填上。
单击 Get Imports。
我们可以看到 IMP REC 检测到了重定向过的项,但是提示无效,我们单击右边的 Show Invalids(显示无效的项)。
关于这些重定向的 IAT 项如何修复我们在下一章节继续讨论。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论