本节摘要:这一节把 Ghidra 从「听说过」变成「跑起来」。先装两样东西:JDK 21 及以上(Ghidra 12.x 的运行前提)与 Ghidra 12.1.4 发行包(免安装,解压即用)。然后五分钟建起首个工程:新建 Non-Shared Project、导入第 0.2 节编译的 demo、双击进入 CodeBrowser。接着导览界面的四大块——符号树、反编译器窗口、函数列表、控制台——以及它们如何联动。再把 demo_stripped 也导进同一工程,形成「带符号版对答案、去符号版做练习」的双样本布局。最后跑自动分析并解释每个主要选项在做什么,附一张常见卡点排查表。本节结束时,你的 Ghidra 工程里躺着两个分析完毕、可以双击任何函数看伪代码的程序。
Ghidra 是 Java 应用,先装 JDK 再解压发行包,两步都不需要安装器。
| 项 | 口径(社区,2026-10) | 说明 |
|---|---|---|
| JDK | 21 及以上 | 具体要求以 Ghidra 官方发行说明为准;推荐 Temurin 等主流发行版 |
| Ghidra | 12.1.4,Apache-2.0 | NSA 开源,约 8.9 万 stars;官方发布页下载 zip |
# bash —— 安装自检:两行都有正常输出才算过关 java -version # 期望:openjdk version "21..." 或更高 unzip ghidra_12.1.4_PUBLIC.zip -d /opt/ # 解压即完成"安装" /opt/ghidra_12.1.4_PUBLIC/ghidraRun # Linux/macOS 启动;Windows 用 ghidraRun.bat
版本口径说明:本书所有版本号为 2026-10 社区口径,安装细节(JDK 供应商、路径、启动脚本)以 Ghidra 官方文档为准。内存小的机器(8 GB 以下)建议在启动配置里调低最大堆,具体参数以官方 FAQ 为准。
首次启动会问是否建立工程目录(默认在用户主目录下),保持默认即可。看到 Project Window(工具箱风格的窗口)就是启动成功。
工程(Project)是 Ghidra 与「打开就看」类工具最大的区别:分析结果、重命名、注释都存在工程文件里,下次打开接着用。
步骤(以 12.x 界面为准,菜单名以实际版本为准):
re-lab。bin/demo。Project Window CodeBrowser(双击程序后打开) ┌───────────────────┐ ┌──────────────────────────────┐ │ 程序树:demo │ 双击 │ 符号树 │ 代码/伪代码 │ 杂项窗口 │ │ (可继续导入多个) │ ────────────▶ │ │ │ │ └───────────────────┘ └──────────────────────────────┘
CodeBrowser 的窗口都能从 Window 菜单开关,初学盯住四个就够:
| 窗口 | 职责 | 关键动作 |
|---|---|---|
| Symbol Tree(符号树) | 按类别浏览符号:导入、导出、函数、字符串 | 双击符号跳转定义 |
| Listing(反汇编视图) | 逐指令反汇编,程序的主战场 | 滚动浏览、右键引用 |
| Decompiler(反编译器) | 当前函数的伪 C,与 Listing 同步 | 点击变量高亮、直接重命名 |
| Functions(函数列表) | 全部函数的名、入口、大小、命名来源 | 排序找可疑函数 |
联动的核心是「光标即焦点」:在 Listing 里点一个地址,Decompiler 跳到对应行;在伪 C 里点一个变量,Listing 高亮相关指令。这个联动就是后面第 03 章模型「读函数」的基础——模型读的就是 Decompiler 里的文本。
┌──────────────┬───────────────────────────┬───────────────┐ │ Symbol Tree │ Decompiler(伪 C) │ Functions │ │ Imports │ int check_key(char *s) │ main │ │ Exports │ { │ check_key │ │ Functions │ char buf[32]; │ deobfuscate │ │ Strings │ deobfuscate(...); │ ... │ └──────┬───────┴──────────┬────────────────┴───────┬───────┘ │ 双击跳转 │ 与 Listing 同步 │ 双击跳函数 ▼ ▼ ▼ ┌───────────────────────────────────────────────────────────┐ │ Listing:PUSH RBP / MOV RBP,RSP / CALL 0x00401189 ... │ └───────────────────────────────────────────────────────────┘
回到 Project Window,用同样的 Import File 流程把 bin/demo_stripped 也导进来。现在程序树里有两个程序:
双样本布局是全书反复使用的方法:先在带符号版上建立「正确长什么样」的直觉,再去去符号版上验证方法是否成立。真实工作里你只有后者,但练习时永远值得先造一个前者。
两个注意点:导入后每个程序在工程里独立保存,互不影响;同一程序重复导入会生成副本并提示重名,选 Skip 跳过即可。
在 CodeBrowser 里打开 demo,触发分析(Analysis → Auto Analyze 或首次弹窗)。默认勾选的分析器已经覆盖入门场景,重点认识四个:
| 分析器 | 作用 | 对 demo 的意义 |
|---|---|---|
| Decompiler Parameter ID | 用反编译结果修正函数参数类型 | check_key 的参数显示为 char * 而非 int |
| Function Start Search | 在未定义区域找函数开头 | 找齐 static 小函数 |
| Aggressive Instruction Finder | 在数据区里尝试识别代码 | demo 用不到,混淆样本会用到 |
| Reference | 建立交叉引用索引 | 「谁调用了 check_key」能点出来 |
点 Analyze,demo 这种小程序几秒完成;大样本可能要几分钟到更久,期间右下角有进度。分析完成后:Functions 窗口出现 main、check_key、deobfuscate 等函数——因为你编译时带了 -g,符号表还在,名字直接可用。
顺手做两个验证:在 Functions 里双击 check_key,Decompiler 出现伪 C;在伪 C 的 strcmp 行右键查看引用,能看到 main 里的调用点。这两个动作下一节展开成完整方法。对 demo_stripped 重复同样的分析流程, Functions 里将只剩 entry 与 FUN_ 开头的函数——这就是第 1.2 节的出发点。
| 症状 | 原因 | 解法 |
|---|---|---|
| 启动脚本报 JDK 版本错误 | JDK 低于要求 | 装 JDK 21+,确认 java -version |
| 界面闪烁或直接退出 | 显卡 / 显示缩放兼容问题 | 按官方 FAQ 调整 Java 2D 参数 |
| 导入时 Format 识别错误 | 罕见格式或加了壳 | 手动指定 Language;壳的识别见纵深篇 |
| 分析卡住不动 | 超大样本或死循环式混淆 | 先取消,改用 headless(1.3 节)分块处理 |
| 找不到自动分析提示 | 曾选过「不再提示」 | 菜单 Analysis → Auto Analyze 手动触发 |
| 工程打不开 / 报锁定 | 工程被另一个 Ghidra 实例占用 | 关掉旧实例或删除锁文件(以官方 FAQ 为准) |
最后一行是伏笔:界面适合「一个程序精读」,批量与自动化要靠命令行——这正是 1.3 节的主题。
工具跑起来了,但「能打开」不等于「会读」。下一节练老手艺的核心:在伪 C 与交叉引用之间来回,把 stripped 程序读明白,并把理解用重命名和注释写回工程。