skip to content

2023 年安洵杯 ez_cpp 题解

比较恶心的花指令题目尤其是第一个加密算法

这个题目中有很多花指令来混淆我们的代码.

这里以 main 函数中的混肴为例子,介绍怎么去花指令,然后让 ida 重新能将这个函数识别出来。

首先我们可以看到这里有一个 jb loc_413b94 + 3 的指令,这个指令说明 loc_413b94 处有一段花指令,真正的代码要到 loc_413b94 + 3 处才开始。

右键这个位置,然后点击 undefine

然后我们将真正跳转到的地方,设置为 code 类型

但是这样就算让 ida 认识出来哪些是花指令还不够,因为出题人很鸡贼,这个地方跳转用的 jz,ida 会以为下面那坨花指令会被执行。但是我们可以看到跳转指令上方还有个 xor eax, eax 的指令,这个指令会将 eax 清零,所以这个 jz 指令是一定会跳转走的。我们这里用 ida 的 patch 功能将 jz 改为 jmp 就能让 ida 真的意识到下面一段代码是花指令。

接下来我们用 keypatch 插件修改跳转指令

keypatch 这个插件应该在 52pojie 官方那里下载的 IDA 应该是自带的,如果没有的话可以去 52pojie 官方下载一个

如此这般,将所有的花指令去除了以后,就可以开始调试了。


接下来,我们可以看到有 3 个加密函数

其中前两个是用的面向对象写法,调用了两个对象的虚函数,因为虚函数只能在运行的时候才能知道执行了啥(C++ 多态的知识),所以前两个加密函数用动态调试就能知道是啥了。

第三个加密函数应该是最简单的,就是把数字的二进制反过来,然后再加 1。

第二个加密函数虽然比较复杂,写出对应的逆向代码不难。

主要是第一个加密函数最阴间,因为有不止一种可能。所以这里采用的是暴力破解的方法。输出每一个字节有哪些可能性。然后在这些可能性中找到一个能够满足条件的就行了。

// Enc1
  int tmp_result;
  for (int i = 0; i < 32; i++) {
    bool find_v3 = false;
    for (int v3 = 0; v3 < 128; v3++) {
      int result;
      if ((v3 - 61) <= 0x3Eu) {
        result = v3;
        int v7 = v3 + 13;
        if (v3 > 90) {
          if (v7 <= 122)
            tmp_result = v3 + 13;
          else
            tmp_result = v3 - 13;
        } else {
          result = -13;
          if (v7 <= 90)
            result = 13;
          result = v3 + result;
          tmp_result = result;
        }
      }

      if (tmp_result == arr[i] && check(v3)) {
        find_v3 = true;
        cout << (char)v3;
      }
    }
    if (!find_v3) {
      cout << (char)arr[i];
    }
    cout << " ";
  }

运行结果是这样的。假如说某个字节有多种可能性就会一块输出,然后一眼丁真,flag 是 SYC{Y3S-yE5-y0u-S0Ve-Th3-C9P!!!}

可以看到这个是正确 flag 捏

完整的代码:

#include <iostream>
using namespace std;

unsigned int dec3(unsigned int a1) {
  unsigned int a2 = 8;
  a1--;

  unsigned int v2; // edx
  unsigned int v3; // edi
  unsigned int v4; // ebx

  v2 = 0;
  v3 = 0;
  if (a2 > 0) {
    v4 = a2 - 1;
    do
      v2 |= ((a1 >> v3++) & 1) << v4--;
    while (v3 < a2);
  }
  return v2;
}

unsigned int arr[] = {0x22,        0x0FFFFFFA2, 0x72,        0x0FFFFFFE6,
                      0x52,        0x0FFFFFF8C, 0x0FFFFFFF2, 0x0FFFFFFD4,
                      0x0FFFFFFA6, 0x0A,        0x3C,        0x24,
                      0x0FFFFFFA6, 0x0FFFFFF9C, 0x0FFFFFF86, 0x24,
                      0x42,        0x0FFFFFFD4, 0x22,        0x0FFFFFFB6,
                      0x14,        0x42,        0x0FFFFFFCE, 0x0FFFFFFAC,
                      0x14,        0x6A,        0x2C,        0x7C,
                      0x0FFFFFFE4, 0x0FFFFFFE4, 0x0FFFFFFE4, 0x1E};

void dec2(unsigned int *arr) {
  int v6[] = {0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1,
              0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0};

  int index = 0;
  unsigned int result;
  do {
    if (index <= 16) {
      if (index >= 16) {
        arr[index] ^= 4;
      } else {
        result = v6[index];
        if (result) {
          if (!--result)
            arr[index] ^= 9;
        } else {
          arr[index] += 2;
        }
      }
    } else {
      result = v6[index];
      if (result) {
        if (!--result)
          arr[index] ^= 6;
      } else {
        arr[index] += 5;
      }
    }
    ++index;
  } while (arr[index]);
}

int check(int c) {
  if ((c >= 'a' && c <= 'z')  (c >= 'A' && c <= 'Z')
      (c >= '0' && c <= '9')  c == '{'  c == '}' || c == '_') {
    return true;
  }
  return false;
}

int main() {
  // Enc3
  for (int i = 0; i < 32; i++) {
    arr[i] ^= 1;
    arr[i] = dec3(arr[i]);
  }

  // Enc2
  dec2(arr);

  // Enc1
  int tmp_result;
  for (int i = 0; i < 32; i++) {
    bool find_v3 = false;
    for (int v3 = 0; v3 < 128; v3++) {
      int result;
      if ((v3 - 61) <= 0x3Eu) {
        result = v3;
        int v7 = v3 + 13;
        if (v3 > 90) {
          if (v7 <= 122)
            tmp_result = v3 + 13;
          else
            tmp_result = v3 - 13;
        } else {
          result = -13;
          if (v7 <= 90)
            result = 13;
          result = v3 + result;
          tmp_result = result;
        }
      }

      if (tmp_result == arr[i] && check(v3)) {
        find_v3 = true;
        cout << (char)v3;
      }
    }
    if (!find_v3) {
      cout << (char)arr[i];
    }
    cout << " ";
  }

  return 0;
}