• BUUCTF 刮开有奖 WriteUp


    题目链接

    https://buuoj.cn/challenges#%E5%88%AE%E5%BC%80%E6%9C%89%E5%A5%96

    题解

    用IDA打开,按F5反编译,双击进入DialogFunc函数。

    1

    代码如下:

      1 BOOL __stdcall DialogFunc(HWND hDlg, UINT a2, WPARAM a3, LPARAM a4)
      2 {
      3   const char *v4; // esi
      4   const char *v5; // edi
      5   int v7; // [esp+8h] [ebp-20030h]
      6   int v8; // [esp+Ch] [ebp-2002Ch]
      7   int v9; // [esp+10h] [ebp-20028h]
      8   int v10; // [esp+14h] [ebp-20024h]
      9   int v11; // [esp+18h] [ebp-20020h]
     10   int v12; // [esp+1Ch] [ebp-2001Ch]
     11   int v13; // [esp+20h] [ebp-20018h]
     12   int v14; // [esp+24h] [ebp-20014h]
     13   int v15; // [esp+28h] [ebp-20010h]
     14   int v16; // [esp+2Ch] [ebp-2000Ch]
     15   int v17; // [esp+30h] [ebp-20008h]
     16   CHAR String; // [esp+34h] [ebp-20004h]
     17   char v19; // [esp+35h] [ebp-20003h]
     18   char v20; // [esp+36h] [ebp-20002h]
     19   char v21; // [esp+37h] [ebp-20001h]
     20   char v22; // [esp+38h] [ebp-20000h]
     21   char v23; // [esp+39h] [ebp-1FFFFh]
     22   char v24; // [esp+3Ah] [ebp-1FFFEh]
     23   char v25; // [esp+3Bh] [ebp-1FFFDh]
     24   char v26; // [esp+10034h] [ebp-10004h]
     25   char v27; // [esp+10035h] [ebp-10003h]
     26   char v28; // [esp+10036h] [ebp-10002h]
     27 
     28   if ( a2 == 272 )
     29     return 1;
     30   if ( a2 != 273 )
     31     return 0;
     32   if ( (_WORD)a3 == 1001 )
     33   {
     34     memset(&String, 0, 0xFFFFu);
     35     GetDlgItemTextA(hDlg, 1000, &String, 0xFFFF);
     36     if ( strlen(&String) == 8 )
     37     {
     38       v7 = 90;
     39       v8 = 74;
     40       v9 = 83;
     41       v10 = 69;
     42       v11 = 67;
     43       v12 = 97;
     44       v13 = 78;
     45       v14 = 72;
     46       v15 = 51;
     47       v16 = 110;
     48       v17 = 103;
     49       sub_4010F0((int)&v7, 0, 10);
     50       memset(&v26, 0, 0xFFFFu);
     51       v26 = v23;
     52       v28 = v25;
     53       v27 = v24;
     54       v4 = sub_401000((int)&v26, strlen(&v26));
     55       memset(&v26, 0, 0xFFFFu);
     56       v27 = v21;
     57       v26 = v20;
     58       v28 = v22;
     59       v5 = sub_401000((int)&v26, strlen(&v26));
     60       if ( String == v7 + 34
     61         && v19 == v11
     62         && 4 * v20 - 141 == 3 * v9
     63         && v21 / 4 == 2 * (v14 / 9)
     64         && !strcmp(v4, "ak1w")
     65         && !strcmp(v5, "V1Ax") )
     66       {
     67         MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0);
     68       }
     69     }
     70     return 0;
     71   }
     72   if ( (_WORD)a3 != 1 && (_WORD)a3 != 2 )
     73     return 0;
     74   EndDialog(hDlg, (unsigned __int16)a3);
     75   return 1;
     76 }

    35行读取输入,36行说明flag长度为8。

    进入49行的sub_4010F0函数,并修改为可以运行的C语言格式。代码如下:

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 int __cdecl sub_4010F0(char *a1, int a2, int a3) // int a1
      4 {
      5   int result; // eax
      6   int i; // esi
      7   int v5; // ecx
      8   int v6; // edx
      9 
     10   result = a3;
     11   for ( i = a2; i <= a3; a2 = i )
     12   {
     13     v5 = i; //v5 = 4 * i 这一行为什么要改?求大佬指教 
     14     v6 = a1[i]; //v6 = *(_DWORD *)(4 * i + a1)
     15     if ( a2 < result && i < result )
     16     {
     17       do
     18       {
     19         if ( v6 > a1[result] ) //v6 > *(_DWORD *)(a1 + 4 * result)
     20         {
     21           if ( i >= result )
     22             break;
     23           ++i;
     24           a1[v5] = a1[result]; //*(_DWORD *)(v5 + a1) = *(_DWORD *)(a1 + 4 * result)
     25           if ( i >= result )
     26             break;
     27           while ( a1[i] <= v6 ) // *(_DWORD *)(a1 + 4 * i) <= v6
     28           {
     29             if ( ++i >= result )
     30               goto LABEL_13;
     31           }
     32           if ( i >= result )
     33             break;
     34           v5 = i; //v5 = 4 * i 这一行为什么要改?求大佬指教 
     35           a1[result] = a1[i]; // *(_DWORD *)(a1 + 4 * result) = *(_DWORD *)(4 * i + a1)
     36         }
     37         --result;
     38       }
     39       while ( i < result );
     40     }
     41 LABEL_13:
     42     a1[result] = v6; //*(_DWORD *)(a1 + 4 * result) = v6
     43     sub_4010F0(a1, a2, i - 1);
     44     result = a3;
     45     ++i;
     46   }
     47   return result;
     48 }
     49 
     50 char str[20] = {90,74,83,69,67,97,78,72,51,110,103};
     51 
     52 int main()
     53 {
     54     cout << str << endl;
     55     sub_4010F0(str,0,10);
     56     cout << str << endl;
     57 }

    这里50行我们定义的字符串见DialogFunc函数中第38到48行。运行结果:

    4

    我们再回到DialogFuc函数。

    6

    通过观察变量v7到v25定义时的地址(或者双击变量名),我们知道它们在地址中是相邻的,实际上如下图:

    5

    那么可以理解,DialogFunc函数中第51~54行,是把经过sub_4010F0处理后的字符串的倒数第3~倒数第1位赋给v4,而第56~59行,是将倒数第6~倒数第4位赋给v5。

    接下来我们研究sub_401000函数。代码如下:

      1 _BYTE *__cdecl sub_401000(int a1, int a2)
      2 {
      3   int v2; // eax
      4   int v3; // esi
      5   size_t v4; // ebx
      6   _BYTE *v5; // eax
      7   _BYTE *v6; // edi
      8   int v7; // eax
      9   _BYTE *v8; // ebx
     10   int v9; // edi
     11   signed int v10; // edx
     12   int v11; // edi
     13   signed int v12; // eax
     14   signed int v13; // esi
     15   _BYTE *result; // eax
     16   _BYTE *v15; // [esp+Ch] [ebp-10h]
     17   _BYTE *v16; // [esp+10h] [ebp-Ch]
     18   int v17; // [esp+14h] [ebp-8h]
     19   int v18; // [esp+18h] [ebp-4h]
     20 
     21   v2 = a2 / 3;
     22   v3 = 0;
     23   if ( a2 % 3 > 0 )
     24     ++v2;
     25   v4 = 4 * v2 + 1;
     26   v5 = malloc(v4);
     27   v6 = v5;
     28   v15 = v5;
     29   if ( !v5 )
     30     exit(0);
     31   memset(v5, 0, v4);
     32   v7 = a2;
     33   v8 = v6;
     34   v16 = v6;
     35   if ( a2 > 0 )
     36   {
     37     while ( 1 )
     38     {
     39       v9 = 0;
     40       v10 = 0;
     41       v18 = 0;
     42       do
     43       {
     44         if ( v3 >= v7 )
     45           break;
     46         ++v10;
     47         v9 = *(unsigned __int8 *)(v3++ + a1) | (v9 << 8);
     48       }
     49       while ( v10 < 3 );
     50       v11 = v9 << 8 * (3 - v10);
     51       v12 = 0;
     52       v17 = v3;
     53       v13 = 18;
     54       do
     55       {
     56         if ( v10 >= v12 )
     57         {
     58           *((_BYTE *)&v18 + v12) = (v11 >> v13) & 0x3F;
     59           v8 = v16;
     60         }
     61         else
     62         {
     63           *((_BYTE *)&v18 + v12) = 64;
     64         }
     65         *v8++ = byte_407830[*((char *)&v18 + v12)];
     66         v13 -= 6;
     67         ++v12;
     68         v16 = v8;
     69       }
     70       while ( v13 > -6 );
     71       v3 = v17;
     72       if ( v17 >= a2 )
     73         break;
     74       v7 = a2;
     75     }
     76     v6 = v15;
     77   }
     78   result = v6;
     79   *v8 = 0;
     80   return result;
     81 }

    进入第65行的byte_407830

    7

    怀疑sub_401000是base64加密。

    再回到DialogFuc函数,研究flag的格式:

      if ( String == v7 + 34                    // 第一位等于经过sub_4010F0处理后的字符串的第一位('3')51+34=85('U')
            && v19 == v11                           // 第二位等于v11,即经过sub_4010F00处理后的字符串的第5位'J'
            && 4 * v20 - 141 == 3 * v9              // 经过计算,第三位等于(3 * 69('E') + 141) / 4 = 87('W')
            && v21 / 4 == 2 * (v14 / 9)             // 第四位等于2 * ( 90('Z') / 9 ) * 4 = 80('P')
            && !strcmp(v4, "ak1w")                  // 第六、七、八位经过base64加密后等于'ak1w'
            && !strcmp(                             // 第三、四、五位经过base64加密后等于'V1Ax'
                  v5,
                  "V1Ax") )
          {
            MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0);
          }

    将’ak1w’、’V1Ax’进行base64解密,再连上前两位拼接起来,加上flag{}格式,即可得到flag:

    flag{UJWP1jMp}

    参考

    BUUCTF--刮开有奖

    Open Live Writer 安装

    open live writer 安装 markdown 插件

    博客高亮代码及使用OpenLiveWriter修改之前博客

    其他

    一开始用openlivewriter插入markdown代码总是报错

    2

    解决办法是取消勾选语言。


    3

  • 相关阅读:
    LVS DR实验!
    Memcached 与 Redis 区别
    LVS笔试题!
    并发编程拓展知识
    并发编程之协程
    并发编程之线程
    并发编程之多道技术
    粘包问题与socketserver实现并发
    套接字通信
    git的使用
  • 原文地址:https://www.cnblogs.com/hardcoreYutian/p/12602027.html
Copyright © 2020-2023  润新知