我们拿到了一个反编译后的C代码文件(challenge.c),这是逆向工程中最常见的起点:
cint __fastcall main(int argc, const char **argv, const char **envp)
{
bool v3;
_QWORD *v4;
__int64 v6;
__int64 v7;
_QWORD v8[2];
char v9;
_QWORD v10[7];
_main(argc, argv, envp);
std::ios_base::sync_with_stdio(0LL, v3);
// ... 更多复杂的代码
}
** 困惑点**:
v3, v4, v6 这样?_QWORD 是什么意思?__fastcall 是什么?解答:
v1, v2 等占位_QWORD:表示8字节(64位)的数据类型,相当于 unsigned long long__fastcall:调用约定,表示函数参数如何传递通过阅读代码,我们发现:
cstd::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "========== Reverse Practice Challenge ==========\n");
std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Enter passphrase: ");
翻译成人话:程序在输出欢迎信息,要求用户输入密码。
cif ((unsigned __int8)verify_passphrase(v8)) {
decrypt_blob[abi:cxx11](v10, &enc_flag);
// 显示解密结果
} else {
std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Access denied.\n");
std::operator<<<std::char_traits<char>>(
refptr__ZSt4cout,
"Hint: check rotated-xor layers and index-dependent offset.\n");
}
程序逻辑:
"Hint: check rotated-xor layers and index-dependent offset."
这个提示告诉我们加密算法可能包含:
代码中有一行特别复杂的判断:
cif ((*((_BYTE *)v4 + *(_QWORD *)(*v4 - 24LL) + 32) & 5) == 0)
** 这行代码在做什么?**
让我们一步步分解:
v4:指向输入流对象(std::cin)*v4 - 24LL:访问对象内部的虚函数表+ 32:偏移到状态标志位的位置& 5:检查特定的状态位== 0:判断输入是否成功** 简化理解**:这相当于检查 std::cin.good() 和 !std::cin.fail()
程序中有两个重要函数没有实现:
verify_passphrase() - 验证密码decrypt_blob() - 解密flag由于我们没有源代码,需要通过逆向分析来推断这些函数的实现。
基于提示信息,我们创建一个暴力破解工具来测试不同的解密算法:
cpp#include <iostream>
#include <vector>
#include <string>
#include <cstdint>
using namespace std;
// 8位右旋转函数
inline uint8_t rotateRight8(uint8_t value, unsigned rotation) {
rotation &= 7; // 限制在0-7范围内
if (rotation == 0) return value;
return (uint8_t)((value >> rotation) | (value << (8 - rotation)));
}
// 尝试解密函数
string tryDecryption(const vector<uint8_t>& data, int multiplier, int rotation_mod, uint8_t xor_key) {
string result;
result.reserve(data.size());
for (size_t i = 0; i < data.size(); ++i) {
uint8_t byte = data[i];
// 步骤1:减去索引偏移
byte = (uint8_t)((byte - (uint8_t)((i * multiplier) & 0xFF)) & 0xFF);
// 步骤2:右旋转
if (rotation_mod > 0) {
byte = rotateRight8(byte, (unsigned)(i % rotation_mod));
}
// 步骤3:异或
byte = (uint8_t)(byte ^ xor_key);
result.push_back((char)byte);
}
return result;
}
我们需要测试不同的参数组合:
cpp// 加密数据
vector<uint8_t> sample_data = {
60, 115, 250, 254, 46, 75, 168, 225, 49, 193,
111, 203, 104, 20, 85, 110, 70, 24, 201, 247
};
// 尝试不同的参数组合
vector<tuple<int, int, uint8_t>> patterns = {
{7, 5, 0x5A}, // 乘数7, 旋转模5, 异或0x5A
{3, 4, 0x5A},
{5, 3, 0x5A},
// ... 更多组合
};
for (auto& pattern : patterns) {
int mult = get<0>(pattern);
int rot_mod = get<1>(pattern);
uint8_t xor_key = get<2>(pattern);
string result = tryDecryption(sample_data, mult, rot_mod, xor_key);
printf("乘数:%d, 旋转模:%d, 异或:0x%02x -> '%s'\n",
mult, rot_mod, xor_key, result.c_str());
// 检查是否包含flag模式
if (result.find("flag") != string::npos) {
cout << "*** 可能找到flag! ***\n";
}
}
运行我们的分析工具后,得到了结果:
乘数:7, 旋转模:5, 异或:0x5a -> 'flag{reverse_me_123}'
** 找到了正确的解密参数**:
i * 7)i % 5)使用相同的算法解密密码数据:
cpp// 密码数据
vector<uint8_t> enc_pass_data = {
53, 91, 10, 182, 147, 76, 168, 213, 17, 178, 133
};
string password = decryptData(enc_pass_data);
cout << "正确密码: " << password << endl; // 输出: open-sesame
最终验证:
bash$ echo "open-sesame" | ./challenge_working.exe
========== Reverse Practice Challenge ==========
Enter passphrase: Access granted.
Here is the secret: flag{reverse_me_123}
本文作者:晏秋
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!