[DASCTF Sept 2021]pig_brain_king

  1. IDA打开之后按下Shift + F12找到字符串

    image

    定位到之后找到下面的cls,这是系统清屏指令。定位这个指令(原因是程序里执行了这个指令(易知))

    image

    看到了大规模的变量赋值指令。但是仔细看就会发现都是在变量v281中取值,因而只需要写个基本的字典序翻译程序

  2. 字典序翻译
    很容易看出来这是一个字典打印程序。这里对字典的序列进行了打印,而各个数组的值对应:

    whoisthestrongestpigbrainking?!
    canyouanswer1000questionscorrectly?
    nowstartdoingthequestions!
    pleaseenter
    nonono
    bingo!
    theansweris
    

    所对应的值和对应行如下

    //...
      sub_411154();
      v282 = 0;
      v259 = v281[67];                              // whoisthestrongestpigbrainking?!
      v252 = v281[66];
    //...
      std::ostream::operator<<(v39, sub_4115F0);
      v260 = v281[66];                              // canyouanswer1000questionscorrectly?
      v253 = v281[50];
    //...
      while ( 1 )
      {
        v261 = v281[67];                            // nowstartdoingthequestions!
        v254 = v281[44];
    //...
            if ( i >= 3 )
            goto LABEL_10;
          v262 = v281[43];                          // pleaseenter
          v255 = v281[30];
    //...
          if ( v273 )
            break;
          v264 = v281[40];                          // nonono
          v257 = v281[39];
          v251 = v281[40];
    //...
          std::ostream::operator<<(v133, sub_4115F0);
        }
        v263 = v281[67];                            // bingo!
        v256 = v281[40];
        v250 = v281[32];
    //...
    LABEL_10:
        *v278 = v277;
        if ( v277 )
        {
          ++v280;
        }
        else
        {
          v265 = v281[44];                          // theansweris
          v258 = v281[34];
          v245 = v281[43];
    //...
    

    找到theansweris

    else
        {
          v265 = v279[44];
          v258 = v279[34];
          v245 = v279[43];
          v238 = v279[30];
          v231 = v279[48];
          v227 = v279[44];
          v223 = v279[39];
          v218 = v279[26];
          v209 = v279[30];
          v206 = v279[33];
          v134 = sub_41121C(std::cout, v279[19]);
          v135 = sub_41121C(v134, v206);
          v136 = sub_41121C(v135, v209);
          v137 = sub_411474(v136, " ");
          v138 = sub_41121C(v137, v218);
          v139 = sub_41121C(v138, v223);
          v140 = sub_41121C(v139, v227);
          v141 = sub_41121C(v140, v231);
          v142 = sub_41121C(v141, v238);
          v143 = sub_41121C(v142, v245);
          v144 = sub_411474(v143, " ");
          v145 = sub_41121C(v144, v258);
          v146 = sub_41121C(v145, v265);
          sub_411474(v146, ":");
          sub_4114BF(v266, v267);
        }
        Sleep(0);
        system("cls");
      }
    

    找到关键函数

    int __thiscall sub_41CAE0(HANDLE *this)
    {
      //defs...
      struct _CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo; // [esp+124h] [ebp-38h] BYREF
      HANDLE *v90; // [esp+144h] [ebp-18h]
      int v91; // [esp+158h] [ebp-4h]
    
      v90 = this;
      __CheckForDebuggerJustMyCode(&unk_42F035);
      GetConsoleScreenBufferInfo(v90[64], &ConsoleScreenBufferInfo);
      *((_WORD *)v90 + 136) = ConsoleScreenBufferInfo.dwCursorPosition.X;
      *((_WORD *)v90 + 137) = ConsoleScreenBufferInfo.dwCursorPosition.Y;
      if ( *((double *)v90 + 33) > 3330.0 )
      {
        sub_4110AA(&unk_428DD6);
        v91 = 0;
        sub_411442(v88);
        v91 = -1;
        sub_411528();
        //some output....
      }
      v86 = sub_41146F(v87);
      v91 = 1;
      v56 = sub_4114AB(std::cout, v86);
      std::ostream::operator<<(v56);
      v91 = -1;
      return sub_411528();
    }
    
  3. 根据伪代码第603行的

    //..
          sub_4114BF(v266, v268);
        }
        Sleep(0xBB8u);
        system("cls");
      }
    

    估计程序中出现了Sleep延时。修改这段代码去掉延时。定位到相应的汇编代码:
    image

    将相应的硬编码改掉,也就是改成

    push 00000000h
    

    换句话说

    68 00 00 00 00
    

    同理,修正下述位置:
    D870h(FOA,下同)

    FF FF 8B F4 68 00 00 00 00 FF 15 04 D0 42 00 3B
    

    DBB0h

    2D FF FF 8B F4 68 00 00 00 00 FF 15 04 D0 42 00
    

    E040h

    FF E8 79 28 FF FF 8B F4 68 00 00 00 00 FF 15 04
    

    然后更改判断的代码,即第541行伪代码

    if ( v273 )
            break;
    

    对应的硬编码
    image

    改为

    jnz loc_41EA40
    

    即(jnz的硬编码是85)

    DD80h:

    0F 85 BA 00 00 00 8B F4 68 F0 15 41 00 B8 01 00
    
  4. 发现在答完1000道题之后仍然没有flag,找到*号修改为0即可

    int __thiscall sub_41ADE0(char *this)
    {
      unsigned int v1; // eax
      int v2; // eax
      int v3; // eax
      int v5; // [esp-8h] [ebp-158h]
      int v6; // [esp-4h] [ebp-154h]
      int v7; // [esp+0h] [ebp-150h]
      int v8; // [esp+0h] [ebp-150h]
      int v9; // [esp+0h] [ebp-150h]
      int v10; // [esp+4h] [ebp-14Ch]
      int v11; // [esp+4h] [ebp-14Ch]
      char v12[36]; // [esp+1Ch] [ebp-134h] BYREF
      char v13[39]; // [esp+40h] [ebp-110h] BYREF
      bool v14; // [esp+67h] [ebp-E9h]
      unsigned int i; // [esp+130h] [ebp-20h]
      char *v16; // [esp+13Ch] [ebp-14h]
      int v17; // [esp+14Ch] [ebp-4h]
    
      v16 = this;
      __CheckForDebuggerJustMyCode(&unk_42F035);
      SetConsoleCursorPosition(*((HANDLE *)v16 + 64), *(COORD *)(v16 + 272));
      for ( i = 0; ; ++i )
      {
        sub_41146F(v13);
        v1 = sub_41118B(v7, v10);
        v14 = i < v1;
        sub_411528(v8, v11);
        if ( !v14 )
          break;
        sub_411474(std::cout, "*");
      }
      sub_41146F(v12);
      v17 = 0;
      v5 = sub_41118B(sub_4115F0, v7);
      v2 = sub_411474(std::cout, " ");
      v3 = std::ostream::operator<<(v2, v5, v6);
      std::ostream::operator<<(v3);
      v17 = -1;
      return sub_411528(v9, v10);
    }
    

      sub_411474(std::cout, "*");
    

    对应的硬编码进行修正:

    .rdata:00428DD4                         ; const char Str[]
    .rdata:00428DD4 2A 00                   Str             db '*',0                ; DATA XREF: sub_41ADE0+E1↑o
    .rdata:00428DD6 00                      unk_428DD6      db    0
    

    image

  5. 最终输入1000行随机字符得到flag:

    输入方法:在notepad里输入任意字符复制粘贴1000行,然后粘贴到控制台里就行

    image

  6. flag{YOU_ar3_The_k1ng_Of_pig_bra1n!}

posted @ 2021-09-25 21:36  二氢茉莉酮酸甲酯  阅读(232)  评论(2编辑  收藏  举报