逆向黑盒程序时,如何在ARM64汇编中识别C++内部函数调用?
利用同版本编译器的符号化标准库二进制特征匹配
不用手动猜测类型编译测试,直接拿和黑盒程序同版本的编译器(GCC/Clang/MSVC),编译带完整符号的测试程序(不要strip符号),提取生成的标准库函数(比如std::basic_string的各类构造、析构函数)的二进制特征,和黑盒程序里的无符号函数做匹配。注意要对齐优化等级——先通过黑盒里的代码结构(比如是否有冗余分支、循环展开)判断它的优化等级(O0/O2/O3),再用对应等级编译测试代码,特征匹配的准确率会大幅提升。用逆向工具的内置C分析能力
IDA的Hex-Rays反编译器开启C模式后,会自动识别大量标准库的构造、析构及方法调用,比如把栈内存置零+内存分配的序列直接还原成std::string的初始化逻辑。Ghidra的反编译器也有类似的C++分析选项,能自动还原很多底层调用结构,省掉手动匹配的麻烦。
对于单纯的置零操作,结合上下文判断:函数开头对栈上连续内存置零,后续跟着标准库内存操作的,大概率是POD类型或带默认构造的标准类型初始化;堆内存置零的,常和std::vector、std::string的内存初始化逻辑相关。针对标准库固定行为做特征匹配
不同标准库有固定的调用模式:比如GCC下std::basic_string的构造,会先调用malloc,然后复制字符串内容,最后给内部的size和capacity成员赋值;MSVC下则会调用operator new,还有特定的内存布局检查逻辑。把这些固定的字节序列做成特征模板,直接用IDA的「搜索>字节序列」功能查找,比自己写脚本高效得多。
对于被优化成空函数(直接ret)的调用,看它的上下文:如果是在对象创建后立即调用,或者销毁前调用,结合对象的内存大小,大概率是空类的默认构造/析构,或是标准库中无操作的方法。结合字符串常量交叉验证
除了错误日志里的类型名称,还可以找黑盒里的标准库相关字符串(比如"std::out_of_range"这类异常信息),定位到引用这些字符串的位置,回溯调用栈就能找到对应的标准库函数(比如std::vector::at)。
内容的提问来源于stack exchange,提问作者Maksim Chekmarev

