论坛首页 逆向工程技术区 阅读主题

[原创]深入浅出 Keystone 框架学习

444 浏览 14 回复
#1 楼主 2026-06-01 21:09:11
通过此前的文章,我们已经掌握了两大框架。在逆向工程的工具链中,它们各司其职:Unicorn (大脑) :负责跑代码。它模拟 CPU 的状态流转与内存交互。[原创]深入浅出 Unicorn 框架学习Capstone (眼睛) :负责看代码。它将枯燥的机器码翻译成人类可读的汇编语言。[原创]深入浅出 Capstone 框架学习然而,仅有“大脑”和“眼睛”是不够的。当我们想要修改程序的逻辑(例如 Patch 掉反调试检查、注入 Shellcode)时,我们需要——Keystone (双手) 。Keystone 是一个轻量级、多平台、多架构的汇编框架。它的作用与 Capstone 正好相反:Capstone 将机器码转为汇编,而 Keystone 将汇编代码编译回机器码。在 Python 脚本中,我们主要使用以下两个类:​​Ks​​ (Keystone Engine)
这是汇编引擎的主入口。你需要实例化它来创建一个汇编器对象。​​KsError​​ (Exception)
异常处理类。当你的汇编代码有语法错误(如拼写错误、操作数不匹配)时,Keystone 会抛出此异常。Keystone 的常量命名规范与 Unicorn/Capstone 保持高度一致,只需将前缀 UC_​ 或 CS_​ 换成 ​KS_​ 即可。​常用组合对照表:对于 x86 架构,汇编语言有不同的格式。Keystone 允许通过 KS_OPT_SYNTAX 选项来切换语法风格。​​KS_OPT_SYNTAX_INTEL​ (默认):Intel 语法。​​KS_OPT_SYNTAX_ATT​:AT&T 语法。​​KS_OPT_SYNTAX_NASM​:NASM 语法。​设置方法:在将 Keystone 集成到 Unicorn 之前,我们先单独运行它,体验一下如何将一句汇编代码翻译成机器码。目标将汇编指令 "xor rax, rax; inc rax" 编译为 x64 机器码。示例代码:运行结果:​ks.asm()​ 方法的返回值是一个元组 (encoding, count) :​​encoding​​ (list[int]) :​​count​​ (int) :​需求​:
在逆向分析中,我们经常遇到反调试指令(如 RDTSC​、CPUID​)或者不需要执行的垃圾代码。
假设在地址 0x400000​ 处有一条复杂的指令(例如 XOR EAX, EAX​,长度 2 字节),我们希望将其“抹去”,替换为 NOP(空指令),让 CPU 什么都不做直接滑过去。示例代码:运行结果:​需求​:
在破解 CrackMe 或去除混淆时,我们经常遇到关键的分支跳转,例如 TEST EAX, EAX; JZ 0xTarget​。如果验证失败,程序会跳转到错误处理分支。
我们的目标是:强制将 JZ​(条件跳转)修改为 JMP(无条件跳转),确保程序始终走向我们预期的路径,从而绕过校验。​核心挑战 (JIT 陷阱) ​:
Unicorn 使用 JIT(即时编译)技术。如果在 UC_HOOK_CODE​ 回调中动态修改当前指令的内存,CPU 实际上已经完成了该指令的取指和解码,Patch 仅对下一次执行有效。
因此,对于确定的逻辑修改,最佳实践是在模拟启动前 (Pre-Patch) 就完成内存修改。示例代码:运行结果:通过这种方式,我们成功地利用 Keystone 改变了程序的控制流,让它按照我们的意愿执行了跳转逻辑。​需求​:
有时我们需要在程序的空白区域(Cave)注入一段全新的逻辑,比如打印调试信息、Dump 内存数据等。
我们需要在内存 0x500000​ 处写入一段 Shellcode,调用 Linux 的 write 系统调用打印 "HACKED",然后控制 CPU 跳转执行。示例代码:运行结果:通过 Keystone,我们无需手动拼凑机器码,直接用汇编语言就实现了复杂的代码注入功能。在基础用法之外,Keystone 还提供了一些高级特性来应对特定的编译需求,比如切换汇编风格、处理相对地址计算以及解析符号标签。对于 x86 架构,汇编语言存在多种格式。Keystone 默认使用逆向工程中最通用的 Intel 语法,但也完美支持 Linux/GDB 风格的 AT&T 语法 以及更严格的 NASM 语法。支持的语法常量:​​KS_OPT_SYNTAX_INTEL​ (默认):Intel 语法。​​KS_OPT_SYNTAX_ATT​:AT&T 语法。​​KS_OPT_SYNTAX_NASM​:NASM 语法。下面的代码展示了如何切换语法,并验证两种写法的编译结果是否一致。运行结果:在编写汇编代码时,使用标签(Label)跳转是人类的本能,例如 jmp loop_start。然而,Keystone 是一个轻量级编译器,在 Python 绑定中默认并不支持复杂的符号解析回调(Symbol Resolver Callback)。Pythonic 解决方案:利用 Python 强大的字符串格式化功能(f-string),在将代码送入 Keystone 编译之前,手动完成符号的“链接”工作。示例:假设我们需要在地址 0x401020​ 处编写一段逻辑,其中包含跳转到 0x401000​ 和 0x401050 的指令。运行结果:至此,我们已经学完了二进制分析与逆向工程的“三剑客”。这三个框架各司其职,共同构成了一个完整的操控闭环:协作流程图: ‍# 正确做法:安装 Keystone 汇编引擎

---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-289573.htm
#2 2026-06-01 21:09:11
tql
#3 2026-06-01 21:09:11
学习一下
#4 2026-06-01 21:09:11
学习一下
#5 2026-06-01 21:09:11
感谢分享
#6 2026-06-01 21:09:11
向大佬学习
#7 2026-06-01 21:09:11
学习一下
#8 2026-06-01 21:09:11
学习一下
#9 2026-06-01 21:09:11
学习了
#10 2026-06-01 21:09:11
学习!
#11 2026-06-01 21:09:11
学习
#12 2026-06-01 21:09:11
学习!
#13 2026-06-01 21:09:11
学习了,感谢分享
#14 2026-06-01 21:09:11
感谢分享
#15 2026-06-01 21:09:11
学习一下

请登录后参与讨论

立即登录 注册账号