美文网首页
释放多层代码

释放多层代码

作者: 静析机言 | 来源:发表于2021-08-23 15:46 被阅读0次

    最近在做2019看雪CTF总决赛第6题—三道八佛,很有意思。它采用内存位置无关代码编程并加壳,经过1401次对折叠代码层层随机释放。在前面的所有层中都没有解密程序的逻辑,只有单步到最后一层才会有真正的完整代码逻辑。

    代码都是内存位置无关代码,在保存输入的用户名和序列号后便开始解密代码,将系统的栈克隆到全局区域(mov dword ptr fs:[4], eax和mov dword ptr fs:[8], ebx),最后通过call eax跳转到解密后的代码。

    由于每次释放前都需要先复制迁移栈并设置挂靠,我们可以选择TEB中的StackBase作为硬件断点,然后在StackBase处设置硬件写断点(使用x32dbg调试)。

    然后一直按着F9不动,在触发了1400次时停下来,再进行操作。因为最后一次修改fs:[8]后还有一次自解密,还需要跟踪才能到达真正的验证算法。如果直接运行1401次,关键代码都被清除了。

    其实,我们也可以通过运行脚本的方式来获得核心代码。

    最终获得的核心代码如下图所示,以mov ebp, esp, sub esp, 28开始。

    做到此步我基本就没有多少思路了,该函数牵涉到的运算特别复杂,看着头大。抱着学习的态度参考了HHHso和KevinsBobo两位大佬的做法。

    [原创] KCTF 2019 Q4 第六题 一个支点-CTF对抗-看雪论坛-安全社区|安全招聘|bbs.pediy.com

    [原创]看雪CTF 2019总决赛 第六题 三道八佛-CTF对抗-看雪论坛-安全社区|安全招聘|bbs.pediy.com

    HHHso将核心代码dump下来,长度为0x9e56,加载到0x4016AC处,然后用IDA F5出伪码。代码非常复杂,且和他列出的完全不一样,如下所示。

    看着这么复杂的代码,完全没有逆出算法的信心。

    转而,学习KevinsBobo的方法:仅把牵涉到key操作的函数代码dump出来,长度仅为0x3453。手动将dump的文件末尾一个字节改成c3,即ret,就可以用ida创建函数F5反编译了。

    根据KevinsBobo逆向出的算法代码,照猫画虎,修改F5后源码中的变量名称,截图如下。

    说明此法得到算法逻辑是可行的,F5出来的代码十分简洁。完整的算法还原代码如下

    #include <stdio.h>

    #include <windows.h>

    #include <stdlib.h>

    #include <string.h>

    unsigned char esiData[17] ={0};

    #define __ROL2__(x, n)  (((x) << (n)) | ((x) >> (16-(n))))

    intcheck(unsigned char*esiData,WORD *calc_r)

    {

        WORD k_E_D; //ST5C_2

        WORD k_A_9; //ST58_2

        WORD k_C_B; //di

        WORD k_0_F; //ST54_2

        WORD k_6_5; //ST60_2

        WORD k_2_1; //edx

        WORD k_8_7; //ebx

        WORD k_4_3; //ST48_4

        WORD v14; //eax

        WORD v17; //edx

        WORD v18; //eax

        WORD v19; //eax

        WORD v20; //ST00_2

        WORD v22; //ecx

        WORD result; //eax

        k_2_1 =esiData[0x1] +(esiData[0x2] << 8);

        k_4_3 =esiData[0x3] +(esiData[0x4] << 8);

        k_6_5 =esiData[0x5] +(esiData[0x6] << 8);

        k_8_7 =esiData[0x7] +(esiData[0x8] << 8);

        k_A_9 =esiData[0x9] +(esiData[0xA] << 8);

        k_C_B =esiData[0xB] +(esiData[0xC] << 8);

        k_E_D =esiData[0xD] +(esiData[0xE] << 8);

        k_0_F =esiData[0xF] +(esiData[0x0] << 8);

        WORD t0 =k_2_1 ^ k_4_3;

        WORD t1 =k_6_5 ^ k_8_7;

        WORD t2 =k_C_B -k_A_9;

        WORD t3 =k_0_F +k_E_D;

        WORD x1 =((((t1 & 0x5555) +((t1 >> 1) & 0x5555)) & 0x3333)     +((((t1 & 0x5555) +((t1 >> 1) & 0x5555)) >> 2) & 0x3333));

        x1 =((((x1 & 0xF0F) +((x1 >> 4) & 0xF0F)) >> 8) +((x1 & 0xF) +((x1 >> 4) & 0xF)));

        v14 =(t2 & ~t0 | t3 & t0);

        v17 =(t0 *v14 >> x1) +24;

        v19 =t2 ^ v17;

        v20 =v14 | v17;

        v22 =v14 & v17 | (v19 & v20);

        calc_r[0] =k_4_3 ^ v22;                       //0 4B 43 434B

        calc_r[1] =k_2_1 ^ v22;                       //2 54 46 4654

        calc_r[2] =k_0_F +v19;                       //4 00 1A 1A00

        calc_r[3] =k_E_D -v19;                       //6 19 18 1819

        calc_r[4] =k_C_B +v17;                       //8 17 16 1617

        calc_r[5] =k_A_9 +v17;                       //A 15 14 1415

        calc_r[6] =__ROL2__(v14 ^ k_8_7, x1 & 0xFF);  //C 13 12 1213

        calc_r[7] =__ROL2__(v14 ^ k_6_5, x1 & 0xFF);  //E 11 10 1011

        return1;                                      //K  C  T  F 

                                                       //4B435446001A19181716151413121110

    }

    总结:根据HHHso和KevinsBobo的不同做法可以得出,给IDA分析的代码越小越好,利于还原算法。

    然后运行KevinsBobo给出的C++爆破解法,得到

    UserName:KCTF

    Key:6CCDE9D2EC1D469DC67C647E66B4C565

    相关文章

      网友评论

          本文标题:释放多层代码

          本文链接:https://www.haomeiwen.com/subject/zskliltx.html