首页
社区
课程
招聘
[原创]看雪CTF2016--23、24、26、27题破文(补)
发表于: 2016-12-27 10:04 3240

[原创]看雪CTF2016--23、24、26、27题破文(补)

2016-12-27 10:04
3240
一下补4题的破文...

25题没做出来,涉及密码学我一般都跪,但多谢HHHso提点找到了突破口,这也便于我解28题,即算法中的常量是加密或解密算法的特征。

不多说了开始进入破文,主要以原理为主

23题爆破点找窗口过程函数的WM_COMMAND消息,断下来有2个函数,第一个是图片识别(看不出来没有关系,看返回结果,他把我们输入的字符等价替换为整数而且呈一一对应关系),第二个函数就是验证函数,验证成功则提示注册成功;

验证函数是分段验证,后面的就是个对比,把整数翻译回来得到IsSerialNumber,而前面只有4位懒得逆推就穷举吧,穷举算法如下:
BYTE ary_btDes[0x4] = "\0";

DWORD backToGood(DWORD dwSoc)
{   
    DWORD dwDes;

    do
    {
        ary_btDes[1] = 0;
        do
        {
            ary_btDes[2] = 0;
            do
            {
                ary_btDes[3] = 0;
                do
                {
                    
                    __asm {
                        mov     esi, offset ary_btDes
                        mov     al, byte ptr [esi]
                        movzx   edx, byte ptr [esi+1]
                        not     al
                        movzx   ecx, byte ptr [esi+2]
                        movzx   eax, al
                        mov     ebx, dword ptr dword_4121C0[eax*4]
                        xor     ebx, 0FFFh
                        movzx   eax, bl
                        xor     edx, eax
                        shr     ebx, 8
                        xor     ebx, dword ptr dword_4121C0[edx*4]
                        movzx   eax, bl
                        xor     ecx, eax
                        shr     ebx, 8
                        xor     ebx, dword ptr dword_4121C0[ecx*4]
                        movzx   ecx, byte ptr [esi+3]
                        movzx   eax, bl
                        xor     ecx, eax
                        shr     ebx, 8
                        xor     ebx, dword ptr dword_4121C0[ecx*4]
                        mov     dwDes, ebx
                    }
                    if (dwDes == ~dwSoc) {
                        char szBuf[0x16] = "\0";
                        char* pTmp = (char*)&dwDes;
                        pTmp[0] = ary_btDes[3];
                        pTmp[1] = ary_btDes[2];
                        pTmp[2] = ary_btDes[1];
                        pTmp[3] = ary_btDes[0];
                        wsprintf(szBuf, "%X", dwDes);
                        MessageBox(NULL, szBuf, szBuf, NULL);
                        return dwDes;
                    }
                    ary_btDes[3]++;
                } while (ary_btDes[3] <= 0x3D);
                ary_btDes[2]++;
            } while (ary_btDes[2] <= 0x3D);
            ary_btDes[1]++;
        } while (ary_btDes[1] <= 0x3D);
        ary_btDes[0]++;
    } while (ary_btDes[0] <= 0x3D);
   
    return dwDes;
}

int main(int argc, char* argv[])
{
    DWORD dwSoc = 0xA466EEEF;
    printf("%X", backToGood(dwSoc));
        return 0;
}

注意dword_4121C0在程序里面找出来,最终得到注册码为thisIsSerialNumber

24题,首先必须是以pediy开头,反正我记得整个sn够长的,下面是逆推的C代码,如下:

BYTE g_ary_btSoc[0x9c] = {
    0x01, 0x04, 0x08, 0x02, 0x04, 0x08, 0x03, 0x04, 0x08, 0x04, 0x04, 0x08, 0x05, 0x04, 0x08, 0x06, 0x04, 0x08, 0x07, 0x04, 0x08, 0x08, 0x04, 0x08, 0x09, 0x04, 0x08, 0x01, 0x04, 0x08, 0x02, 0x04,
    0x08, 0x03, 0x04, 0x08, 0x04, 0x04, 0x08, 0x05, 0x04, 0x08, 0x06, 0x04, 0x08, 0x07, 0x04, 0x08, 0x08, 0x04, 0x08, 0x09, 0x04, 0x08, 0x01, 0x04, 0x08, 0x02, 0x04, 0x08, 0x03, 0x04, 0x08, 0x04,
    0x04, 0x08, 0x05, 0x04, 0x08, 0x06, 0x04, 0x08, 0x07, 0x04, 0x08, 0x08, 0x04, 0x08, 0x09, 0x04, 0x08, 0x01, 0x04, 0x08, 0x02, 0x04, 0x08, 0x03, 0x04, 0x08, 0x04, 0x04, 0x08, 0x05, 0x04, 0x08,
    0x06, 0x04, 0x08, 0x07, 0x04, 0x08, 0x08, 0x04, 0x08, 0x09, 0x04, 0x08, 0x01, 0x04, 0x08, 0x02, 0x04, 0x08, 0x03, 0x04, 0x08, 0x04, 0x04, 0x08, 0x05, 0x04, 0x08, 0x06, 0x04, 0x08, 0x07, 0x04,
    0x08, 0x08, 0x04, 0x08, 0x09, 0x04, 0x08, 0x01, 0x04, 0x08, 0x02, 0x04, 0x08, 0x03, 0x04, 0x08, 0x04, 0x04, 0x08, 0x05, 0x04, 0x08, 0x06, 0x04, 0x08, 0x00, 0x00, 0x00
};

