使用OllyDbg从零开始Cracking 第五十四章-EXECryptor v2.2.50.a脱壳-Part1
第五十四章-EXECryptor v2.2.50.a脱壳-Part1当我们遇到一款之前没有分析过的壳的时候,不要盲目的下手,我们最好先在网上搜一下该壳相关的UnPackMe。如果有相关的UnPackMe的话,我们可以将UnPackMe与目标程序对照着来分析。如果实在找不到相关的UnPackMe的话,我们可以去下载一个该壳的加壳器,然后我们找一个比较简单的小程序(PS:或者自己编写一个小程序也可以,有源代码最好不过了)来作为加壳的对象。接着我们使用该壳的加壳器对我们的小程序进行加壳,我们逐一选择不同的加密强度,从最低保护强度到最高保护强度。接下来逐一分析该壳不同的加密选项都有什么不同,等我们把该壳的各个保护手段都研究透彻了以后,再来分析我们最初的目标程序,就会容易很多。就算以后该壳发布了新的版本,我们有了对其之前版本的深入理解,再来分析其最新版本应该也不会太困难,因为通常来说,新版本的改动不会很大。我已经为大家准备好了EXECryptror的一系列UnPackMe,虽然不是EXECryptror最新的版本,但是对于研究EXECryptror的保护机制已经足够了。(PS:EXECryptror在当年来说算的上一款猛壳)这里我们可以看到不同等级的UnPackMe,难度逐一递增。本章我们的目标程序是上图中的这个UnPackMe_ExeCryptor2.2.50.a.exe。我们直接运行该程序,在弹出的对话框中可以看到保护措施。我们可以看到这个等级的加密强度几乎为零,只是简单的压缩代码/数据/资源,跟UPX壳的做法很比较相似。这里如果我们将UPX的UnPackMe与该程序对照着来分析的话,就可以很容易的得知其OEP以及IAT的起始地址,大小。我们用OD加载UPX的UnPackMe,断在了入口点处。这个入口我们应该很熟悉了吧,可以说几乎本系列教程的每一个章节都可以看到。由于该UnPackMe_ExeCryptor2.2.50.a.exe与UnPackMe_UPX1.91.a.exe的原程序都是一样的,所以加壳以后,它们的OEP,以及IAT也应该是一样的,它们调用的第一个API函数都是GetVersion。我们可以得到这些基本的信息。好,下面我们来分析UnPackMe_ExeCryptor2.2.50.a.exe。首先配置好OllyAdvanced这个反反调试插件。这里我用Patched 4这款OD(我一般都是用这个版本),OllyAdvanced这款插件里面有很多选项可供我们选择,其他的选项勾不勾选无所谓,但是Break on TLS Callback这个选项这里我们一定要记得勾选。如果大家用OD加载UnPackMe_ExeCryptor2.2.50.a.exe的话,会发现还没有达到入口点程序就退出了。这是因为ExeCryptor利用了TLS CALLBACK这一特性在入口点之前执行代码-检测是否正在被调试,如果是,则退出进程。TLS CALLBACK可以在入口点之前执行代码这个特性最初是由一个病毒作者发现的,后来被ExeCryptor的作者利用来进行反调试。这里我们将首次中断的地方切换为System breakpoint处。我们一运行起来就会断在TLS CALLBACK处。我们可以看到OD状态栏上的提示。这是OllyAdvanced这个插件帮我们定位到的TLS CALLBACK回调函数的入口地址。下面我们来看看如何手工定位TLS CALLBACK回调函数的入口地址。我们通过在数据窗口中按CTRL+G输入400000定位到PE头,然后单击鼠标右键选择-Special-PE header将数据窗口的显示模式切换为PE解析模式,往下拉。这里我们可以看到TLS Table address为93110(RVA),加上映像基址400000就得到了493110,即TLS TABLE的起始地址。我们在数据窗口中定位到该地址,我们往下面看就可以找到TLS回调函数的入口地址。这里我们就定位到了ExeCryptor在到达入口点之前要执行代码的起始地址了,使用OllyAdvanced插件的话,它可以帮助我们直接定位到这个地址。接下来我们来看看如何使用PE文件编辑器来定位TLS回调函数的入口地址。这里我们单击directory按钮查看数据目录。我们可以看到TLS Table起始地址的RVA为93110,大小为18。这右边还有个TLS按钮,单击该按钮我们就可以精确的查看TLS的回调函数入口地址的指针等信息。我们可以看到TLS回调函数的入口地址存放在49312C中,我们在数据窗口中定位到该地址。我们可以看到的确是TLS回调函数的入口地址,嘿嘿。好了,现在我们就知道如何用OD,PE文件编辑器以及OllyAdvanced插件来定位TLS回调函数的入口地址了。使用OllyAdvanced插件的话,我们直接就可以断在TLS回调函数的入口地址处,如果是手工的话,我们首先要断在系统断点处,然后在TLS回调函数的入口处设置一个断点,然后运行起来,就可以断在TLS回调函数的入口处了。我们运行起来。这里我们可以看到壳已经检测到自己正在被调试,退出了进程。OllyAdvanced插件里面的选项我们都勾选上了还被检测到,那我们用AntiDetectOlly这个工具Patch一下OD试试看,会发现还是会被检测到。好,那我们再次回到TLS回调函数入口,看看为什么会被检测到。这里我们打开断点窗口查看一下,尽管我们之前并没有设置断点,我们可以看到这里有一个一次性断点。而此时壳在TLS回调函数中的检测代码还没有执行,当检测代码执行的时候,就会发现内存中有指令被替换成CC,也就说明正在被调试,所以这里我们删除掉这个断点,然后运行起来,看看还会不会被检测到。这里我们可以看到程序正常运行起来了,并没有退出。也就是说的确是这个断点被壳检测到了,才导致退出的。我们直接手动将该断点删除即可。如果遇到有的情况,删除了这个断点,还是退出的话,那么就是说出除了OllyAdvanced插件里面的反反调试选项以外,我们还要添加其他的反反调试选项。好了,现在问题我们已经解决了,我们重启OD。现在我们打开区段列表窗口,假设OEP位于代码段的话,那么我们选中起始地址为401000的区段(代码段),单击鼠标右键选择Set break-on-execute。因为我们刚刚重启了OD,所以我们还要再次删除断点列表窗口中的断点。运行起来。(PS:这里利用OllyBone这个插件的Set break-on-execute选项,我依然是怎么断也断不下来,无语球了,哈哈哈。等明年有时间我自己写个break-on-execute的插件吧!这里的话我就给大家介绍一下我断OEP的方法吧,嘿嘿。首先最后一次异常法大家就不要想了,因为压根就没有异常,哈哈。我呢,是用OD自带的Set break-on-access这个选项来定位OEP的,由于是访问断点,所以读取,写入,执行的时候都会断下来,所以肯定是没有OllyBone的break-on-execute快的,但是OllyBone不好用,我也没有办法。我们重启OD,断在了TLS CALLBACK回调函数的入口处。老规矩,删除掉断点列表窗口中的一次性断点。接着给代码段设置break-on-access断点。这里的大家要记住,break-on-access是一次性断点,断下来了就没了,下次要用的话,还要设置一次。这里我们就设置完毕break-on-access断点了,我们可以看到该区段的起始地址被标注为红色了。我们运行起来。断在了这里,从OD状态栏中的提示信息,我们可以知道这是由于写入导致的中断。我们要的是执行导致的中断,而不是读取或者写入导致的中断。这里大家不要盲目的再次设置break-on-access断点,然后按F9键直接运行起来。如果基础好的童鞋的话,一眼就可以看出这里是一个循环,大家看出来没有?我的天!有童鞋说木有看出来!我们用鼠标选中接下来的4DB304这个地址处的跳转指令。看到没,出现了向上指的红色箭头,这款代码不是循环操作是什么?嘿嘿。那么怎么样跳过循环呢?很简单,直接对下一条语句即4DB306处设置一个断点,然后运行起来,就可以跳过这个循环了。但是大家不要慌,将代码往下拉,看看这是不是一个嵌套循环。我们会发现4DB364处也是一个向上的跳转,说明这块代码是一个双层嵌套循环。好,那么我们直接对4DB364这个地址的下一条语句处即4DB336地址处设置一个断点。运行起来。我们可以看到断在了4DB366地址处,也就是我们跳过了这个双层嵌套循环。接下来我们删除掉4DB366地址处的断点,然后依然是对代码段设置break-on-access断点。运行起来。这样我们就断在了OEP处,注意到OD状态栏中的提示信息没有?该中断是由执行导致的。以上就是我定位OEP的方法。不知道有木有童鞋的OllyBone插件能够断下来,如果你们中有人能断下来,请分享一下经验,谢谢,反正我是一次都没有断下来。~~~~(>_<)~~~~)这里我们可以看到断在了我们熟悉的OEP-4271B0处了,这个等级的保护并不存在stolen bytes,我们直接就可以定位到OEP。我们对比着UPX的UnPackMe来看,它到达OEP后以后,下面的GetVersion的调用处并没有被重定向,而我们这里被重定向了,下面我们来修复IAT。首先我们来定位IAT的起始地址和结束位置。这里我们可以看到IAT的起始地址为460818,跟UPX的UnPackMe一样。我们继续往下定位IAT的结束位置。这里我们可以看到IAT的结束地址为460F28。我们来计算一下IAT的长度。计算得出IAT的长度为710。OEP(RVA):271B0IAT起始地址(RVA):60818IAT的大小:710这里IMP REC重建IAT所需要的数据我们都有了。下面我们的任务就是来修复IAT,ExeCryptor并不存在我们前面章节介绍过的关键跳,它是怎么做的呢?它会在特定的时候将正确的API函数地址填充到对应的IAT项中,所以这里我们给GetVersion所在的IAT项设置内存写入断点。这里我们首先要选择Remove break-on-execute将break-on-execute断点删除掉,以免出错。这里我们给将要调用的第一个API函数所在的IAT项设置了内存写入断点,运行起来,看看会发生什么。断在了这里,我们可以看到这一条指令是将正确的API函数地址保存到对应的IAT项中。下面几行,我们会发现其会将479030处的代码修改为C3,即RET指令,然后利用RET指令返回到某地址处再去调用实际的要调用的API函数,下面我们来详细跟踪一下这个流程。我们可以看到在正确的API地址被保存到对应的IAT项中后,下面会向479030地址处写入一个C3,我们看看479030地址处之前是什么内容。479030之前是这样的:写入C3后变成了:这里我们可以看到被修改为了RET指令,相当于该壳在修复IAT项以后再进行自修改(修改自身代码)。但是该壳的代码并不位于第一个区段,所以这里我们重启OD,达到OEP以后对479030地址处的指令设置内存访问断点。首先我们到达第一个API函数调用处。下面我们给返回地址4271DC处设置一个断点。现在我们运行起来。我们可以看到断在了条件跳转处,当API函数地址被填充到对应IAT项中以后,这里就会被自修改为RET指令,壳的自修改是我们要重点关注的,也就是说我们在到达OEP处以后,可以对壳修复IAT项代码所在的区段设置内存写入断点,当断下来时,就到了自修改的地方,现在我们重启OD,到达OEP处。这里我们再次到达第一个API函数调用处,这里是CALL重定向后的地址492493,当479030处被修改为了RET指令,重定向的IAT项已经被恢复为正常的API函数地址了,所以这里我们给壳所在的区段设置内存写入断点,接着运行起来,看看会发生什么。接着我们还是对返回地址4271DC处设置一个断点,运行起来,看看会发生什么。继续:下一个:这是实际上是在填充一个字符串,我们就不一个字母一个字母的看了,我们直接在数据窗口中查看填充完毕后的整个字符串是什么。我们可以看到实际上是一个DLL的名称字符串,可能下面会被用来获取API函数的地址,我们继续。这里是添加字符串结束符’\0’。这里又是重复上面的步骤,但是这次是填充字符’K’的小端存储方式,4B反过来就是B4,这么做的目的可能是为了隐藏字符串。接着到了这里,我们可以看到是保存Kernel32.dll的基地址,我这里是7C800000。接着再次到了这里,填充C3,此时对应IAT项中的值已经被修复为正常的API函数地址了。我们继续运行就断在了返回地址处,我们按F7单步继续往下跟踪到下一个API函数调用处。给返回地址处设置一个断点,运行起来。这里是将47A0BC处的首字节修改为RET指令。我们单步往下跟踪到47A0BC的RET指令处,可以看到对应IAT项中的值已经被修改为正确的API函数地址了,该API函数是Kernel32.dll导出的。我们继续看接下来要调用的这个API函数。到了这里,我们对比着UPX的UnPackMe来看。我们可以看到这里实际要调用的API函数是VirtualAlloc,我们还是在返回地址处设置一个断点,运行起来。这里又是填充另一个RET,我们来看看修改之前的代码是什么:被修改为RET之前是POP EDX,修改为RET以后,就会返回到480D4A处去调用实际要调用的API函数,即VirtualAlloc。也就是说调用API函数的过程是,首先将对应IAT项中重定向的值修改为正确的API函数地址,然后通过自修改得到RET指令,接着通过该RET指令返回到相应的地址处去调用实际要调用的API函数。我们继续往下单步跟踪来验证一下:可以看到这里480D5F处的POP EDX被修改为了RET,此时我们可以注意到4609A8这个IAT项中的值已经被修复为正常的API函数地址了,接着执行RET指令,就会返回到480D45处,调用实际要调用的API函数。好了,下面我来给大家总结一下整个过程:首先获取相应模块的基地址(可能是调用的LoadLibraryA),然后是获取对应的API函数地址(可能是调用GetProcAddress),接着将IAT项中重定向的值修改为正确的API函数地址,然后修改自身区段的代码来达到调用实际要调用API函数的目的。好了,本章就到这里,下一章我们来尝试编写脚本修改ExeCryptor的IAT。
本系列文章汉化版转载看雪论坛
感谢原作者:RicardoNarvaja(西班牙人) 原作者个人主页:http://www.ricardonarvaja.info/
感谢热心翻译的朋友:1~3章译者:BGCoder4~58章译者:安于此生
全集配套程序下载地址:
链接: http://pan.baidu.com/s/1eQzTWfo 密码: vytv
[快捷回复]-感谢楼主热心分享! 感谢楼主分享。 楼主辛苦了,谢谢分享! 楼主,牛逼啊! 楼主辛苦了,谢谢分享! 老大推荐必是精品 嗯嗯 很感谢楼主的教程! 感谢楼主热心分享!
页:
[1]