首页
社区
课程
招聘
[原创]CTF2016看雪--最后一题
发表于: 2016-12-29 23:36 5135

[原创]CTF2016看雪--最后一题

2016-12-29 23:36
5135

最后一题,这题的作者是我同学--小野老板

做题的当天也是我离开武汉的日子,这题是在高铁上做的,做完以后看着窗外风景呼啸而过心情很惆怅。。。其实什么也看不见天都黑了

感谢科锐,感谢各位同学的帮助,感谢钱老师,感谢张老师,感谢柯老师,感谢姚老师,感谢李老师,感谢袁老师,感谢CCTV,感谢国家。。。

注:
1.以下数字全部是16进制

这题应该是用纯汇编写的,10KB够小,看到熟悉的push ebp mov ebp,esp,接着push各位寄存器大仙,这样的标准格式很容易让人想到radasm。

而题目本身应该是构思了一个比较大的验证框架,但是时间来不及所以有点赶工,回想起来那段时间确实学校的作业也比较多。

进入程序,程序用了两种反调试手段,准确的说应该是反断点手段:
1.遍历程序本身代码段,加总每个字节算校验和,如果不对则人为制造C05退出程序,这种反调试手段用了3次,这是为了防止下CC断点,地点如下图:
1

2

3


2.另一种反调试手段,是创建一个线程计时修改内存属性,这是为了防止下内存断点,地点如下图(图中的call ebx,第一个是Sleep,第二个是VirtualProtect,至于为什么是之后再表):


第1个手段nop调产生C05异常的代码即可,第2个手段可以直接ret调这个线程函数,由于我做这题没有下内存断点,所以我也没管他。

接着说为什么call ebx就是call Sleep,当然可以动态调出来,因为OD有这个功能。但是还是需要分析下401039这个函数,这是因为后面破解也需要了解他在干嘛,我直接说答案了,这个函数就是在GetProcAddress,作者是自己解析导出表自己实现这个功能,然后填入到全局数据区,但是填入函数指针地址是做了手脚,这样不能直接由OD分析,而需要修正后call到这个指针才会提示出函数名。

而由于修正手法一样,要解析这些全局数据区也有了方便法门,如下图:


可以在标红那里下断点,然后修改eax为对应要解析的全局地址,然后单步走完修改ebx的值,ebx就是修正后的API地址,这样把全局数据区一一对应就可以全部解析出来了,但也不需要全部解析,只要解析出最关键的一个即可,即403B19,这里对应的是MessageBox,也是后面提示成功弹框的地方,记住403B19这个地址后面有用。

程序的验证流程是放在4016F0和4017F9这两个线程函数中进行的,而在主线程中有看到拿输入数据并验证其实后面没什么用,这也是我为什么说作者设计了一个比较大的框架。

在4016F0拿到输入字符(必须为8个字节),会计算所有输入字符的总和,并同时会逐个字符异或66后结果保存到一个全局数组,如下图:


紧接着会根据字符总和做跳转,唯一正确的是325这个总和,因为325这个才会启动4017F9的等待事件,接着进入到4017F9这个线程函数中拿出刚才异或结果的全局数组的前4个字节与后4个字节加总,看是否等于32113442,不等于则验证失败,等于进入下一步,如下图:


在这里会用异或结果的全局数组解密一段40个字符的代码段,然后跑这段代码,解密算法比较简单就是加上后4个字节,然后异或前4个字节,如下图:


由于作者有提示验证成功是弹框good!,这里就有个推断了,代码中call API不可能把地址写死,这也是PE中导入表存在的意义,而作者自己模拟了导入表,那必然就会用到自己模拟的导入表来调用MessageBox,所以403B19这个保存了MessageBox跳转地址的全局变量就有用了,而这段解密代码正确的话,应该存在403B19这个地址。

有了上面的推断我们可以写枚举代码了,可以首先找到适合加总等于325,并且都逐位异或66后前4个字节与后4个字节加总等于的解的集合,然后在这些集合中去用程序的方法去解密那段28个字节的代码段,然后看解密的代码里面是否存在连续3个字节分别是19,3B,40,这样进一步缩小适合的解集,最终找到了100个左右的解集,求解集的C代码如下:
#include <windows.h>

BYTE g_ary_btSocCodes[40] = {
    0x69, 0x92, 0x14, 0x09, 0x58, 0x1A, 0x65, 0x79,
    0x60, 0x13, 0xCC, 0xD1, 0x28, 0x34, 0x0A, 0x2C,
    0x0F, 0x40, 0x0B, 0x5C, 0x83, 0x08, 0x4B, 0xF4,
    0x30, 0x85, 0x39, 0x34, 0x18, 0x40, 0x0B, 0xCD,
    0xE9, 0x6F, 0xCA, 0x8C, 0x1F, 0x0F, 0x4B, 0xF4
};

BYTE g_ary_btDesCodes[40] = {
    0x00
};

