这个题目中有很多花指令来混淆我们的代码.
这里以 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;}