常见的逆向工程工具往往都是针对基本假设而开发的,例如:二进制文件通常符合编译器生成的标准模式、指令不会跳转到其他指令、一些情况下符号是可用的等等。逆向工程师可能都知道,如果这些假设不符合实际,那么逆向的工作量将会大大增加。这将造成逆向工具出现问题,甚至完全不可用。本文主要讲述了这样的一个场景,并提出了一个效率较高的解决方案。
这个二进制文件所使用技术的与众不同之处,在于它应用的规模。通常,这种技术用于模糊字符串,也不会超过几十个字节。然而,这个二进制文件使用该技术构建两个嵌入式的可执行文件,总共大约16KB的数据,因此,大约有16000字节的内容使用了这种技术,如上图所示,每一部分都由7个字节的指令实现。上图所示的函数中,包含大约118KB的代码,这占据了整个二进制文件的25%以上。即使没有使用这种技术,该函数也会很大,因为它除了上面的指令之外,还有大约7KB的变异代码。
第二,每次写入栈变量时,都有一个赋值语句:
借助IDA的帮助,我们可以成功对这个函数进行处理。使用IDA来分析这一函数并没有出现明显的速度差异。但是,如果使用Hex-Rays来处理,将会出现明显的问题。其实,这并不能说明Hex-Rays的性能较差,毕竟这个函数有118KB之大,Hex-Rays将会进行比IDA更多的处理。首先,我必须修改Hex-Rays反编译选项,从而可以反编译这一函数:
1、在对特定二进制文件进行逆向工程时,我经常多次使用File->Producefile->Create.cfile…菜单命令。该函数会在遇到每个命令时出现短暂的中断。
2、某些插件,例如Referee,最好与上述提到的命令一起使用。
3、当以交互方式(例如通过重命名变量或添加注释)在此函数上使用反编译器时,UI会变得非常缓慢,且可能会无响应。
4、随机查看指定函数的交叉引用,或者来自特定函数的交叉引用的过程将非常缓慢。对于反编译错误的函数,我们必须要等待反编译器完成。
基于上述原因,我们决定采用更加有效的方案:
1、通过相应的112KB编译代码,提取写入栈中的两个.bin文件;
2、将这些.bin文件修补到数据库之中;
3、使用一个补丁,调用memcpy()替换112KB的指令;
4、修补函数的代码,分支出超过112KB的栈写入。
我要做的第一件事,就是将栈写入的Hex-Rays反编译结果复制粘贴到自己的文本文件中。然后,我们迅速地进行一些健全性检查,以确保所有写入操作能够按顺序进行,我使用了一些正则表达式的搜索和替换操作,并且采用了手动编辑,来将数据清理成我可以在Python中使用的格式。
接下来,我还写了几行Python代码,将数据保存为二进制文件:
在这一位置,我使用IDA的Edit->PatchProgram->Assemble…命令,将一个较小的补丁写入相应的函数:
经过一些调整,并且使用十六进制编辑其结果后,我的补丁被成功安装:
然后,我使用两行IDC脚本,将二进制文件作为数据,加载到正确的位置:
之后,导航栏显示,大约31%的文本部分已经转换为数据。
通过本文中的案例,可以看出,如果我们足够了解所使用的工具,就能找出导致问题的原因,从而可以进一步解决这一问题。始终保持好奇心,并积极进行实验,并且不要只想到次优的逆向工程方案而不再去积极探索是否有更加简单的解决方案。