核心原则:C++ 底层就是带类的 C。看到长长的
::符号不要慌,扒掉标准库(STL)的外衣,剩下的控制流和算术运算才是出题人真正想考你的东西。
一、 哪些【不用看】(直接当噪音过滤)
反编译器会把 C++ 的底层内存管理、对象生命周期全盘托出,以下这些 90% 都是废话,直接跳过:
- 析构函数:看到
::~string()、::~allocator()、::~vector()等带有~符号的函数,代表对象生命周期结束,释放内存,完全不影响你的逻辑判断。 - 内存分配器:
std::allocator<...>及其各种初始化(allocator::allocator),这是 STL 容器在底层申请堆空间,直接无视。 - 异常抛出与崩溃处理:看到
_cxa_throw、std::runtime_error、exception、outOfBounds、FullPanic等,说明这里触发了报错或反调试。除非你在找绕过反调试的方法,否则可以暂时跳过这段代码块。 - 临时迭代器构造:
__gnu_cxx::__normal_iterator及其繁杂的operator+、operator-构造。它本质就是个指针,直接看它最终指向了哪。
二、 哪些【重点看】(还原真实逻辑)
过滤掉废话后,重点盯住以下几个部分:
- 输入与输出:
- 重点看
std::operator>>(std::cin, xxx)(输入)和std::operator<<(std::cout, xxx)(输出),这是你与程序的交互点。
- 重点看
- 核心循环与控制流:
for、while、if、switch是逻辑骨架,重点看它们里面的变量是怎么变化的。
- 字符/数组的取值:
- 比如
std::string::operator[](str, i),直接看成str[i]。
- 比如
- 数学与位运算:
- 所有的
+、-、*、/、%、^、&、|、<<、>>,出题人的加密算法全在这里。
- 所有的
- 字符串比较:
- 看到
std::operator!=或operator==,说明在进行密文比对。
- 看到
三、 常见特征【人话翻译对照表】
| C++ 反编译特征 (IDA伪代码) | 翻译成人类语言 (等价 C 代码) |
|---|---|
std::string::basic_string(v1, v2) |
string v1 = v2; (构造或拷贝) |
std::string::operator=(v1, v2) |
v1 = v2; (赋值) |
std::string::operator[](v1, i) |
v1[i] (取下标字符) |
std::operator>><char>(&std::cin, v1) |
cin >> v1; (读入) |
std::operator<<(std::cout, v1) |
cout << v1; (输出) |
std::string::length(v1) 或 size(v1) |
v1.length() (取长度) |
std::string::substr(v1, v2, start, len) |
v1 = v2.substr(start, len); (截取子串) |
std::string::back(v1) |
v1[v1.length()-1] (最后一个字符) |
std::string::begin(v1) / end(v1) |
指向开头/结尾的指针 |
std::operator!=<char>(v1, v2) |
v1 != v2 (字符串比较) |
__readfsqword(0x28u) |
栈保护 Canary,直接无视 |
四、 实战速读三步走口诀
拿到一坨 C++ 代码,按以下顺序执行:
- 第一遍:CTRL+X 划掉废代码
在脑子里(或纸上)把带~的、带allocator的、带iterator构造的行全部抹掉。 - 第二遍:符号替换
把operator[]替换成中括号,把一长串输入输出替换成cin/cout。 - 第三遍:盯紧循环和变量
只看for循环里str[i]做了什么运算,把运算公式抄下来(比如str[i] = str[i] ^ 0x42),直接写脚本逆向即可。
遇到卡壳时:如果在
main函数里看到莫名其妙的zero变量判断,或者复杂的异常抛出,尝试去它调用的check()或solve()里找找,通常是反调试的障眼法。
