Buuctf Simple Rev 题解

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

先来张截图感受一下吧:

https://i.loli.net/2021/01/16/cIM8SL1nJCjPe4U.png

image.png

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

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

void main(void)
{
  char cVar1;
  int iVar2;
  do {
    while( true ) {
      printf("Welcome to CTF game!\\nPlease 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 == '\\n') 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';