比较恶心的花指令题目尤其是第一个加密算法
这个题目中有很多花指令来混淆我们的代码.
这里以 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;
}