void backToGood()
{
    BYTE* pbtLeft = NULL;
    BYTE* pbtRight = NULL;
    DWORD dwLeft = 0;
    DWORD dwRight = 0;
    DWORD dwConst = 0x32113442;
    BYTE ary_btTmp[0x10] = "\0";
    do {
        pbtLeft = (BYTE*)&dwLeft;
        ary_btTmp[0] = (pbtLeft[0] ^ 0x66);
        ary_btTmp[1] = (pbtLeft[1] ^ 0x66);
        ary_btTmp[2] = (pbtLeft[2] ^ 0x66);
        ary_btTmp[3] = (pbtLeft[3] ^ 0x66);

        if (ary_btTmp[0] < '0' || ary_btTmp[0] > 'z' ||
            (ary_btTmp[0] > '9' && ary_btTmp[0] < 'A') ||
            (ary_btTmp[0] > 'Z' && ary_btTmp[0] < 'a') ||
            ary_btTmp[1] < '0' || ary_btTmp[1] > 'z' ||
            (ary_btTmp[1] > '9' && ary_btTmp[1] < 'A') ||
            (ary_btTmp[1] > 'Z' && ary_btTmp[1] < 'a') ||
            ary_btTmp[2] < '0' || ary_btTmp[2] > 'z' ||
            (ary_btTmp[2] > '9' && ary_btTmp[2] < 'A') ||
            (ary_btTmp[2] > 'Z' && ary_btTmp[2] < 'a') ||
            ary_btTmp[3] < '0' || ary_btTmp[3] > 'z' ||
            (ary_btTmp[3] > '9' && ary_btTmp[3] < 'A') ||
            (ary_btTmp[3] > 'Z' && ary_btTmp[3] < 'a')) {
            dwLeft++;
            continue;
        }
        DWORD dwSum = 0;
        dwRight = dwConst - dwLeft;
        pbtRight = (BYTE*)&dwRight;

        ary_btTmp[4] = (pbtRight[0] ^ 0x66);
        ary_btTmp[5] = (pbtRight[1] ^ 0x66);
        ary_btTmp[6] = (pbtRight[2] ^ 0x66);
        ary_btTmp[7] = (pbtRight[3] ^ 0x66);
        if (ary_btTmp[4] < '0' ||
            ary_btTmp[4] > 'z' ||
            (ary_btTmp[4] > '9' && ary_btTmp[4] < 'A') ||
            (ary_btTmp[4] > 'Z' && ary_btTmp[4] < 'a') ||
            ary_btTmp[5] < '0' ||
            ary_btTmp[5] > 'z' ||
            (ary_btTmp[5] > '9' && ary_btTmp[5] < 'A') ||
            (ary_btTmp[5] > 'Z' && ary_btTmp[5] < 'a') ||
            ary_btTmp[6] < '0' ||
            ary_btTmp[6] > 'z' ||
            (ary_btTmp[6] > '9' && ary_btTmp[6] < 'A') ||
            (ary_btTmp[6] > 'Z' && ary_btTmp[6] < 'a') ||
            ary_btTmp[7] < '0' ||
            ary_btTmp[7] > 'z' ||
            (ary_btTmp[7] > '9' && ary_btTmp[7] < 'A') ||
            (ary_btTmp[7] > 'Z' && ary_btTmp[7] < 'a')) {
            dwLeft++;
            continue;
        }

        dwSum = dwSum + ary_btTmp[0];
        dwSum = dwSum + ary_btTmp[1];
        dwSum = dwSum + ary_btTmp[2];
        dwSum = dwSum + ary_btTmp[3];
        dwSum = dwSum + ary_btTmp[4];
        dwSum = dwSum + ary_btTmp[5];
        dwSum = dwSum + ary_btTmp[6];
        dwSum = dwSum + ary_btTmp[7];
        if (dwSum == 0x325) {
            DWORD dwIndex = 0;
            do {
                DWORD* pdwSocTmp = (DWORD*)g_ary_btSocCodes;
                DWORD* pdwDesTmp = (DWORD*)g_ary_btDesCodes;
                pdwDesTmp[dwIndex] = pdwSocTmp[dwIndex] + dwRight;
                pdwDesTmp[dwIndex] = pdwDesTmp[dwIndex] ^ dwLeft;
                dwIndex++;
            } while (dwIndex < 10);
            bool isRight = false;
            dwIndex = 0;
            do {
               
                if (g_ary_btDesCodes[dwIndex] == 0xFF) {
                    isRight = true;
                }
                dwIndex++;
            } while (dwIndex < 40);
            if (isRight) {
                dwIndex = 0;
                do {
                    
                    if ((dwIndex < 38 &&
                        g_ary_btDesCodes[dwIndex] == 0x19 &&
                        g_ary_btDesCodes[dwIndex +1] == 0x3b &&
                        g_ary_btDesCodes[dwIndex + 2] == 0x40)) {
                        printf("%s\r\n", ary_btTmp);
                    }
                    dwIndex++;
                } while (dwIndex < 40);
            }
            
            
            DWORD dwTmp = 0;
        }
        dwLeft++;
    } while (dwLeft < dwConst);

}

int main(int argc, char* argv[])
{
        backToGood();
        return 0;
}

找到这个比较小的解集,手动输入验证吧。。。,边听着小说边试,最终找到了这个KAhuskey会弹good!

上传的附件:
收藏
免费 1
支持
分享
最新回复 (1)
雪    币: 9
活跃值: (175)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
2
知己知彼,有的放矢!
2016-12-31 15:59
0
游客
登录 | 注册 方可回帖
返回
//