通过此前的文章,我们已经掌握了两大框架。在逆向工程的工具链中,它们各司其职: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
[原创]深入浅出 Keystone 框架学习
444 浏览
14 回复
tql
学习一下
学习一下
感谢分享
向大佬学习
学习一下
学习一下
学习了
学习!
学习
学习!
学习了,感谢分享
感谢分享
学习一下