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

这里以 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;}