Python逆向实战从驱动解密到自动化Flag提取在CTF竞赛中逆向工程类题目往往需要选手快速理解程序逻辑并提取关键信息。当面对Windows驱动这类复杂目标时直接逆向分析整个驱动可能效率低下。更聪明的做法是定位关键加密逻辑后用Python快速实现解密流程。本文将分享一套针对驱动逆向的高效解题方法论通过RCTF 2017 MyDriver2这道经典赛题展示如何从零开始构建自动化解密工具链。1. 逆向分析的关键切入点面对一个.sys驱动文件许多选手会陷入必须完全理解驱动工作原理的误区。实际上CTF题目中的驱动往往只包含少量核心逻辑。以MyDriver2为例通过以下步骤可以快速定位关键代码字符串与数据段分析使用IDA Pro快速浏览数据段寻找可疑的加密数据块如qword_16310和qword_16390交叉引用追踪通过数据块的交叉引用定位到核心加密函数sub_113C8参数提取识别函数中的硬编码参数如0xccc12345和0x54321ccc# 关键参数提取示例 key_part1 0xccc12345 key_part2 0x54321ccc逆向过程中发现驱动通过sub_11DF0函数生成主密钥0x5c3113c5这将成为我们解密脚本的基础。值得注意的是这类题目通常会留下明显的线索——比如硬编码的魔数、可预测的加密模式等这些都是快速解题的突破口。2. 密钥生成逻辑还原驱动中的密钥生成函数虽然看似复杂但实际逻辑可以简化为位操作unsigned __int64 __fastcall sub_11DF0(__int64 a1, __int64 a2) { return a2 0xF0F0F0F0F0F0F0F0ui64 ^ a1 0x0F0F0F0F0F0F0F0Fui64; }用Python实现这一逻辑时需要注意整数精度问题。32位和64位Python对长整型的处理可能不同建议明确指定数据类型def generate_key(part1, part2): mask_high 0xF0F0F0F0F0F0F0F0 mask_low 0x0F0F0F0F0F0F0F0F return (part2 mask_high) ^ (part1 mask_low) main_key generate_key(0xccc12345, 0x54321ccc) print(hex(main_key)) # 输出应为0x5c3113c5常见踩坑点位运算操作符优先级建议多用括号明确整数溢出问题Python 3默认支持大整数但与其他语言交互时需注意大小端转换驱动中多为小端序3. 数据解密流程实现原始驱动中的解密分为两个阶段我们的Python脚本需要准确还原这一过程3.1 第一阶段解密块异或处理驱动代码片段v3 qword_16310; do { *v3 ^ v1; // v1是主密钥0x5c3113c5 v3; } while ((signed __int64)v3 (signed __int64)qword_16390);对应的Python实现from pwn import * encrypted_data [ 0x5C5813A25C6E1395, 0x5C5413885C5413B3, 0x5C5013A95C57139A, 0x5C0213F75C6E13A2, 0x5C4913B15C1F13F6, 0x13B1 ] def phase1_decrypt(data, key): result b for block in data: # 处理8字节块注意pwntools的p64处理小端序 result p64(block ^ key) return result key 0x5c3113c55c3113c5 # 64位扩展后的密钥 phase1_output phase1_decrypt(encrypted_data, key) print(phase1_output) # 应输出部分明文注意实际解题时加密数据可能隐藏在驱动文件的特定偏移处需要先用二进制分析工具提取。3.2 第二阶段解密循环异或驱动中的第二轮解密采用循环异或模式do { qword_16390[v6] ^ qword_16310[v4]; v6; v4 (v4 1) % (unsigned __int16)v2; // v242 } while (v6 128);Python实现需要考虑边界条件和字节操作def phase2_decrypt(enc_data, key_stream, key_length): result bytearray() for i, byte in enumerate(enc_data): key_byte key_stream[i % key_length] result.append(byte ^ key_byte) return bytes(result) # 示例使用 phase2_encrypted [ 0x6105664765377470, 0x733A416D730C2011, 0x6E285F096C166D36, 0x6F5C686D6531690B, 0x780002726A5F58, 0x67005F00500074, 0x4D006500760069, 0x6C0066005F0065, 0x32005F00670061, 0x74002E00330033, 0x5F005000740078, 0x65007600690067, 0x66005F0065004D, 0x5F00670061006C, 0x2E003300330032, 0x50007400780074 ] phase2_input b for block in phase2_encrypted: phase2_input p64(block) final_output phase2_decrypt(phase2_input, phase1_output, 42) print(final_output.decode(utf-8)) # 应输出完整Flag4. 完整脚本优化与调试技巧将上述步骤整合为一个完整脚本时还需要考虑以下优化点错误处理增加对数据长度的校验性能优化对大文件采用流式处理调试输出关键步骤添加verbose模式import sys from pwn import * class DriverDecryptor: def __init__(self, verboseFalse): self.verbose verbose def log(self, message): if self.verbose: print(f[*] {message}) def generate_key(self, part1, part2): mask_high 0xF0F0F0F0F0F0F0F0 mask_low 0x0F0F0F0F0F0F0F0F key (part2 mask_high) ^ (part1 mask_low) self.log(fGenerated key: {hex(key)}) return key def decrypt(self, phase1_data, phase2_data): # 第一阶段解密 main_key self.generate_key(0xccc12345, 0x54321ccc) extended_key (main_key 32) | main_key phase1_output b for block in phase1_data: phase1_output p64(block ^ extended_key) self.log(fPhase1 output: {phase1_output[:20]}...) # 第二阶段解密 phase2_input b for block in phase2_data: phase2_input p64(block) key_length 42 result bytearray() for i, byte in enumerate(phase2_input): key_byte phase1_output[i % key_length] result.append(byte ^ key_byte) return bytes(result) if __name__ __main__: decryptor DriverDecryptor(verboseTrue) # 准备测试数据 phase1_test [ 0x5C5813A25C6E1395, 0x5C5413885C5413B3, 0x5C5013A95C57139A, 0x5C0213F75C6E13A2, 0x5C4913B15C1F13F6, 0x13B1 ] phase2_test [ 0x6105664765377470, 0x733A416D730C2011, 0x6E285F096C166D36, 0x6F5C686D6531690B, 0x780002726A5F58, 0x67005F00500074, 0x4D006500760069, 0x6C0066005F0065, 0x32005F00670061, 0x74002E00330033, 0x5F005000740078, 0x65007600690067, 0x66005F0065004D, 0x5F00670061006C, 0x2E003300330032, 0x50007400780074 ] flag decryptor.decrypt(phase1_test, phase2_test) print(\n[] Final Flag:, flag.decode(utf-8))实战建议使用pwntools的context设置统一字节序对驱动文件进行哈希校验确保分析对象正确在脚本中添加自动化测试用例验证中间结果5. 扩展应用与类似题目模式掌握这种驱动解密方法后可以快速解决一类CTF逆向题目。常见变种包括多层加密驱动中实现多个加密阶段需要逐层解密动态密钥密钥通过IOCTL从用户态传入需要跟踪数据流混淆处理加入无用的代码混淆需要识别核心逻辑对于Inline hook类题目如本题最终Flag提示的还需要注意驱动可能修改系统调用表关键函数可能被运行时hook某些API调用可能被重定向# 检测Inline hook的示例代码 import ctypes def check_hook(function_address): kernel32 ctypes.windll.kernel32 old_protect ctypes.c_ulong() kernel32.VirtualProtect(function_address, 4, 0x40, ctypes.byref(old_protect)) original_bytes ctypes.string_at(function_address, 4) kernel32.VirtualProtect(function_address, 4, old_protect, ctypes.byref(old_protect)) return original_bytes在真实比赛环境中建议将这类通用解密逻辑封装为可复用的Python模块并建立自己的CTF工具库。例如可以创建一个DriverAnalyzer类支持自动识别常见加密模式、提取关键数据块等功能。