AmazingMFC.exe

发布者:Re_Upper
发布于:2022-10-31 19:22

AmazingMFC.exe

第4届四川省网络空间安全大赛-Re-初赛
链接:https://pan.baidu.com/s/1EloxPLfkjCthhkMtrf1McQ
提取码:D0g3

 

1). 直接运行, 一波乱点击

  • 每次点击一个flag按钮,都会弹窗让你输入,输入为空也好,不为空也罢,都会原封不动的显示你的输入
    图片描述
    图片描述

  • 仔细发现
    你点击倒数第2个按钮,他的显示不一样,别人输错显示Oops,Nothing
    而倒数第二个显示Oops,有点不同
    图片描述

    这说明了啥? CTFer要观察仔细呀~我只想说TMD

  • 你每点击一个按钮,她都会显示一个字符串,看上去像Base64,加密算法千千万,试几下就可以了,不是BAse64也别伤心
    不过你无法直接copy字符串,然后解密,得去IDA搜索字符串,然后copy
    如果你去Base64解密了,然后解密到了倒数第二个,发现解密的结果是F14g here here,所以flag的获取和倒数第二个有关
    问题来了?怎么找到倒数第二个的窗口处理函数?

2). 拖进Die,看看有什么
发现没什么坑,是一个PE32的文件不过,有TLS
涉及了3个TLS函数的地址,去IDA查看了一下,

1
2
3
0x005512C4
0x0055D241
0x00552A22

也没过多的TLS分析,没看出啥坑,可能对解题有所影响,但是最后没啥影响
可能TLS是自带的,用于清理或者初始化

 

3).然后就IDA调试
F9就退出,说明有反调试
一般的话,我可以想到的退出方式

1
2
3
exit(-1)
TerminalProcess()
ExitProcess()

于是就去xdbg看一下AmazingMFC.exe调用了哪些API,其实就去看一下有没有退出函数
下面是对应API调用的位置

1
2
3
4
5
6
7
8
9
10
TerminalProcess()
0x00540D34
0x005474B2
0x0055044B
 
ExitProcess()
0x0040328F
0x00403E10
0x004045F5
0x0055045D

于是就去对应地址和对应地方看这些调用,然后在可能退出的地方下断点,也没多少个退出函数,就在调用之前都下一个断点

 

图片描述

 

于是下断电,F9,然后对应地方F9,看看会不会执行退出函数,如果执行了,那就修改流程,如果没有执行退出函数就不管

 

当然会执行退出函数
于是你可以在修改 标志寄存器,IP地址,修改汇编指令 来不退出
我退出调试,就修改jz为jnz,然乎保存到文件里面去(注意备份一下源文件)
然后F9调试,就再也不会退出了

 

问题:怎么定位函数?
1). 函数的交叉引用,比如哪些函数都调用了相同的API
2). 利用字符串的调用,我不过多的赘述(不是很行得通)
疑惑
字符串Oops, nothing!被9次调用,能理解,但是字符串Oops在IDA里面看不到谁调用了它

 

正在的flag函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
DlgItem = CWnd::GetDlgItem(this, -1);
  CWnd::SetWindowTextA(DlgItem, "RjE0ZyBoZXJlIGhlcmU=");// F14g here here
  strcpy(Source, "CFTDSA|6470*\"c*a6eaa>2fz");
  sub_401C40(0xD8u);
  sub_4045A0((int)v10, 0);
  v15 = 0;
  CDialog::DoModal((CDialog *)v10);             // 弹窗喊你输入的函数
  sub_404300(v11);
  v8 = std::_Ptr_base<_EXCEPTION_RECORD const>::get((char *)this + 208);
  v7 = sub_403D20(v8);//v8是指针,指向了输入的字符串,这里是第一个flag校验函数,内含有花指令
  BeingDebugged = 0;
  BeingDebugged = NtCurrentPeb()->BeingDebugged;
  if ( v7 != 0xF1BFF95A || BeingDebugged )//如果你在调试或者你的flag校验值不为0xF1BFF95A,就死翘翘
  {
    v5 = (const CHAR *)std::_Ptr_base<_EXCEPTION_RECORD const>::get((char *)this + 208);
    CWnd::MessageBoxA(this, v5, "Oops", 0);
  }
  else //正常情况下,输出的函数
  {
    v2 = std::_Ptr_base<_EXCEPTION_RECORD const>::get((char *)this + 208);
    *((_DWORD *)this + 53) = sub_548134(v3, v2);
    sub_401C40(4u);
    sub_401FF0(&v12);
    LOBYTE(v15) = 1;
    sub_403E30(Source);//解密字符串6470*\"c*a6eaa>2fz的函数,也有花指令,去掉花之后,还要去掉一个异常
    sub_402E40((int)&v12, Source, *((_DWORD *)this + 53));
    v4 = (const CHAR *)std::_Ptr_base<_EXCEPTION_RECORD const>::get(&v12);
    CWnd::MessageBoxA(this, v4, "Oops", 0);
    LOBYTE(v15) = 0;
    sub_4030C0(&v12);
  }
  v15 = -1;
  return sub_404660();
}

