逆向工程中的减法思维用Unidbg Trace高效剥离标准加密算法逆向分析常常像在迷雾中寻找出路特别是当目标代码混杂了标准加密算法和自定义逻辑时。传统方法可能需要逐行分析成千上万行汇编代码而今天我要分享的是一种截然不同的思路——通过减法来简化逆向过程。1. 逆向分析的新视角从加法到减法大多数逆向工程师习惯于加法思维——不断积累对代码的理解逐步构建完整的算法还原。但在处理复杂样本时这种方法往往效率低下容易迷失在代码海洋中。减法思维则反其道而行之先识别并排除已知的标准算法部分将注意力集中在剩余的未知逻辑上。这种方法的核心优势在于工作量评估通过统计标准算法占用的代码量预估剩余分析的难度优先级排序快速判断样本的技术价值决定是否值得深入效率提升避免在标准算法上浪费过多时间在分析blackbox样本时原始Trace包含18000行汇编其中16000行是标准的HMAC-SHA1实现。通过减法处理后实际需要分析的自定义逻辑仅剩1600行。2. Unidbg Trace的关键技术实现Unidbg的Code Trace功能为这种减法分析提供了理想工具。以下是具体实施步骤2.1 基础环境配置首先建立基本的Unidbg模拟环境public class BlackboxAnalyzer { private final AndroidEmulator emulator; private final VM vm; private final Module module; public BlackboxAnalyzer() throws FileNotFoundException { // 创建32位模拟器实例 emulator AndroidEmulatorBuilder.for32Bit() .setProcessName(com.blackbox) .build(); final Memory memory emulator.getMemory(); memory.setLibraryResolver(new AndroidResolver(23)); // API 23 // 加载目标APK和SO文件 vm emulator.createDalvikVM(new File(blackbox.apk)); DalvikModule dm vm.loadLibrary(new File(libnative-lib.so), true); module dm.getModule(); // 启用Code Trace String traceFile blackbox_trace.txt; PrintStream traceStream new PrintStream(new FileOutputStream(traceFile), true); emulator.traceCode(module.base, module.base module.size) .setRedirect(traceStream); } }2.2 魔数识别技巧标准加密算法通常包含特定的魔数Magic Number这是快速识别的关键线索算法类型特征魔数常见位置SHA-10x67452301初始化向量MD50x67452301初始状态AES0x63C6A563S盒特定位置CRC320xEDB88320多项式表示在blackbox样本中通过搜索0x67452301快速定位到SHA-1实现部分。2.3 Trace分割技术获得完整Trace后需要精确分割标准算法部分确定边界通过交叉引用和函数调用关系确定算法起始和结束地址行数统计计算标准算法占用的Trace行数有效性验证确保分割不会破坏剩余逻辑的完整性def split_trace(input_file, output_file, start_addr, end_addr): with open(input_file, r) as f_in, open(output_file, w) as f_out: in_algorithm False for line in f_in: if hex(start_addr) in line: in_algorithm True if not in_algorithm: f_out.write(line) if hex(end_addr) in line: in_algorithm False3. 剩余逻辑的分析策略剥离标准算法后剩余代码通常呈现以下特征代码量显著减少如blackbox样本从18000行降至1600行逻辑相对简单难以容纳复杂加密算法依赖前序结果常会使用标准算法的输出作为输入3.1 自定义算法的常见模式根据经验精简后的自定义算法通常属于以下类别字节变换类异或操作字节替换位移组合数学运算类模运算简单哈希线性变换编码转换类Base64变种自定义字符映射数字编码3.2 关键分析技术针对剩余逻辑推荐采用以下分析方法内存访问追踪监控对标准算法结果的访问模式输入输出关联建立输入变化与输出变化的对应关系符号执行对关键路径进行符号化分析// Unidbg内存访问追踪示例 emulator.traceRead(hmacResultAddr, hmacResultAddr 20).setRedirect(System.out); emulator.traceWrite(outputAddr, outputAddr 7).setRedirect(System.out);4. 实战blackbox样本深度解析让我们具体分析这个样本的剩余逻辑处理流程。4.1 算法流程概览HMAC-SHA1阶段已识别输入时间戳18字节输出20字节哈希值结果提取阶段取哈希最后1字节的低4位作为索引根据索引从哈希结果中选取4字节自定义变换阶段与0x7FFFFFFF进行与运算循环处理生成5位输出最终映射阶段使用固定字符集23456789BCDFGHJKMNPQRTVWXY生成7位最终结果4.2 核心变换函数分析样本中的关键函数sub_37A4实现了特殊的除法运算int __fastcall custom_div(int a1, int a2) { int v3 a1 ^ a2; if (a2 1) { if ((v3 ^ a1) 0) a1 -a1; } else { int v4 abs(a1); if (v4 a2) { if (v4 a2) a1 0; if (v4 a2) a1 (v3 31) | 1; } else if ((a2 (a2 - 1)) ! 0) { // 复杂除法实现 int v5 __clz(a2) - __clz(v4); int v6 a2 v5; int v7 1 v5; a1 0; while (true) { if (v4 v6) { v4 - v6; a1 | v7; } if (v4 v6 1) { v4 - v6 1; a1 | v7 1; } if (v4 v6 2) { v4 - v6 2; a1 | v7 2; } if (v4 v6 3) { v4 - v6 3; a1 | v7 3; } if (v4 0) break; v7 4; if (v7 0) break; v6 4; } if (v3 0) a1 -a1; } else { a1 v4 (31 - __clz(a2)); if (v3 0) a1 -a1; } } return a1; }4.3 完整算法还原基于上述分析可以重构完整的算法流程def blackbox_algorithm(timestamp, input_str): # 1. HMAC-SHA1计算 key base64.b64encode(input_str.encode())[:8] hmac_result hmac.new(key, (timestamp1).to_bytes(8, big), sha1).digest() # 2. 结果提取 index hmac_result[-1] 0xF selected_bytes hmac_result[index:index4] int_value int.from_bytes(selected_bytes, big) 0x7FFFFFFF # 3. 自定义变换 charset 23456789BCDFGHJKMNPQRTVWXY result [] for _ in range(5): int_value custom_div(int_value, 26) remainder int_value % 26 result.append(charset[remainder]) # 4. 补充最后两位 # ... (具体逻辑略) return .join(result)这种减法分析方法不仅适用于blackbox样本也可广泛应用于各类混合加密逻辑的逆向工程。通过先识别和排除标准组件我们能更高效地聚焦于真正需要分析的自定义部分大幅提升逆向效率。