zoukankan      html  css  js  c++  java
  • Buuctf Simple Rev 题解

    这次题解我们来点不一样的,一般我们逆向都用ida,但是之前我找了一个工具 ghidra,这次我打算用这个工具来做这个题目。

    先来张截图感受一下吧:

    首先不废话,将程序拖进工具。选中main函数,可以看到该工具自动生成的main函数伪代码。

    本题解中的部分伪代码变量被我修改过,方便阅读

    void main(void)
    {
      char cVar1;
      int iVar2;
      do {
        while( true ) {
          printf("Welcome to CTF game!
    Please input d/D to start or input q/Q to quit this program: ");
          iVar2 = getchar();
          cVar1 = (char)iVar2;
          if ((cVar1 != 'd') && (cVar1 != 'D')) break;
          Decry();
        }
        if ((cVar1 == 'q') || (cVar1 == 'Q')) {
          Exit();
        }
        else {
          puts("Input fault format!");
          iVar2 = getchar();
          putchar(iVar2);
        }
      } while( true );
    }
    

    很显然,Decry()函数就是我们要找到的游戏程序的主体函数,点进去后可以看到一大坨代码。这个时候要冷静读题。

    首先这里有几个全局变量,我们可以找到这几个变量的值是

    key3 = "kills";
    key1 = "ADSFK";
    

    然后就是一些拼接的操作。注意了,因为数字的高位存在内存较高的位置,如果要将一串数字看成一个字符数组的话,顺序要颠倒过来。具体的可以看我的上一篇博客

    https://www.cnblogs.com/Node-Sans-Blog/p/14285636.html

    接下来我们可以得到

    text = "killshadow";
    key = "ADSFKNDCLS";
    

    然后就是一段对输入加密的程序

      while( true ) {
        iVar1 = getchar();
        inputChar = (char)iVar1;
        if (inputChar == '
    ') break;
        if (inputChar == ' ') {
          index = index + 1;
        }
        else {
          if ((inputChar < 'a') || ('z' < inputChar)) {
            if (('@' < inputChar) && (inputChar < '[')) {
              iVar1 = ((int)inputChar - (int)(char)key[j % len]) + 0x3a;
              result[index] = (char)iVar1 + (char)(iVar1 / 0x1a) * -0x1a + 'a';
              j = j + 1;
            }
          }
          else {
            iVar1 = ((int)inputChar - (int)(char)key[j % len]) + 0x3a;
            result[index] = (char)iVar1 + (char)(iVar1 / 0x1a) * -0x1a + 'a';
            j = j + 1;
          }
          if (j % len == 0) {
                        /* 输出空格 */
            putchar(0x20);
          }
          index = index + 1;
        }
      }
    

    仔细阅读的话,不难发现这里是字符数组一位一位加密的,每一位加密后的结果之间没有联系,所以可以写脚本逐位爆破,时间复杂度也足够承受。

    对了这里加密的几个表达式中,有一个表达式是

    result[index] = (char)iVar1 + (char)(iVar1 / 0x1a) * -0x1a + 'a';
    

    这里仔细看一下的话可以发现是 iVar1 % 26 + 'a' 的意思。毕竟 mod 运算可以看成是一个被除数减去能减的最多个数的除数得到的结果。(有点绕自己慢点理解下吧)

    脚本:

    #include <iostream>
    
    using std::cout;
    using std::endl;
    
    int main() {
      char target[] = "killshadow";
      char key[] = "adsfkndcls";
      char t;
      for (int i = 0; i < 10; ++i) {
        for (char j = 0; j < 127; ++j) {
          if (j >= 'a' && j <= 'z' || j >= 'A' && j <= 'Z') {
            t = j - key[i] + 0x3a;
            t = t % 26 + (int)'a';
            if (t == target[i]) {
              putchar(j);
              break; 
            }
          }
        }
      }
      putchar('
    ');
      return 0;
    }
    

    当然,这道题还是有点缺陷的,比如说如果输入是小写的话,可以有多解,并且给的样例程序无法运行。

  • 相关阅读:
    计蒜客 聪明的班主任(思维)
    codeforces 456 E. Civilization(并查集+数的直径)
    codeforces 456 D. A Lot of Games(字典数+博弈+思维+树形dp)
    codeforces 233 D. Table(思维+dp )
    codeforces 233 C. Cycles(贪心+思维)
    codeforces 814 D. An overnight dance in discotheque (贪心+bfs)
    codeforces 814 C. An impassioned circulation of affection(二分+思维)
    codeforces 813 D. Two Melodies(dp)
    Atcoder F
    Java正则表达式
  • 原文地址:https://www.cnblogs.com/Node-Sans-Blog/p/14286478.html
Copyright © 2011-2022 走看看