DASCTF 2022 WriteUp 逆向实战:IDA Pro 7.7 动态调试解 RC4 魔改混淆(附完整脚本)

📅 2026/7/12 4:06:38
DASCTF 2022 WriteUp 逆向实战:IDA Pro 7.7 动态调试解 RC4 魔改混淆(附完整脚本)
DASCTF 2022 逆向实战IDA Pro 7.7 动态调试解 RC4 魔改混淆附完整脚本1. 题目背景与初步分析本次分析的题目来自DASCTF 2022赛事中的Re easyre逆向工程挑战。题目提供了一个经过混淆处理的二进制文件主要考察选手对自修改代码(SMC)的识别能力以及对魔改加密算法的逆向分析技巧。首先使用IDA Pro 7.7加载目标文件初步分析发现以下几个关键特征程序入口点存在大量无效指令这是典型的代码混淆手段关键函数被分割成多个片段通过跳转指令连接存在动态解密代码段的操作说明采用了SMC技术提示在分析这类题目时建议先运行程序并附加调试器观察其实际行为模式2. 动态调试环境配置为了有效分析自修改代码我们需要配置合适的调试环境# IDA Python调试脚本初始化 import idaapi import idc def set_debug_options(): # 启用硬件断点 idaapi.set_dbg_options(idaapi.DBGOPT_ENABLE_HWBPT) # 禁止调试器跳过库函数 idaapi.set_dbg_options(idaapi.DBGOPT_SKIP_NONE) # 启用内存补丁检测 idaapi.set_dbg_options(idaapi.DBGOPT_MEMORY_PATCHES)关键调试参数配置参数值说明DebuggerLocal Windows debugger本地调试器选择Suspend onLibrary load/unload库加载时暂停TracingInstruction tracing指令级跟踪3. 识别自修改代码段通过动态调试我们发现程序在0x401000处执行了代码解密操作。以下是解密过程的伪代码void decrypt_code(uint8_t* code_start, uint32_t size) { uint8_t key 0x71; for(uint32_t i 0; i size; i) { code_start[i] ^ key; key (key * 0x1F) 0xFF; } }使用IDA Python脚本自动化解密过程def decrypt_range(start_ea, end_ea): key 0x71 for ea in range(start_ea, end_ea): b idaapi.get_byte(ea) idaapi.patch_byte(ea, b ^ key) key (key * 0x1F) 0xFF print(fDecrypted code from {hex(start_ea)} to {hex(end_ea)}) # 应用解密到关键区域 decrypt_range(0x401000, 0x401500)4. RC4魔改算法分析解密后可以识别出程序使用了修改版的RC4算法。与传统RC4相比主要差异如下密钥调度阶段增加了额外的混淆运算引入了动态生成的轮常数def modified_rc4_init(key): S list(range(256)) j 0 for i in range(256): j (j S[i] key[i % len(key)] 71) % 256 # 额外加71 S[i], S[j] S[j], S[i] S[i] (S[i] 33) 0xFF # 每轮额外操作 return S密钥流生成阶段增加了位移和掩码操作引入了与位置相关的变换def modified_rc4_keystream(S, data_len): i j 0 keystream [] for k in range(data_len): i (i 1) % 256 j (j S[i]) % 256 S[i], S[j] S[j], S[i] t (S[i] S[j]) % 256 keystream.append((S[t] k % 0xD) 0xFF) # 位置相关变换 return keystream5. 完整解密脚本实现基于上述分析我们编写完整的解密脚本#include stdio.h #include stdint.h void rc4_init(uint8_t *key, uint8_t *S, size_t key_len) { int j 0; for(int i 0; i 256; i) { S[i] i; } for(int i 0; i 256; i) { j (j S[i] key[i % key_len] 71) % 256; S[i] ^ S[j]; S[j] ^ S[i]; S[i] ^ S[j]; S[i] (S[i] 33) 0xFF; } } void rc4_decrypt(uint8_t *key, uint8_t *data, size_t data_len) { uint8_t S[256]; rc4_init(key, S, strlen((char*)key)); int i 0, j 0; for(size_t k 0; k data_len; k) { i (i 1) % 256; j (j S[i]) % 256; uint8_t tmp S[i]; S[i] S[j]; S[j] tmp; uint8_t t (S[i] S[j]) % 256; data[k] (data[k] - 71) ^ S[t]; // 逆向魔改操作 } } int main() { uint8_t encrypted[] { /* 填入加密数据 */ }; uint8_t key[] 123456; // 分析得到的密钥 rc4_decrypt(key, encrypted, sizeof(encrypted)); printf(Decrypted: %s\n, encrypted); return 0; }6. 动态调试技巧与验证在实际调试过程中以下几个技巧特别有用内存断点设置在关键数据区域设置写入断点捕获解密过程idaapi.add_bpt(0x492A60, 0, BPT_WRITE)函数调用跟踪记录所有调用的函数及其参数def trace_call(): print(fCall to {hex(idaapi.get_reg_val(eip))} with:) print(fEAX{hex(idaapi.get_reg_val(eax))}) print(fEBX{hex(idaapi.get_reg_val(ebx))})数据流分析跟踪关键数据的生成和使用过程def track_data_flow(start_ea, reg_name): ea start_ea while ea ! idaapi.BADADDR: print(f{hex(ea)}: {idaapi.generate_disasm_line(ea, 0)}) ea idaapi.next_head(ea)7. 逆向工程思维过程解决此类问题的核心思维流程行为分析运行程序观察基本行为使用Process Monitor监控文件/注册表操作静态分析识别加密/解密函数特征查找字符串引用和API调用动态验证在调试器中验证静态分析假设修改关键变量观察程序反应算法还原提取加密逻辑转换为高级语言编写逆向算法验证结果通过这种方法我们最终成功解密出flagDASCTF{Welc0me-t0-j01n-SU-l0ve-suyug1eg1e}