内嵌补丁 与 洞穴代码分析案例

First Post:

Last Update:

示范案例:unpackme#1.aC.exe,学习过程参照《逆向工程核心原理》

如您发现了某些错误和不规范,请务必指正

插画ID:85939258

内嵌补丁:

    如名字所述,是指将补丁内嵌进程序中的一种打补丁的办法。与常规补丁不同的是,内嵌补丁嵌入在程序的代码当中,也就是说,每次执行该程序时相当于打了一次补丁(常规补丁通常打下第一次就不需要再有第二次了)。

洞穴代码:

    内嵌补丁常用的一种打补丁的方法。目前我个人只了解到其对于“为加密或压缩过的代码下补丁”时的作用,因此也引之为例。

    在反调试过程中,我们会希望能够修改其代码以达成破解。但对于那些被加密过的程序,却通常不能这样轻易的完成打补丁的工作。因为你修改后的代码会在启动程序时经过“解密”,那么你原本的代码就会遭到破坏,使得程序报错。但就出现一个问题——我按照它的方法加密后修改代码不就行了?

    可以,但过程会相当繁琐。假设我们需要修改10条代码,那么就必须加密10份代码。也因为在“下补丁时应该尽可能地不去改变程序主代码”,所以通常不这样做。因此便存在“洞穴代码”这一操作。

    在PE文件的学习中,我们了解到,节区映射到内存时,很可能会预留出一些NULL填补的区域。那么如果在这些区域覆写新的补丁代码,那么就很可能逃过程序的解密算法影响。

    (注:这是我个人学习之后的猜测。越是复杂的解密算法就越是消耗算力,它们不可能浪费不必要的算力去把其他NULL覆盖的区域也来一次解密,所以这些区块理论上应该算是“安全区”一样的存在)

    那么,攻击者需要做的,就是将解密算法最后的Jump指令(JNZ或者JE等跳转指令)指向我们添加补丁的位置,就能够让程序执行我们期望的行为。

如上图为unpackme#1.aC.exe的反调试代码。EP为401000,而401007开始往下有一段看似乱码的东西,实则就是被加密后的代码。

    上图为解密之后的同样区段。能够发现,其字符串明显变得正常了(详见如下的反调试过程)。但如果现在去修改程序的汇编代码,就会在下一次启动程序的时候遭到“解密”,致使程序运行错误。

反调试过程:

    调试程序,来到EP。发现只有一条401001处的CALL指令,跟入。然后在4010E9处将4010F5保存进EAX寄存器中,并将其入栈,再CALL 40109B。

    不妨来到刚刚保存进EAX的4010F5处看看究竟保存了些什么。

    显然,这个EAX中保存的实际上是需要解码的代码段地址。那么就几乎可以认定,40109B就是接下来要进行的解码函数地址了。跟入。

    40109E处,将154放入ECX。而在4010A3~4010AD中,容易发现其对刚刚EAX处的代码进行了异或解密。那么154就应该是解密代码段的长度了。

    正常解密时,完成该循环后应该达到4010B0处的CALL,转到4010BD,再次出现了循环。但本次解码的开始地址为401007,长度为7F,过程仅仅只是与7进行一次异或。

    以及对EAX处保存的地址重新与11异或。可见EAX处的代码进行了双重加密。

    而完成解密之后,返回4010B5,并由下一个CALL进入401039。

    在401046~40104F处存在一个加法循环,在401062处又进行了一次比较,实际上为一个校验过程。但在校验之前,40105D处的CALL会再一次进行解密过程,这里并不太重要,但不妨看看解密之后是否能找到什么讯息。如下图:

    显然,字符串“yoou must unpack me !!!”已经能够找到了。那么我们的目的显然就是修改这个地址处的字符了。

    继续调试将发现如上代码。401068处JE跳转至401083,再由401083跳转至40121E。

    因为Ollydbg在处理解码代码后的回显不太如意,此处换为了x32dbg,发现40121E处即为OEP(我个人是根据401220处调用GetModuleHandleA函数猜测得出的结论,但对于Windows系统的API还不太了解)。

    同时也能发现,401280开始,均为0填充的空白区,那么就可以利用这一块来嵌入补丁了。

    覆写如上代码。该代码主要用于覆写原本的字符串(4012AB处储存的实际上为字符串“ReverseCore”,而4012B7则为字符串“unpacked”,写入之后被x32dbg识别为了其他东西以至于无法清晰分辨了……)。

    最后则需要修改转入出的代码。由上面的图可见,401083处本该为跳转代码,其经过解密之后就是新的跳转代码了。那么覆写该段代码,将EE 91 06改为EE FF 06即可。

    (注:如下图。EE 91 06是未经过解密的代码,所以覆写的代码也应该处于加密状态,即EE FF 06。该方法建立在已知其解密方法为“将数值与7进行XOR处理,所以能够方向计算出新的代码”。即便不在反调试器中修改,直接通过修改16进制文件也能达到相同效果)

    该文件完成补丁。

注:

还存在一个问题。在实际调试过程中,反调试极有可能出现异常导致中断。原因出自于覆写字符串这一行为并不具有权限,因此调试很可能停在rep movsb上。将文件可写打开之后发现并没能解决问题。解决方案在得到答案后将会补齐。