另外一个去花是同理的
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 

涉及的花指令类型是一致的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.text:00403D29 E8 01 00 00 00                          call    loc_403D2F
.text:00403D29                         ; ---------------------------------------------------------------------------
.text:00403D2E 84                                      db 84h
.text:00403D2F                         ; ---------------------------------------------------------------------------
.text:00403D2F
.text:00403D2F                         loc_403D2F:                             ; CODE XREF: sub_403D20+9↑j
.text:00403D2F                                         db      36h
.text:00403D2F 36 83 04 24 08                          add     [esp+18h+var_18], 8
.text:00403D34 C3                                      retn
.text:00403D34                         sub_403D20      endp ; sp-analysis failed
.text:00403D34
.text:00403D34                         ; ---------------------------------------------------------------------------
.text:00403D35 F2                                      db 0F2h
.text:00403D36                         ; ---------------------------------------------------------------------------
.text:00403D36 C7 45 FC 37 25 00 00                    mov     dword ptr [ebp-4], 2537h
.text:00403D3D

执行 call loc_403D2F 等价于 push 0x00403D2E
然后 add [esp+18h+var_18], 8 等价于 0x00403D2E+8
所以栈里面的IP就变为了0x00403D2E+8=0x00403D36
然后ret 等价于 ip=0x00403D36
所以你需要干的是
把下面的nop掉

1
2
3
4
5
6
7
8
9
10
11
12
13
E8 01 00 00 00                          call    loc_403D2F
.text:00403D29                         ; ---------------------------------------------------------------------------
.text:00403D2E 84                                      db 84h
.text:00403D2F                         ; ---------------------------------------------------------------------------
.text:00403D2F
.text:00403D2F                         loc_403D2F:                             ; CODE XREF: sub_403D20+9↑j
.text:00403D2F                                         db      36h
.text:00403D2F 36 83 04 24 08                          add     [esp+18h+var_18], 8
.text:00403D34 C3                                      retn
.text:00403D34                         sub_403D20      endp ; sp-analysis failed
.text:00403D34
.text:00403D34                         ; ---------------------------------------------------------------------------
.text:00403D35 F2                                      db 0F2h

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
IDC脚本
其中一个去掉花的IDC脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <idc.idc>
static main()
{
    auto x,FBin,ProcRange;
    FBin = "E8 01 00 00 00 84 36 83 04 24 08 C3 F2";//目标操作码
    for (x = FindBinary(MinEA(),0x03,FBin);x != BADADDR;x = FindBinary(x,0x03,FBin))
    {
        //起点
        PatchDword(x,0x90909090);//90 90 90 90 00 84 36 83 04 24 08 C3 F2
        x=x+4;
        PatchDword(x,0x90909090);//90 90 90 90 90 90 90 90 04 24 08 C3 F2
        x=x+4;
        PatchDword(x,0x90909090);//90 90 90 90 90 90 90 90 90 90 90 90 F2
        x=x+4;
        PatchByte (x,0x90);//90 90 90 90 90 90 90 90 90 90 90 90 90
    }
}

然后鼠标框住push ebp 一直到ret,然后U一下,也就是取消之前IDA的分析
然后框住0x55~0xC3,然后C一下,点击强制分析,也就睡重新生成汇编代码
然后框住push ebp,一直到ret,然后P一下,也就是重新形成函数
就得到

1
2
3
4
5
6
7
8
9
10
11
12
13
int __cdecl sub_403D20(unsigned __int8 *a1)
{
  int v2; // [esp+10h] [ebp-8h]
  int i; // [esp+14h] [ebp-4h]
 
  for ( i = 9527; ; i = v2 + 33 * i )
  {
    v2 = *a1++;
    if ( !v2 )
      break;
  }
  return i;
}

解密的Python如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
flag1=''
flag2=''
enc = b'CFTDSA|6470*\"c*a6eaa>2fz'
 
for i in range(24):
    flag1+=chr(enc[i]^7)
 
bignum=[0]*8
 
for bignum[0] in range(0x30,0x39):
    for bignum[1] in range(0x30, 0x39):
        for bignum[2] in range(0x30, 0x39):
            for bignum[3] in range(0x30, 0x39):
                for bignum[4] in range(0x30, 0x39):
                    for bignum[5] in range(0x30, 0x39):
                        for bignum[6] in range(0x30, 0x39):
                            for bignum[7] in range(0x30, 0x39):
                                num=9527
                                for i in range(8):
                                    tmp=bignum[i]
                                    num=tmp +33*num
                                if(num&0xffffffff==0xF1BFF95A):
                                    for i in range(8):
                                        flag2+=chr(bignum[i])
                                    flag=flag1.replace("%d",flag2)
                                    print(flag)
                                    exit(0)
 
#DASCTF{1307-23075657-f1bff95a}

wp
声明:该文观点仅代表作者本人,转载请注明来自看雪