Rev·Deck 是一款本地、单用户的静态分析工作站。它将证据优先的 Web 界面与 LLM 副驾驶(copilot)相结合,作用于由无头 Ghidra 服务分析过的二进制文件:你可以直接浏览确定性证据(函数、字符串、导入、交叉引用、有界调用图),也可以向助手提出有界问题,而助手的任何事实性论断都必须引用可检查的证据。
被分析的二进制文件绝不会被执行。浏览器只与本 Flask 应用通信;该应用将经过验证的类型化请求代理给 Ghidra 服务。
https://github.com/user-attachments/assets/fba14dc5-7ad5-4137-9349-ed824da64fbe
cp .env.example .env # set API_BASE and MODEL_NAME; set API_KEY if required
docker compose up --build
Docker Compose 会自动读取 .env 进行变量插值。如果缺少 API_BASE 或 MODEL_NAME,它会在启动前直接失败;API_KEY=not-used 对本地/免密钥提供商仍然有效。整个服务栈会启动这两个服务。打开 http://127.0.0.1:5000。
如果只想运行 Ghidra 服务:
docker pull biniamfd/ghidra-headless-rest:latest # ensure the newest image
docker run --rm \
-p 127.0.0.1:9090:9090 \
-v "$(pwd)/data:/data/ghidra_projects" \
--security-opt no-new-privileges:true \
biniamfd/ghidra-headless-rest:latest
为了可复现地固定版本,请使用经过测试的发布版摘要(digest),而不是 latest:
docker run --rm \
-p 127.0.0.1:9090:9090 \
-v "$(pwd)/data:/data/ghidra_projects" \
--security-opt no-new-privileges:true \
biniamfd/ghidra-headless-rest:1.2.1@sha256:971591a3a8448d8ed969079b452306e806f36079c3ddd298f4a618d6e2f1442d
biniamfd/ghidra-headless-rest:latest。将 .env.example 复制为 .env 并填写以下变量;完整列表与默认值请参阅该文件。
Rev·Deck 通过 OpenAI SDK 与任何兼容 OpenAI 的 Chat Completions 端点通信,配置完全由 API_BASE / API_KEY / MODEL_NAME 决定。其中没有任何提供商特有的请求头、参数或模型逻辑:本地 Ollama 服务器(API_BASE=http://127.0.0.1:11434/v1)、自托管的 vLLM/llama.cpp/LM Studio 端点、OpenAI 本身,或是 OpenRouter 之类的网关,都能以相同方式工作。
.env 提供商配置示例(请使用占位符,切勿提交真实密钥):
# Ollama
API_BASE=http://127.0.0.1:11434/v1
API_KEY=not-used
MODEL_NAME=qwen3:8b
# OpenRouter
API_BASE=https://openrouter.ai/api/v1
API_KEY=replace-with-your-key
MODEL_NAME=anthropic/claude-opus-4.8
# OpenAI
API_BASE=https://api.openai.com/v1
API_KEY=replace-with-your-key
MODEL_NAME=replace-with-a-supported-model-id
# LM Studio, vLLM, or llama.cpp (adjust port/model to the server)
API_BASE=http://127.0.0.1:1234/v1
API_KEY=not-used
MODEL_NAME=replace-with-the-served-model-id
默认情况下(LLM_STREAM=auto),助手请求流式响应,并将令牌(token)实时转发到浏览器。流式传输还能提供更强的取消保证:当你停止响应(或关闭标签页)时,Rev·Deck 会立即关闭底层提供商流,并且不再进行任何工具或模型轮次,从而直接终止上游生成,而不是让它在后台继续运行到完成。
注意事项:
auto 模式下,如果提供商在产生任何内容或工具调用输出之前,以兼容性错误(HTTP 400/404/405/422)拒绝流式请求,Rev·Deck 会回退为一次阻塞式调用,并在本次进程的剩余时间内记住该选择。认证(401/403)、限流(429)和服务器(5xx)错误不会被视为兼容性问题,而是作为错误呈现,不会被静默重试。设置 LLM_STREAM=false 可完全跳过流式传输;设置 LLM_STREAM=true 则强制要求流式传输(无回退)。打开应用并上传二进制文件即可开始一次分析任务。明显是纯文本的内容在发送给 Ghidra 之前会要求确认;只有当内容确实是有意上传的固件/数据而非可执行格式时,才使用显式的原始二进制(raw-binary)覆盖选项。分析完成后,可在两个工作区标签页之间切换:
两种模式都接受按任务设置的步骤预算(step budget),以及**无步骤限制(No step limit)选项——后者会一直运行到任务结束(仍受 MAX_STEP_BUDGET 上限约束,因此循环模型也无法无限运行)。如果一次运行达到预算,它会报告部分结果,并提供继续(Continue)**选项——该选项使用已检索到的证据恢复同一对话,而不会重做已完成的工具调用。成本随工具/模型调用次数增加而增长,因此预算越高,花费越多。
可用工作流:
每个分析任务都有一个主(Main)聊天,外加可选的聚焦子线程。选择新建子调查(New sub-investigation),输入一行简报,即可在同一个二进制文件和同一组只读工具之上,以全新的对话上下文开展工作。线程历史保持彼此隔离,并且同一时间只有一个线程在进行流式输出。
当聚焦工作完成后,选择将结论返回父线程(Return conclusion to parent)。Rev·Deck 仅针对该子线程执行一次有界模型调用,验证其证据引用,并向父线程添加一张带有来源标记的结论卡片。完整的分支仍然可以重新打开,而父线程上下文只会收到简洁的结论——而非分支的完整记录。未通过验证引用的返回卡片会被明确标记为未验证(unverified)。
助手的回答会以内联方式引用证据,如 [function:0xADDR]、[string:0xADDR] 或 [import:name]。引用会与当轮对话中实际检索到的内容进行核对;不匹配的引用会被标记为“(unverified)”,应视为未经证实的说法,而非事实。
助手输出中的 Mermaid 图表(例如调用图草图)会在沙箱化框架中渲染,且无法访问外部网络。
浏览器只与 Rev·Deck Web 应用通信。Rev·Deck 协调所配置的 LLM 与无头 Ghidra 服务,然后将得到的证据与智能体活动呈现在同一个工作区中。
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
npm ci && npm run vendor # one-time: vendors the pinned Mermaid runtime
cp .env.example .env # edit API_BASE / MODEL_NAME / API_KEY
set -a; source .env; set +a # plain Python does not load .env automatically
# Start the separate Ghidra service, then:
python webui/app.py
打开 http://127.0.0.1:5000。Docker Compose 会自动读取 .env;从源码运行则需要按上文所示的方式导出它。Flask 开发服务器适用于本地使用;Docker 镜像运行 Gunicorn。
本项目是为单个受信任的分析师在自己的机器上使用而设计的——并非用于多用户或公共托管。默认情况下,应用与 Ghidra 服务只绑定到 127.0.0.1,调试模式关闭,上传的二进制文件绝不会被执行,LLM 提供商密钥也始终保留在服务端。
pip install -r requirements.txt -r requirements-dev.txt
python -m pytest
node --test "webui/static/js/tests/**/*.test.mjs"
npm ci && npm run vendor:verify # verifies the vendored Mermaid bundle's integrity
/readyz 返回 503 — 无法在 GHIDRA_API_BASE 访问 Ghidra 服务,或 API_BASE/MODEL_NAME 未设置。API_BASE/API_KEY/MODEL_NAME,并确认提供商在 LLM_TIMEOUT 内可达。MAX_UPLOAD_BYTES。ANALYSIS_TIMEOUT(例如,针对 1 万+ 个函数的 C++/Android 二进制可设为 5400),然后重新上传。LLM_TIMEOUT 与此无关。| 变量 | 默认值 | 含义 |
|---|
API_BASE | 必需 | 兼容 OpenAI 的基础 URL(http/https)。缺失时 Compose 会在启动前失败。 |
API_KEY | not-used | 提供商密钥。绝不会被记入日志或发送到浏览器;not-used 对无密钥的本地提供商有效。 |
MODEL_NAME | 必需 | 所配置端点期望的模型 ID。缺失时 Compose 会在启动前失败。 |
LLM_STREAM | auto | 流式传输方式:auto(流式传输;在产生输出前遇到兼容性错误时回退为一次阻塞式调用)、true(始终流式)、false(始终阻塞)。 |
GHIDRA_API_BASE | http://127.0.0.1:9090 | Ghidra 服务的基础 URL。 |
GHIDRA_IMAGE | biniamfd/ghidra-headless-rest:1.2.1@sha256:971591a3... | 通过不可变摘要固定的、已经过测试的发布版本。:latest 也会解析到此摘要;可覆盖以固定其他发布版本。 |
HOST / PORT | 127.0.0.1 / 5000 | 开发服务器绑定地址。 |
MAX_UPLOAD_BYTES | 104857600 | 上传大小上限。 |
CHATS_DIR | webui/chats | 聊天历史记录目录。 |
| 工作流 | 用途 | 是否需要目标函数地址 |
|---|
program_triage | 根据元数据、导入、字符串和函数总结程序可能的目的。 | 否 |
suspicious_behavior | 先呈现确定性指标,再给出有界且标注清晰的假设。 | 否 |
selected_function | 反编译某个函数,并结合其调用者/被调用者进行解释。 | 是 |
call_chain | 从起始函数出发,探索一个有界的原生/合成调用图邻域。 | 是 |
attack_surface_triage | 读取确定性评分的覆盖率/top-K,然后深入检查至多三个候选;评分是优先级,而非定论。 | 否 |
vulnerability_hypothesis | 选择一个有界候选,并呈现证据、反证和待解决的问题;绝不自动确认。 | 否 |