吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 7412|回复: 38
收起左侧

[CTF] 百度杯CTF比赛 2017 二月场 Project

  [复制链接]
DCO 发表于 2018-10-22 20:49
本帖最后由 DCO 于 2018-10-22 21:01 编辑

这是很早之前的CTF比赛,已经有大佬发过WP了。最近一直拿各种CM练习,硬盘里存了一些分析笔记,也没好意思发出来,毕竟别人已经写过,总有种拾人牙慧的嫌疑。
就当是自己学习的记录吧,感谢那些曾经帮到过我的分享文章。拿出来或许还会帮到一些像我一样的小白,因为某个点过不去而苦苦思索的,到处寻求帮助。共勉!
代码风格比较乱,可能有些地方说的也不太正确,若有大佬发现,谢谢指正!

流程分析

跟踪发现,有一个作者自己添加的异常

.text:0040154E                 int     3

向上找SHE异常处理的回调。下列代码在栈中构造一个EXCEPTION_REGISTRATION结构

.text:00401440 sub_401440      proc near
.text:00401440 var_1C          = dword ptr -1Ch
.text:00401440 ms_exc          = CPPEH_RECORD ptr -18h
.text:00401440
.text:00401440 ; __unwind { // __except_handler4
.text:00401440                 push    ebp
.text:00401441                 mov     ebp, esp
.text:00401443                 push    0FFFFFFFEh
.text:00401445                 push    offset stru_407F78
.text:0040144A                 push    offset __except_handler4
.text:0040144F                 mov     eax, large fs:0
.text:00401455                 push    eax
.text:00401456                 sub     esp, 0Ch
.text:00401459                 push    ebx
.text:0040145A                 push    esi
.text:0040145B                 push    edi
.text:0040145C                 mov     eax, ___security_cookie
.text:00401461                 xor     [ebp+ms_exc.registration.ScopeTable], eax
.text:00401464                 xor     eax, ebp
.text:00401466                 push    eax
.text:00401467                 lea     eax, [ebp+ms_exc.registration]
.text:0040146A                 mov     large fs:0, eax

就在__except_handler4回调函数哪里下断点,异常触发后来到这里,有一个回到用户代码

738EACEC  - FFE6       jmp esi      ; Project1.00401485

跟踪几次来到sub_404BA0,这里就开始验证输入了

变形MD5

下面这段就是变形的MD5,其实就是把Magic Number给修改了
输入的Key经过变形的MD5计算的结果与预定义的值进行比较,不同就ExitProcess()。
预定义的MD5结果是:0FCh, 0E4h, 0AAh, 83h, 0E4h, 0ABh, 0E9h, 0Dh, 0D0h

.text:00404C1A                 mov     edx, g_szKey
.text:00404C20                 lea     ecx, [ebp+var_E0]
.text:00404C26                 push    esi             ; key_len
.text:00404C27                 mov     [ebp+var_DC], 0
.text:00404C31                 mov     [ebp+var_E0], 0
.text:00404C3B                 mov     [ebp+var_D8], 76543210h
.text:00404C45                 mov     [ebp+var_D4], 0FEDCBA98h
.text:00404C4F                 mov     [ebp+var_D0], 89ABCDEFh
.text:00404C59                 mov     [ebp+var_CC], 1234567h   ;注意Magic number并不是标准的
.text:00404C63                 call    sub_4058F0
.text:00404C68                 add     esp, 4
.text:00404C6B                 lea     ecx, [ebp+var_E0]
.text:00404C71                 call    sub_4059B0      ; 内部有MD5计算
.text:00404C76                 xor     esi, esi
.text:00404C78                 nop     dword ptr [eax+eax+00000000h]
.text:00404C80
.text:00404C80 loc_404C80:                             ; CODE XREF: sub_404BA0+FB↓j
.text:00404C80                 mov     al, [ebp+esi+var_88]
.text:00404C87                 cmp     al, ds:byte_407690[esi]
.text:00404C8D                 jz      short loc_404C97
.text:00404C8F                 push    0               ; _DWORD
.text:00404C91                 call    ExitProcess
.text:00404C97
.text:00404C97 loc_404C97:                             ; CODE XREF: sub_404BA0+ED↑j
.text:00404C97                 inc     esi
.text:00404C98                 cmp     esi, 10h
.text:00404C9B                 jl      short loc_404C80

其实没必要纠结这部分,在进行算法分析时直接修改跳转跳过即可,因为不是标准的MD5,所以仅存的希望“MD5在线解密”也破灭了
等到最后分析出真正的Key后,可以再来验证这一部分

另类迷宫分析

变形MD5验证之后就是关键验证算法了
代码的大致功能:

  1. 输入的key字符串,每2个字符为一组
  2. 每组的第一个字符只能是”TVWX”,这4个字符是方向
  3. 每组的第二个字符,只能是“BCDFGHJKMPQRTVWXY2346789”中的一个,该字符距离字符串最后一个字符“9”的距离表示向某个方向移动的值(和矩阵坐标相关)
  4. 最终验证通过的条件是两个全局标志位g_byte == 0x36 && g_nFlag == 0x10F
.text:00404820 StartAddress    proc near
.text:00404820
.text:00404820 i               = dword ptr -8
.text:00404820 nLocation       = byte ptr -1
.text:00404820 lpThreadParameter= dword ptr  8
.text:00404820
.text:00404820                 push    ebp
.text:00404821                 mov     ebp, esp
.text:00404823                 sub     esp, 0Ch
.text:00404826                 push    ebx
.text:00404827                 push    esi
.text:00404828                 push    edi
.text:00404829                 push    eax
.text:0040482A                 push    ebp
.text:0040482B                 mov     ebp, esp
.text:0040482D                 push    0
.text:0040482F                 push    0FFEEFFEEh
.text:00404834                 push    0EEFFEEFFh
.text:00404839                 mov     eax, large fs:0
.text:0040483F                 push    eax
.text:00404840                 mov     large fs:0, esp
.text:00404847                 pop     eax
.text:00404848                 mov     large fs:0, eax
.text:0040484E                 pop     eax
.text:0040484F                 pop     eax
.text:00404850                 pop     eax
.text:00404851                 test    eax, eax
.text:00404853                 jz      short loc_404857
.text:00404855                 inc     ebx
.text:00404857
.text:00404857 loc_404857:
.text:00404857                 pop     eax
.text:00404858                 mov     ebp, eax
.text:0040485A                 pop     eax
.text:0040485B                 mov     esi, g_szKey
.text:00404861                 xor     ebx, ebx
.text:00404863                 mov     ecx, esi
.text:00404865                 mov     [ebp+nLocation], 0
.text:00404869                 mov     [ebp+i], ebx    ; 计数
.text:0040486C                 lea     edx, [ecx+1]
.text:0040486F                 nop
.text:00404870
.text:00404870 loc_404870:
.text:00404870                 mov     al, [ecx]
.text:00404872                 inc     ecx
.text:00404873                 test    al, al
.text:00404875                 jnz     short loc_404870
.text:00404877                 sub     ecx, edx        ; strlen(key)
.text:00404879                 jz      loc_4049A3
.text:0040487F                 nop
.text:00404880
.text:00404880 loc_404880:
.text:00404880                 lea     edi, [esi+ebx]  ; ebx用来计数
.text:00404883                 xor     esi, esi
.text:00404885
.text:00404885 loc_404885:
.text:00404885                 movsx   eax, byte ptr [edi+esi*2]
.text:00404889                 push    eax             ; Val
.text:0040488A                 push    offset Str      ; "BCDFGHJKMPQRTVWXY2346789"
.text:0040488F                 call    ds:strchr
.text:00404895                 movsx   ecx, byte ptr [edi+esi*2+1]
.text:0040489A                 mov     ebx, eax
.text:0040489C                 push    ecx             ; Val
.text:0040489D                 push    offset Str      ; "BCDFGHJKMPQRTVWXY2346789"
.text:004048A2                 call    ds:strchr
.text:004048A8                 add     esp, 10h
.text:004048AB                 mov     ecx, eax
.text:004048AD                 test    ebx, ebx
.text:004048AF                 jz      short loc_4048D2
.text:004048B1                 test    ecx, ecx
.text:004048B3                 jz      short loc_4048D2
.text:004048B5                 mov     eax, offset Str ; "BCDFGHJKMPQRTVWXY2346789"
.text:004048BA                 sub     bl, al          ; 距离第一个元素的距离
.text:004048BC                 mov     eax, (offset Str+17h) ; "9"
.text:004048C1                 sub     al, cl          ; 距离最后一个元素的距离
.text:004048C3                 shl     bl, 4
.text:004048C6                 or      bl, al
.text:004048C8                 mov     [ebp+esi+nLocation], bl
.text:004048CC                 inc     esi
.text:004048CD                 cmp     esi, 1
.text:004048D0                 jb      short loc_404885 ; 就执行1次,但不知道编译器怎么给搞成循环了
.text:004048D2
.text:004048D2 loc_4048D2:
.text:004048D2
.text:004048D2                 movzx   eax, [ebp+nLocation]
.text:004048D6                 mov     bl, [ebp+nLocation]
.text:004048D9                 shr     eax, 4
.text:004048DC                 and     bl, 0Fh
.text:004048DF                 add     eax, 0FFFFFFF4h ; switch 4 cases
.text:004048E2                 cmp     eax, 3
.text:004048E5                 ja      loc_40496A      ; ja比较两个无符号数
.text:004048EB                 jmp     ds:off_4049CC[eax*4] ; switch jump
.text:004048F2 ; ---------------------------------------------------------------------------
.text:004048F2
.text:004048F2 case_2:
.text:004048F2
.text:004048F2                 mov     cl, bl
.text:004048F4                 call    sub_404B00
.text:004048F9                 jmp     short loc_404972
.text:004048FB ; ---------------------------------------------------------------------------
.text:004048FB
.text:004048FB case_0:
.text:004048FB
.text:004048FB                 mov     cl, bl
.text:004048FD                 call    sub_404AA0
.text:00404902                 jmp     short loc_404972
.text:00404904 ; ---------------------------------------------------------------------------
.text:00404904
.text:00404904 case_1:
.text:00404904
.text:00404904                 push    eax
.text:00404905                 add     esp, 2   ; 这种堆栈的处理,感觉像是函数内联了,case_1和case_3都有
.text:00404908                 mov     eax, esp
.text:0040490A                 sub     eax, 2
.text:0040490D                 nop
.text:0040490E                 mov     esp, eax
.text:00404910                 pop     eax
.text:00404911                 mov     edx, g_nFlag
.text:00404917                 movzx   eax, bl
.text:0040491A                 sub     edx, eax
.text:0040491C                 jmp     short loc_404936
.text:0040491E ; ---------------------------------------------------------------------------
.text:0040491E
.text:0040491E case_3:
.text:0040491E
.text:0040491E                 push    eax
.text:0040491F                 add     esp, 2
.text:00404922                 mov     eax, esp
.text:00404924                 sub     eax, 2
.text:00404927                 nop
.text:00404928                 mov     esp, eax
.text:0040492A                 pop     eax
.text:0040492B                 mov     edx, g_nFlag
.text:00404931                 movzx   eax, bl
.text:00404934                 add     edx, eax
.text:00404936
.text:00404936 loc_404936:
.text:00404936                 movzx   eax, ds:g_szBuf_1[edx]
.text:0040493D                 movzx   ecx, ds:g_szBuf_2[edx]
.text:00404944                 add     g_byte, bl
.text:0040494A                 xor     ecx, eax
.text:0040494C                 movzx   eax, ds:g_szBuf_3[edx]
.text:00404953                 sub     ecx, eax
.text:00404955                 mov     g_nFlag, edx
.text:0040495B                 movzx   eax, ds:g_szBuf_4[edx]
.text:00404962                 sub     ecx, eax        ; _DWORD
.text:00404964                 jnz     short loc_40496A
.text:00404966                 test    bl, bl
.text:00404968                 jnz     short loc_404978
.text:0040496A
.text:0040496A loc_40496A:
.text:0040496A
.text:0040496A                 push    0
.text:0040496C                 call    ExitProcess
.text:00404972
.text:00404972 loc_404972:
.text:00404972
.text:00404972                 mov     edx, g_nFlag
.text:00404978
.text:00404978 loc_404978:
.text:00404978                 mov     esi, g_szKey
.text:0040497E                 mov     eax, esi
.text:00404980                 mov     ebx, [ebp+i]
.text:00404983                 add     ebx, 2
.text:00404986                 mov     [ebp+i], ebx
.text:00404989                 lea     edi, [eax+1]
.text:0040498C                 nop     dword ptr [eax+00h]
.text:00404990
.text:00404990 loc_404990:
.text:00404990                 mov     cl, [eax]
.text:00404992                 inc     eax
.text:00404993                 test    cl, cl
.text:00404995                 jnz     short loc_404990
.text:00404997                 sub     eax, edi        ; strlen(key)
.text:00404999                 cmp     ebx, eax
.text:0040499B                 jb      loc_404880
.text:004049A1                 jmp     short loc_4049A9
.text:004049A3 ; ---------------------------------------------------------------------------
.text:004049A3
.text:004049A3 loc_4049A3:
.text:004049A3                 mov     edx, g_nFlag
.text:004049A9
.text:004049A9 loc_4049A9:
.text:004049A9                 cmp     g_byte, 36h
.text:004049B0                 jnz     short loc_4049BA
.text:004049B2                 cmp     edx, 10Fh
.text:004049B8                 jz      short loc_4049C2
.text:004049BA
.text:004049BA loc_4049BA:
.text:004049BA                 push    0               ; _DWORD
.text:004049BC                 call    ExitProcess
.text:004049C2
.text:004049C2 loc_4049C2:
.text:004049C2                 pop     edi
.text:004049C3                 pop     esi
.text:004049C4                 pop     ebx
.text:004049C5                 mov     esp, ebp
.text:004049C7                 pop     ebp
.text:004049C8                 retn
.text:004049C8 StartAddress    endp
.text:004049C8
.text:004049C8 ; ---------------------------------------------------------------------------
.text:004049C9                 align 4
.text:004049CC off_4049CC      dd offset case_0        ; DATA XREF: StartAddress+CB↑r
.text:004049CC                 dd offset case_1        ; jump table for switch statement
.text:004049CC                 dd offset case_2
.text:004049CC                 dd offset case_3
.text:004049DC                 align 10h

本来偷懒打算看F5代码的,但是F5代码甚是费解,索性就一行一行的手撸汇编,还原为C吧,就当练习了
这个矩阵的维数也是在逆向中结合全局数组的元素个数和移动关系,一步一步的看出来的
有4个全局的二维数组[17][17],按照一定的规则进行运算可以得到迷宫地图

//BCDFGHJKMPQRTVWXY2346789
//TVWX   这4个字符是方向
BOOL CheckKey()
{
        char szBuf[] = "BCDFGHJKMPQRTVWXY2346789";
        int nLocation = 0;
        int nTmp = 0;
        int nIndex = 0;
        int nBegLen = 0;
        int nEndLen = 0;
        char szTmp[4] = { 0 };

        int nKeyLen = strlen(g_szKey);
        int nBufLen = strlen(szBuf);

        for (int i = 0; i < nKeyLen; i += 2)
        {
                szTmp[0] = g_szKey[i];
                char *pRetA = strstr(szBuf, szTmp);
                szTmp[0] = g_szKey[i + 1];
                char *pRetB = strstr(szBuf, szTmp);
                if (pRetA && pRetB)
                {
                        nBegLen = pRetA - szBuf;                 //距离第一个元素的距离
                        nEndLen = &szBuf[nBufLen - 1] - pRetB;   //距离最后一个元素的距离
                }
                nBegLen -= 12;
                switch (nBegLen)
                {
                case 0:   //T
                        MoveDown(nEndLen);
                        break;
                case 1:   //V
                        MoveLeft(nEndLen);
                        break;
                case 2:   //W
                        MoveUp(nEndLen);
                        break;
                case 3:   //X
                        MoveRight(nEndLen);
                        break;
                default:
                        ExitProcess(0);
                }
        }
        if (g_byte != 0x36 || g_nFlag != 0x10F)
        {
                ExitProcess(0);
        }
        return TRUE;
}
/*
左移
*/
void MoveLeft(int nNum)
{
        g_byte += nNum;
        g_nFlag -= nNum;

        int i = g_nFlag / 17;
        int j = g_nFlag % 17;

        char chRet = (g_szBuf_1[i][j] ^ g_szBuf_2[i][j]) - g_szBuf_3[i][j] - g_szBuf_4[i][j];

        if (chRet || !nNum)
        {
                ExitProcess(0);
        }
}
/*
右移
*/
void MoveRight(int nNum)
{
        g_byte += nNum;
        g_nFlag += nNum;

        int i = g_nFlag / 17;
        int j = g_nFlag % 17;

        char chRet = (g_szBuf_1[i][j] ^ g_szBuf_2[i][j]) - g_szBuf_3[i][j] - g_szBuf_4[i][j];

        if (chRet || !nNum)
        {
                ExitProcess(0);
        }
}
/*
下移
*/
void MoveDown(int nNum)
{
        g_byte += nNum;
        g_nFlag += nNum * 17;

        int i = g_nFlag / 17;
        int j = g_nFlag % 17;

        char chRet = (g_szBuf_1[i][j] ^ g_szBuf_2[i][j]) - g_szBuf_3[i][j] - g_szBuf_4[i][j];

        if (chRet || !nNum)
        {
                ExitProcess(0);
        }
}
/*
上移
*/
void MoveUp(int nNum)
{
        g_byte += nNum;
        g_nFlag -= nNum * 17;

        int i = g_nFlag / 17;
        int j = g_nFlag % 17;

        char chRet = (g_szBuf_1[i][j] ^ g_szBuf_2[i][j]) - g_szBuf_3[i][j] - g_szBuf_4[i][j];

        if (chRet || !nNum)
        {
                ExitProcess(0);
        }
}

生成Map

通过验证成功的条件为0,可以逆推出地图

char chRet = (g_szBuf_1[i][j] ^ g_szBuf_2[i][j]) - g_szBuf_3[i][j] - g_szBuf_4[i][j];

生成地图的C代码:

void GetMap()
{
        char chRet = 0;
        printf("地图:\r\n");
        for (int i = 0; i < 17; ++i)
        {
                for (int j = 0; j < 17; ++j)
                {
                        chRet = (g_szBuf_1[i][j] ^ g_szBuf_2[i][j]) - g_szBuf_3[i][j] - g_szBuf_4[i][j];
                        if (!chRet)
                        {
                                printf("  ");   //路
                                g_Map[i][j] = 1;
                        }
                        else
                        {
                                printf("■");   //墙
                        }

                }
                printf("\r\n");
        }
}

生成的地图如下所示,从左上角的那个入口,到右下角的那个出口,走法就是Key,
1.png

逆推Key序列

当时把C代码撸出来,感觉这个迷宫有点别致。普通的迷宫都是上下左右4个方向,每次只能走一步,这个好像一次可以走好几步,比如一次向左移动5位……这种操作
按照这个思路来逆推key就麻烦了,搞了好久也不知道该如何写
后来实在没招了,就参考了别人的wp。才发现时我想多了,可以先把它当做每次只能移动一步的迷宫,后续再把连续相同方向的移动合并就可以了
参考WP:https://blog.csdn.net/kevin66654/article/details/58585538
具体的实现代码就放到附件中吧,这里就不放了

Project.rar

147.61 KB, 下载次数: 18, 下载积分: 吾爱币 -1 CB

点评

欢迎分析讨论交流,吾爱破解论坛有你更精彩!  发表于 2018-10-22 21:31

免费评分

参与人数 10威望 +1 吾爱币 +15 热心值 +10 收起 理由
姚小宝 + 1 + 1 我很赞同!
迷茫1。 + 1 + 1 我很赞同!
笙若 + 1 谢谢@Thanks!
恋上你的傻 + 1 + 1 热心回复!
52lxw + 1 + 1 我很赞同!
zhukai055 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
strongwong + 1 热心回复!
SinCon + 1 + 1 耐心分析师关键
杀猪用牛刀 + 1 + 1 谢谢@Thanks!
Sound + 1 + 8 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Dispa1r 发表于 2018-10-23 17:12
DCO 发表于 2018-10-23 14:21
我当初调试的时候没也注意TLS回掉,OD调时正常跑到Main哪里。我刚才试了一下没发现什么异常,能说一下那 ...

就是在tls结束时,会把eip变成NtQueryProcessInformation查询到的Debugport
(好像是的),然后此时eip指向的地址肯定是无法访问的,就出了这个异常话说楼主有联系方式吗,方便交流
 楼主| DCO 发表于 2018-10-23 22:04
Dispa1r 发表于 2018-10-23 17:12
就是在tls结束时,会把eip变成NtQueryProcessInformation查询到的Debugport
(好像是的),然后此时eip指 ...

刚才看了看TLS回调函数中,是解析DLL,获取一些导出函数的,并没有看到NtQueryProcessInformation之类函数的调用,也可能是碰到我自己的知识盲区了,有些地方分析的不到位
絕° 发表于 2018-10-22 21:07
weidadehao 发表于 2018-10-22 21:14

懵逼的围观!
liuwenxuan 发表于 2018-10-22 21:29


懵逼的围观!
bluexxl 发表于 2018-10-22 21:33
懵逼的围观!
天使3号 发表于 2018-10-22 22:02
你们怎么都懵逼围观,像我们专业人士.....................................好吧,我这个业余人士,也来懵逼围观一下...
xiaowanzi 发表于 2018-10-22 22:08
还是继续回去看书吧。。。
微博橙一呀 发表于 2018-10-22 23:25
我我我……看不懂
gunxsword 发表于 2018-10-22 23:40
历害了!!!!!!!!!
zsa0832 发表于 2018-10-23 00:58
眼花了----
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 13:59

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表