逆向工程趣谈:如何通过残缺的重定位表‘猜’出C代码中的秘密数组名?
逆向工程趣谈如何通过残缺的重定位表‘猜’出C代码中的秘密数组名当你面对一个被故意混淆了符号名的目标文件时那种感觉就像拿到了一张被墨水涂改过的藏宝图。最近我在分析一个名为phase5.o的目标文件时就遇到了这样的挑战——关键数组TRAN_ARRAY在符号表中被显示为fEgeEF而其他重要符号也都被类似的无意义字符串替代。这不禁让我思考如何像侦探破案一样从这些被刻意隐藏的线索中还原出程序的真实面目1. 理解重定位表程序链接的胶水重定位表Relocation Table是ELF格式文件中一个至关重要的数据结构它记录了在链接阶段需要修正的地址引用。简单来说它就像是建筑工地上的此处需要连接标记告诉链接器哪些地方需要打补丁。在典型的ELF文件中你会看到两种重定位表.rel.text针对代码段的重定位.rel.data针对数据段的重定位每个重定位条目通常包含两个关键信息偏移量需要修正的位置在段内的偏移重定位类型和符号索引如何修正以及引用哪个符号typedef struct { Elf32_Addr r_offset; // 需要重定位的位置 Elf32_Word r_info; // 符号索引和重定位类型 } Elf32_Rel;提示在32位系统中每个重定位条目占8字节64位系统中则为16字节。2. 逆向推理从机器码到高级语言结构逆向工程最迷人的地方在于它要求你同时具备自上而下和自下而上的思维能力。当我看到phase5.o中那些被混淆的符号名时决定采用以下方法逐步还原2.1 符号表与重定位表的交叉分析首先使用readelf -s phase5.o查看符号表你会发现类似这样的条目Num: Value Size Type Bind Vis Ndx Name 9: 000000 0040 OBJECT GLOBAL DEFAULT 3 fEgeEF 10: 000040 0100 OBJECT GLOBAL DEFAULT 3 qbivHB 12: 000140 0004 OBJECT GLOBAL DEFAULT 3 CODE然后通过objdump -dr phase5.o查看反汇编代码和重定位信息你会看到类似80483a0: 8b 04 85 00 00 00 00 mov 0x0(,%eax,4),%eax R_386_32 fEgeEF这个重定位条目告诉我们在偏移量80483a3处需要填入fEgeEF的地址。结合反汇编代码可以推断这是一个数组访问操作因为有(,%eax,4)的索引计算。2.2 识别数组访问模式在C代码中数组访问通常编译为以下形式的汇编指令mov offset(base, index, scale), dest其中scale等于数组元素的大小如int数组通常为4。通过统计重定位表中引用fEgeEF的位置我发现有9处这样的访问且都出现在transform_code函数中。这强烈暗示fEgeEF实际上是一个被频繁访问的数组。3. 实战还原被混淆的符号名现在让我们一步步还原这个被混淆的程序结构。3.1 重建关键数据结构通过分析重定位表和反汇编代码可以推断出以下对应关系混淆符号实际含义证据线索fEgeEFTRAN_ARRAY多处数组访问模式用于转换逻辑qbivHBFDICT出现在字符编码函数中类似字典表CODECODE保持原名全局变量3.2 补全重定位表原始重定位表中有部分条目被清零我们需要根据程序逻辑补全。以下是关键步骤使用hexedit打开phase5.o定位到.rel.text节通常在0x524偏移处每个重定位条目8字节格式为前4字节需要重定位的偏移后4字节高24位为符号索引低8位为重定位类型例如要补全对fEgeEF的引用0000003d 09000001 # 偏移0x3d引用符号9(fEgeEF)类型R_386_32(01)3.3 验证推理的正确性为了验证我们的推断可以编写一个简单的测试程序extern const int fEgeEF[]; extern const char qbivHB[]; void test_array() { printf(fEgeEF[0] %x\n, fEgeEF[0]); printf(qbivHB[A] %c\n, qbivHB[A]); }如果输出符合预期如转换数组的值和字典表的映射就证明我们的符号还原是正确的。4. 逆向工程中的思维模式这种逆向推理过程实际上反映了软件安全分析中的核心思维模式模式识别识别常见的编译器代码生成模式假设验证提出假设并寻找证据支持或反驳交叉验证结合多种信息来源符号表、重定位表、反汇编上下文推理从程序整体行为推断局部功能例如在分析transform_code函数时我注意到它使用了TRAN_ARRAY即fEgeEF进行位操作// 还原后的transform_code函数 int transform_code(int code, int mode) { switch(TRAN_ARRAY[mode] 0x7) { case 0: code ~TRAN_ARRAY[mode]; break; case 1: code ^ TRAN_ARRAY[mode]; break; // ... } return code; }这种模式很像是某种编码或加密算法进一步验证了fEgeEF作为转换数组的角色。5. 工具链与技巧分享在实际操作中以下工具组合特别有用readelf查看ELF文件结构readelf -a phase5.oobjdump反汇编与重定位信息objdump -dr phase5.ohexedit直接编辑二进制文件nm查看符号表nm phase5.o几个实用技巧关注.rodata节常量数组通常存放在这里查找重复的访问模式数组操作通常有规律可循注意函数调用约定可以帮助识别参数传递6. 从理论到实践一个完整的推理案例让我们看一个具体的例子。在反汇编代码中我们发现了以下片段mov $0x0,%eax mov %eax,-0x4(%ebp) mov -0x4(%ebp),%eax cmp 0x8(%ebp),%eax jae 8048456 mov -0x4(%ebp),%eax mov 0x0(,%eax,4),%edx R_386_32 fEgeEF mov %edx,%eax and $0x7,%eax这段代码对应的C代码大致是for(int i 0; i size; i) { int val TRAN_ARRAY[i]; // fEgeEF switch(val 0x7) { // ... } }通过这样的模式匹配我们就能逐步重建出原始的代码逻辑。逆向工程就像是在解一个精心设计的谜题每个线索都隐藏在二进制文件的各个角落。那次分析phase5.o的经历让我深刻体会到即使面对高度混淆的代码通过系统性的分析和合理的推理我们仍然能够还原出程序的本意。最令我兴奋的时刻是当补全最后一个重定位条目后程序突然输出了预期的编码字符串——那一刻所有的猜测和验证都得到了完美的证实。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2497219.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!