这个实验性的 Ghidra 插件让你能够轻松处理原生 pcode 模拟。不再需要编写脚本,可以直接在 Ghidra 中使用它。它对于处理各种常见模拟器不支持的非主流处理器尤为有用。
如果处理器/虚拟机受 Ghidra 支持以进行逆向工程,它就可以被模拟!例如,下面演示了 eBPF 指令模拟:

本质上,该插件是对 ghidra.app.emulator 包内类的扩展包装。以下是已实现的功能:
尽管 PCode 模拟在理想情况下意味着统一性,但大多数处理器需要各自专属的处理方式。欢迎随时报告你遇到的问题。我确实很想测试所有处理器,但这几乎不可能。

包含所有插件窗口:栈视图、寄存器、断点视图和主窗口。

包含用于设置模拟开始与结束、断点以及将变更字节应用到模拟器状态的热键。

你可以按需修改寄存器。设置链接寄存器(绿色箭头)有助于模拟器判断哪个寄存器包含返回地址。该插件了解如何通过栈、lr 寄存器、AARCH64 和 MIPS 寄存器工作。如果你遇到的是非主流的处理器/虚拟机,请选择链接寄存器并点击按钮。

当你在 CodeBrowser 中打开程序时,GhidraEmu 会自动映射栈空间。栈指针将设置在栈范围的中间。这样你可以在栈帧的顶部或底部设置值。如果在更新或重置时遇到卡顿,请滚动它。在模拟过程中,如果程序需要更多栈空间,插件会自动分配。


如果模拟期间有任何字节发生变化,你会在经典 ByteViewer 中看到它们。别担心,按下 "Reset" 按钮后,它们将重置为原始值。

如果你做了更改,请让模拟器知道已变更的字节(栈会自动更新——无需操作)。更改后,选中这些字节(它们会显示为绿色),然后点击此选项(或使用热键 "M")。

插件在此打印输出信息。例如,类似下面的模拟错误消息:

“Jump Over” 功能允许你出于某种原因不想模拟当前指令时,向前跳过一条指令。由于一旦检测到尝试读取未初始化的内存,模拟进程就会中止,因此该功能允许你绕过此问题。看一个例子。这是许多 x86_64 程序中的首批指令之一,用于保存 canary 栈:
MOV RAX, qword ptr FS:[0x28]
我们只需稍微“作弊”一下,通过增大 PC 值来跳过它。为此,请在你不想模拟的指令处停下,然后按 J 热键。否则,继续单步执行将导致未初始化内存读取错误。

如果你停在一个通向子程序(内部调用)的指令处,并且希望模拟执行到下一条指令(经典的“step over”),请按 F6 热键,事情就会如你所愿:

几点重要事项需要留意:
使用 gradle 构建扩展:GHIDRA_INSTALL_DIR=${GHIDRA_HOME} gradle,然后使用 Ghidra 安装它:File → Install Extensions...
在 CodeBrowser 中,进入 File → Configure → Miscellaneous,然后勾选 GhidraEmu 插件。
在使用插件时遇到任何 bug,或者有改进的想法?别害羞,尽管打开新的 issue,我会处理的。
EmulatorHelper 的限制不允许在另一个空间中使用程序空间。因此,例如,你的外部共享库永远不会知道程序内存空间,反之亦然。所以你无法将其当作具有单一内存空间的单一进程来模拟。如果我在这里遗漏了什么,请告诉我。