void backToGoodMy(BYTE* pbtDes)
{
    DWORD dwCount = 0;
    DWORD dwCOuntDes = 0;
    BYTE ary_btDes[0x9c];
    while ( dwCount < 0x9c )
    {
        BYTE btTmp = 0;
        if (!(g_ary_btSoc[dwCount] & 0xF0))
            btTmp = 16 * g_ary_btSoc[dwCount];
        else
            int nTmp = 0;
        dwCount++;
        btTmp = (g_ary_btSoc[dwCount] | btTmp);

        ary_btDes[dwCount - 1] = ((btTmp >> 4) + 48);
        ary_btDes[dwCount - 1] = ary_btDes[dwCount - 1] ^ 0x86;
        ary_btDes[dwCount] = ((btTmp & 0x0F) + 48);
        ary_btDes[dwCount] = ary_btDes[dwCount] ^ 0x86;
        ++dwCount;
    }

    dwCount = 0;
    dwCOuntDes = 0;
    while (dwCOuntDes < 0x9c * 2) {
        pbtDes[dwCOuntDes] = ary_btDes[dwCount] >> 4;
        pbtDes[dwCOuntDes + 1] = ary_btDes[dwCount] & 0x0F;
        if (pbtDes[dwCOuntDes]  > 9) {
            pbtDes[dwCOuntDes] = 55 + pbtDes[dwCOuntDes];
        } else {
            pbtDes[dwCOuntDes] = 48 + pbtDes[dwCOuntDes];
        }
        
        if (pbtDes[dwCOuntDes + 1]  > 9) {
            pbtDes[dwCOuntDes + 1] = 55 + pbtDes[dwCOuntDes + 1];
        } else {
            pbtDes[dwCOuntDes + 1] = 48 + pbtDes[dwCOuntDes + 1];
        }

        dwCOuntDes++;
        dwCOuntDes++;
        dwCount++;
    }
}

int main(int argc, char* argv[])
{
    BYTE ary_btDes[0x9c * 2];
    backToGoodMy(ary_btDes);
       
        return 0;
}

算出来的结果保存在ary_btDes中,拼上pediy就得到正确的sn了pediyB7B2BEB4B2BEB5B2BEB2B2BEB3B2BEB0B2BEB1B2BEBEB2BEBFB2BEB7B2BEB4B2BEB5B2BEB2B2BEB3B2BEB0B2BEB1B2BEBEB2BEBFB2BEB7B2BEB4B2BEB5B2BEB2B2BEB3B2BEB0B2BEB1B2BEBEB2BEBFB2BEB7B2BEB4B2BEB5B2BEB2B2BEB3B2BEB0B2BEB1B2BEBEB2BEBFB2BEB7B2BEB4B2BEB5B2BEB2B2BEB3B2BEB0B2BEB1B2BEBEB2BEBFB2BEB7B2BEB4B2BEB5B2BEB2B2BEB3B2BEB0B2BEB6B6B6

26题,和我自己的题思路很像,大家同门调试器是必写项目。。。

但相对来说不是太复杂,这题关键还是复原代码,大体结构分为
1.输入sn后首先在调试器中加密一次,
2.然后启动被调试程序并挂起,将加密后的sn和一段实现准备好的字节码写入被调试程序
3.修改EIP到写入的字节码位置,恢复被调试程序主线程
4.int3断点第1次来是系统断点,第2次来就是写入的字节码中间产生,这里把加号修改成为了减号
5.第3次断点就是最终验证

加密程序有2段,一段在调试器中,一段在被调试程序中,dump出来注意加号的位置,由于其是逐位加密,穷举发现第一位怎么都不是EF,后来通过hook原程序,才发现k、h等可以得到EF,但是除了k外其他的后面的加密数据就不对了。

这题的算法存在漏洞,都用第一位加密,而且其他位去撞加密库没撞到就用固定数值,那只要其他位是无法撞加密库成功的数据就可以验证成功,这也是其多解的原因

另外,为什么第一位加密后是EF,这个原因我没分析,HHHso做了详细分析,建议大家去认真看下,这也是个以后可以用到的招数

sn就不列举了第一位是k其他位全1好像就行

27题,没法找到爆破点,后来发现他写一个内存地址,然后跳到那去运行,那这个程序应该是加密了字节码,然后解密成功后也就是那段字节码提示成功,但是当我随便输入一个够位长的数据后3j1l2njlfjl发现验证成功了。。。

这题也就破解了,分析原因是由于其解密逐位字符多个异或,多个异或如果字符不是足够特殊的话,可以不同字符得到同一结果的,这也是其多解的原因

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//