第五十七章-ExeCryptor v2.2.50.c/d/e/f/g脱壳 UnPackMe C: 本章我们继续加强ExeCryptor UnPackMe的难度。UnPackMe C与UnPackMe B的难度比较接近,只不过UnPackMe C在运行的时候会检测是否存在注册表以及文件监视工具,如果检测到了会将它们关闭。 由于这里我并没有开启注册表以及文件的监视工具,所以UnPackMe C与UnPackMe B的脱壳方法是一样的,我的机器上MOV EAX,DWORD PTR SS:[EBP - C]这条指令的地址为486DF7。 00486DF7 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C] 00486DFA E8 61670100 CALL 0049D560 ; UnPackMe.0049D560 00486DFF 5B POP EBX 00486E00 8B0424 MOV EAX,DWORD PTR SS:[ESP] 00486E03 52 PUSH EDX 我们将脚本中硬件执行断点的地址修改为486DFA。 脚本如下: ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- var table var content mov table,460818 start: cmp table,460F28 ja final cmp [table],50000000 ja ToSkip mov content,[table] cmp content,0 je ToSkip log content log table mov eip,content bphws 486DFA,"x" mov [486DFA],0 mov [486DFB],0 cob ToRepair run ToRepair: cmp eip,486DFA jne ToSkip log eax mov [table],eax run ToSkip: add table,4 jmp start final: ret 到达OEP处以后别忘了删除掉break-on-execute断点(PS:使用OllyBone插件设置了break-on-execute断点的话,记得要删除,没有用到OllyBone插件的话,就不用管了),接着将监控线程挂起,然后在ZwTerminateProcess这个API函数的入口处设置一个硬件执行断点,接着执行该脚本修复IAT,IAT修复完毕以后就可以进行dump了,然后打开IMP REC修复dump文件,这样UnPackMe C就搞定了。 UnPackMe D: 接下来我们来看看UnPackMe D,双击运行,看看等级D的保护措施: 我们可以看到调试消息这个选项开启了,也就是说会检测调试消息。不知道对我们有没有影响,我们用OD加载UnPackMe D,还是跟之前一样断在了系统断点处,我们删除掉断点列表窗口中一次性断点,接着给代码段设置break-on-execute断点,运行起来就可以到达OEP处了。 到目前为止,我们还没有看到Debug Messages这个选项开启了对我们有什么实质上的影响。下面我们来查看一下线程的情况。 跟之前的一样,我们还是将除了主线程以及线程函数入口地址为270000的这两个线程以外的其他线程都挂起。 好,下面我们定位到OEP下方调用的第一个API函数指令处,对其IAT项设置内存写入断点,接着利用OD的Trace into进行自动跟踪。 自动跟踪需要一段时间。 好了,自动跟踪结束了,断在了这里,我们在跟踪日志中定位到MOV EAX,DWORD PTR SS:[EBP -C]这条语句,我们可以看到它在这里。 也就是说跟UnPackMe C并没有什么区别。 0046D8DC 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C] ; kernel32.GetVersion 0046D8DF 8BE5 MOV ESP,EBP 我们只需要将硬件执行断点的地址修改为46D8DF即可,修改后的脚本如下: ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- var table var content mov table,460818 start: cmp table,460F28 ja final cmp [table],50000000 ja ToSkip mov content,[table] cmp content,0 je ToSkip log content log table mov eip,content bphws 46D8DF,"x" mov [46D8DF],0 mov [46D8DF],0 cob ToRepair run ToRepair: cmp eip,46D8DF jne ToSkip log eax mov [table],eax run ToSkip: add table,4 jmp start final: ret ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 好了,现在我们重启OD,再次断到OEP处,接着删除掉break-on-execute断点,然后在ZwTerminateProcess这个API函数的入口处设置一个硬件执行断点,接着执行该脚本。 我们可以看到IAT项都被修复了,也就是说的确跟UnPackMe C没有区别。下面我们继续来看UnPackMe E,看看有没有什么不同的地方。 UnPackMe E: 我们运行UnPackMe E,看看跟UnPackMe D相比有什么区别。我们可以看到UnPackMe E的Active Watch(这个单词我们可以理解为动态监视)这个选项开启了。 我们会发现脱UnPackMe E,UnPackMe F与脱UnPackMe D的步骤基本上是一样的,这里我就不再赘述了。 我们直接来看UnPackMe G,UnPackMe G的话就会玩一些新花样了。 UnPackMe G: 我们双击运行UnPackMe G,可以看到这个等级反跟踪选项被开启了。我们需要利用OD的trace into(自动跟踪)功能来定位MOV EAX,DWORD PTR SS:[EBP-C]这条指令, 不知道反跟踪这个选项会不会对此造成影响。 我们用OD加载UnPackMe G,断在了系统断点处,接着我们删除掉断点窗口中的一次性断点,然后对代码段设置break-on-execute断点,接着运行起来,我们会发现在到达OEP之前,会断下来5到6次(由于单步异常导致的),这是反跟踪这个选项带来第一处影响。 我们可以看到OD状态栏中提示:发生了单步异常,需要我们手动按Shift + F7/F8/F9忽略掉这个异常继续往下执行。这里我们不能够勾选忽略单步异常这个选项,如果我们勾选了这个选项的话,那么OllyBone插件就不起作用了,所以这里我们必须手动按Shift+F9忽略这些单步异常,大约按5到6次Shift +F9就可能断到OEP处了。 另外一个细节就是,我们会发现除了该程序运行必需的两个线程,并不存在其他的监控线程了,这也算是反跟踪选项带了的又一个不同之处吧。 我们可以看到这里只有该程序运行必需的两个线程,如果还存在其他线程(这里我们姑且称这些线程为监控线程)的话,我们需要将这些监控线程挂起。这里由于反跟踪模式开启了,为了以防万一,我们将OllyAdvanced插件里面的Anti-RDTSC以及GetTickCount这两个选项勾选上。 和 大家在使用Anti-RDTSC这个反反调试选项的时候,要稍微留意一下OD右下角显示的状态,如果显示为中断,过一会儿弹出一个消息框提示驱动无法正常启动的话,说明Anti-RDTSC这个选项附带的驱动程序无法正常工作,遇到情况的话,大家可以重启一下电脑试试看。 现在我们跟之前一样对460ADC这个IAT项设置内存写入断点,删除掉break-on-execute断点,接下来利用OD的trace into功能进行自动跟踪,看看会发生什么。 我们断到了这里。 下面我们在跟踪日志中定位MOV EAX,DWORD PTR SS:[EBP-C]这条指令。 这里我们可以看到MOV EAX,DWORD PTR SS:[EBP-C]这条指令的地址为491E65。 00491E65 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C] ; kernel32.GetVersion 00491E68 8BE5 MOV ESP,EBP 也就说到目前为止,trace into并没有出现问题,有可能是我们勾选上了OllyAdvanced插件中的Anti-RDTSC以及GetTickCount这两个选项的缘故吧,我们还可以看到此时线程函数入口地址为270000的这个线程中止了。 好,我们需要的信息已经搜集完毕了,接下来我们先进行dump,接着来修改脚本,然后执行该脚本修复IAT。 这里我们将脚本中硬件执行断点的地址替换掉。 var table var content mov table,460818 start: cmp table,460F28 ja final cmp [table],50000000 ja ToSkip mov content,[table] cmp content,0 je ToSkip log content log table mov eip,content bphws 491E68,"x" mov [491E68],0 mov [491E68],0 cob ToRepair run ToRepair: cmp eip,491E68 jne ToSkip log eax mov [table],eax run ToSkip: add table,4 jmp start final: ret ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 好,现在我们在ZwTerminateProcess这个API函数的入口地址处设置一个硬件执行断点,接着执行该脚本,我们可以看到IAT项都被修复了。 这里的不同之处在于,中途并没有跳转到ZwTerminateProcess处,但是IAT项也被修复了,好,下面我们打开IMP REC。 我们可以看到IMP REC中显示有无效的项,我们单击该项左边的加号将其展开,可以看到这些项修复后的值是错误的。 mov table,460818 start: cmp table,460978 ja final cmp [table],50000000 ja ToSkip 我们将脚本修改成这个样子(只让其修复第一个DLL中导出函数对应的IAT项),我们执行该脚本,接下来看看日志信息。 这里我们可以看到中间有几处单步异常(之前是没有的),好,我们重启OD,断到OEP处,现在我们不需要使用OllyBone插件了,所以我们可以将忽略单步异常的选项勾选上。 我们再次在ZwTerminateProcess的入口处设置一个硬件执行断点,执行该脚本,接下来我们来看看第一个DLL中的IAT项有没有被修复。 我们再来查看一下日志信息。 我们可以看到第一个DLL中的IAT项这次都被修复了,而且跟之前一样中途会跳转到ZwTerminateProcess处,好,现在我们再次将脚本修改回去,让其修复整个IAT。 执行了该脚本以后,我们可以看到所有的项都被修复了。 我们修复dump文件。 运行修复后的dump文件。 好了,程序完美运行,本章到此结束。
本系列文章汉化版转载看雪论坛
感谢原作者:RicardoNarvaja(西班牙人)
感谢热心翻译的朋友: 1~3章译者:BGCoder 4~58章译者:安于此生
全集配套程序下载地址:
|