dsh-plugin-rea 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -1
- package/README.md +90 -41
- package/assets/make-screenshots.ps1 +153 -0
- package/assets/screenshot-1.png +0 -0
- package/assets/screenshot-2.png +0 -0
- package/check-updates.ps1 +140 -57
- package/cordis.patch.yml +23 -18
- package/examples/cordis.patch.posix.yml +18 -0
- package/examples/cordis.patch.with-env.yml +42 -0
- package/package.json +6 -3
- package/screenshots.json +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,13 +2,53 @@
|
|
|
2
2
|
|
|
3
3
|
本插件遵循语义化版本。版本号变化说明「配置组合」这层的变化,与 REA 自身的版本无关。
|
|
4
4
|
|
|
5
|
+
## 1.0.5 — 2026-10-13
|
|
6
|
+
|
|
7
|
+
把 1.0.4 留下的形状问题收尾,并让承诺过的 CI 真正跑在仓库上。
|
|
8
|
+
|
|
9
|
+
- **CI 首次真正进仓库**:1.0.4 的 CHANGELOG 与 README 都写了 `validate.yml` / `release.yml`,
|
|
10
|
+
但 `.github/` 当时没有提交,GitHub 上 `actions/workflows` 是空的——现已推送并在 push 上跑通。
|
|
11
|
+
- **校验范围扩到示例**:机器路径检查从只查 `cordis.patch.yml` 扩到 `examples/*.yml`(读者会照抄的文件);
|
|
12
|
+
新增一步断言 npm 包必须带齐 `screenshots.json`、`assets/`、`examples/`——`files[]` 的回归守卫。
|
|
13
|
+
- **`examples/cordis.patch.with-env.yml` 不再提供可照抄的假路径**:原来的 `C:\tools\...` 是编造值,
|
|
14
|
+
现改为 `<your Ghidra 12.1.x extraction directory>`,并补上 `!!js process.env.GHIDRA_INSTALL_DIR`
|
|
15
|
+
这一「安装者零改配置」的写法(entry-list dialect 支持 `!!js`;引擎变量本来就会被 MCP 子进程继承)。
|
|
16
|
+
- **`check-updates.ps1` 加固**:`Test-NodeEngines` 去掉会先于函数体抛异常的类型约束;
|
|
17
|
+
两个 registry 都查不通时不再静默跳过版本比对;`rea` 优先解析 `rea.cmd`(与发布行的
|
|
18
|
+
`cmd.exe /c rea` 对齐,此前 `Get-Command rea` 会先命中 `.ps1` 垫片);`rea doctor` 非零退出码会提示。
|
|
19
|
+
- **`assets/make-screenshots.ps1` 补 BOM**:该文件自己的注释要求 UTF-8 with BOM,此前漏做。
|
|
20
|
+
- **`package.json` description 真正缩短**:239 → 约 186 字符(1.0.4 只是改写,仍会被 npm 列表页截断)。
|
|
21
|
+
- **文档口径修正**:README 的 harness 版本拆成「桌面运行时 / 自带 dsh CLI」两个口径;
|
|
22
|
+
投稿条目注释里的 Release 版本改为当前值。
|
|
23
|
+
|
|
24
|
+
## 1.0.4 — 2026-10-13
|
|
25
|
+
|
|
26
|
+
按外部评审修订:发布物不再携带任何机器相关路径。
|
|
27
|
+
|
|
28
|
+
- **发布用的那一行改为可移植**:Windows 用 `cmd.exe /c rea mcp`(走 PATH),macOS/Linux 用
|
|
29
|
+
`command: rea` + `args: ['mcp']`;`cordis.patch.yml` 里**不再出现** `D:\...` 之类的绝对路径。
|
|
30
|
+
- **新增 `examples/`**:`cordis.patch.posix.yml`(POSIX 变体)、`cordis.patch.with-env.yml`(需要为
|
|
31
|
+
MCP 子进程固定引擎环境时的写法)。
|
|
32
|
+
- **机器相关值改放本机 profile 覆盖**(`id: mcp-rea` 的 id-targeted config override)。README 两个
|
|
33
|
+
语言版本都补了这一工作流;profile 覆盖永不随插件发布。
|
|
34
|
+
- **`check-updates.ps1` 重写**:Node engines 判断改为按 `^`/`~`/`>=` 逐项匹配(此前 Node 26+ 会误报,
|
|
35
|
+
且 `[version]'6.5.0-rc.1'` 会抛异常);node/rea/npm 不在 PATH 时有降级路径;profile 结构访问加防御;
|
|
36
|
+
识别本机 profile 是否覆盖了 `mcp-rea`。
|
|
37
|
+
- **`files` 白名单补齐** `screenshots.json`、`assets/`、`examples/`(npm 包里也带上展示图与示例)。
|
|
38
|
+
- **`package.json` description 缩短**(npm 列表页会截断长描述)。
|
|
39
|
+
- **新增 CI**:`.github/workflows/validate.yml` 校验 manifest/JSON/YAML,并**守住"发布物不得含机器
|
|
40
|
+
绝对路径"**这条约束;`.github/workflows/release.yml` 在发 Release 时自动打包成版本无关资产名并上传,
|
|
41
|
+
另含(默认关闭的)npm Trusted Publishing 发布任务。
|
|
42
|
+
- **README 顶部去掉 awesome 徽章**:本插件尚未被该列表收录,收录后再加回。
|
|
43
|
+
|
|
5
44
|
## 1.0.3 — 2026-10-12
|
|
6
45
|
|
|
7
46
|
仓库展示与发布范围调整,无行为变更。
|
|
8
47
|
|
|
9
48
|
- 新增 `assets/screenshot-1.png`、`assets/screenshot-2.png` 与 `screenshots.json`(市场详情页展示用,
|
|
10
49
|
由 `assets/make-screenshots.ps1` 可复现生成)。
|
|
11
|
-
-
|
|
50
|
+
- 维护记录改为**仅本机保留**:本机维护记录 `docs/project-notes.md` 既不进仓库也不进 tarball;
|
|
51
|
+
投稿条目 `docs/marketplace-entry.yml` 留在仓库里,但不进 npm 包。
|
|
12
52
|
|
|
13
53
|
## 1.0.2 — 2026-10-12
|
|
14
54
|
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# dsh-plugin-rea
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/dsh-plugin-rea)
|
|
4
4
|
|
|
5
5
|
把 **[REA — Reverse Engineer Anything](https://github.com/morluto/rea)** 接入 **DeepSeek Harness (dsh)**:
|
|
6
6
|
一个**纯配置型 Cordis bundle**,复用官方 MCP 客户端插件 `@deepseek-ai/dsh-mcp-client`,
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
> - 上游项目:**REA — Reverse Engineer Anything** — <https://github.com/morluto/rea>(MIT)
|
|
13
13
|
> - 上游文档:<https://github.com/morluto/rea#what-you-can-analyze> · [中文](https://github.com/morluto/rea/blob/main/README_zh.md#可以分析什么) · 站点 <https://rea.tools/>
|
|
14
14
|
> - 上游 npm 包:`rea-agents`
|
|
15
|
-
> - 本插件仓库:**<https://github.com/czcdr/dsh-plugin-rea>**
|
|
15
|
+
> - 本插件仓库:**<https://github.com/czcdr/dsh-plugin-rea>** · npm:`dsh-plugin-rea`
|
|
16
16
|
> - 问题反馈:REA 本身的问题请提到上游;本插件的问题提到 [本仓库 Issues](https://github.com/czcdr/dsh-plugin-rea/issues)。
|
|
17
17
|
|
|
18
18
|
---
|
|
@@ -40,8 +40,8 @@ packages and assets; process behavior; plus offline ELF layout, EVM bytecode, re
|
|
|
40
40
|
and saved network captures.
|
|
41
41
|
|
|
42
42
|
**What this plugin adds.** Exactly two things: it registers that MCP server into DSH's tool layer
|
|
43
|
-
under the `mcp__rea__*` names, and it
|
|
44
|
-
|
|
43
|
+
under the `mcp__rea__*` names, and it lets the engine environment (`GHIDRA_INSTALL_DIR`, …) be scoped
|
|
44
|
+
to that MCP child process instead of the whole harness.
|
|
45
45
|
|
|
46
46
|
**What it can and cannot do.** The analysis is upstream's; this section only restates upstream's own
|
|
47
47
|
contract so expectations are right.
|
|
@@ -59,41 +59,65 @@ contract so expectations are right.
|
|
|
59
59
|
re-implementation, security review, migration reference. To obtain actual source code, use the
|
|
60
60
|
legitimate route — the upstream repository, vendor authorisation, or the vendor's own SDK.
|
|
61
61
|
|
|
62
|
-
**Verified against** (author's machine, 2026-10-12):
|
|
62
|
+
**Verified against** (author's machine, 2026-10-12/13):
|
|
63
63
|
|
|
64
64
|
| Component | Version |
|
|
65
65
|
|---|---|
|
|
66
66
|
| REA (`rea-agents`) | **6.4.0** |
|
|
67
|
-
| DeepSeek Harness
|
|
67
|
+
| DeepSeek Harness | desktop runtime **0.2.0-rc.2**, with its bundled dsh CLI 0.1.7-rc.2 |
|
|
68
68
|
| `@deepseek-ai/dsh-mcp-client` (row provider) | bundled by the harness; npm latest `0.0.1-rc.1` |
|
|
69
69
|
| Ghidra | 12.1.4 (REA currently accepts 12.1.x) |
|
|
70
70
|
| Node.js | 24.21.0 (REA engines: `^22.19.0 \|\| ^24.11.0 \|\| >=26.0.0`) |
|
|
71
71
|
| Host | Windows 11 x64 |
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
native engine.
|
|
73
|
+
The shipped row was exercised live: `list_documents` answered through the `cmd.exe` form, and
|
|
74
|
+
`open_binary` completed with the `ghidra` provider while the engine directory came only from a
|
|
75
|
+
profile-level override.
|
|
77
76
|
|
|
78
|
-
**
|
|
79
|
-
|
|
77
|
+
**Prerequisites.** Node.js (a version REA accepts) and the REA CLI installed globally
|
|
78
|
+
(`npm i -g rea-agents`). For native analysis, Ghidra 12.1.x (Hopper / IDA are alternatives under
|
|
79
|
+
their own licences). Static JavaScript/Electron and .NET analysis need no engine.
|
|
80
|
+
|
|
81
|
+
**Install.**
|
|
80
82
|
|
|
81
83
|
```
|
|
82
84
|
dsh plugin --profile <profile> add github:czcdr/dsh-plugin-rea
|
|
85
|
+
# or, from npm:
|
|
86
|
+
dsh plugin --profile <profile> add dsh-plugin-rea
|
|
83
87
|
```
|
|
84
88
|
|
|
85
89
|
A prebuilt tarball is attached to [Releases](https://github.com/czcdr/dsh-plugin-rea/releases)
|
|
86
|
-
(version-free asset name, so the link keeps resolving).
|
|
87
|
-
|
|
90
|
+
(version-free asset name, so the link keeps resolving).
|
|
91
|
+
|
|
92
|
+
**Configure — usually nothing.** The shipped row carries **no machine-specific path**:
|
|
93
|
+
|
|
94
|
+
- Windows: `command: cmd.exe`, `args: ['/c', 'rea', 'mcp']` — the npm shim is a `.cmd`, so a shell is
|
|
95
|
+
required.
|
|
96
|
+
- macOS/Linux: `command: rea`, `args: ['mcp']` — see
|
|
97
|
+
[`examples/cordis.patch.posix.yml`](examples/cordis.patch.posix.yml).
|
|
98
|
+
|
|
99
|
+
The only optional piece is the analysis engine. REA reads `GHIDRA_INSTALL_DIR` from its environment,
|
|
100
|
+
so either:
|
|
88
101
|
|
|
89
|
-
|
|
102
|
+
1. set it as an **OS-level environment variable** and (re)start the harness, or
|
|
103
|
+
2. pin it for the MCP child only — see
|
|
104
|
+
[`examples/cordis.patch.with-env.yml`](examples/cordis.patch.with-env.yml).
|
|
90
105
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
106
|
+
Either way the variable reaches REA without any literal path: the client hands the parent
|
|
107
|
+
environment to the child (minus names that look like secrets), and the patch dialect evaluates
|
|
108
|
+
`!!js` expressions, so `GHIDRA_INSTALL_DIR: !!js process.env.GHIDRA_INSTALL_DIR` also works.
|
|
109
|
+
|
|
110
|
+
**Keep machine-specific values out of the plugin.** Override the row from your own profile's
|
|
111
|
+
`cordis.patch.yml` (id-targeted config override). That file is machine-local and never published:
|
|
112
|
+
|
|
113
|
+
```yaml
|
|
114
|
+
- id: mcp-rea
|
|
115
|
+
config:
|
|
116
|
+
env:
|
|
117
|
+
GHIDRA_INSTALL_DIR: '<your Ghidra 12.1.x directory>'
|
|
118
|
+
```
|
|
94
119
|
|
|
95
|
-
|
|
96
|
-
harness sees. `env.JAVA_HOME` is optional (only needed when `java` is not on `PATH`).
|
|
120
|
+
Only one row may use `serverName: rea` in a profile.
|
|
97
121
|
|
|
98
122
|
**Verify.** Ask for a `mcp__rea__*` call — `binary_session` reports the engine checks
|
|
99
123
|
(`configuration` / `installation` / `headless` / `native_decompiler` / `java`), all of which should be
|
|
@@ -107,17 +131,18 @@ artifacts you are authorized to inspect.
|
|
|
107
131
|
**Updating — two independent things, both manual.**
|
|
108
132
|
|
|
109
133
|
- **This plugin** never updates itself. Installed from a plugin market? Update it **in that market**.
|
|
110
|
-
Installed from a local `file:` checkout
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
(`scripts/rea.mjs`) is stable across releases, so this needs no change here.
|
|
134
|
+
Installed from a local `file:` checkout? Overwrite the directory and install it again. Updating REA
|
|
135
|
+
below does **not** update this plugin, and updating this plugin does not touch REA.
|
|
136
|
+
- **Upstream REA**: `npm i -g rea-agents@latest`. Its `bin` entry (`scripts/rea.mjs`) is stable across
|
|
137
|
+
releases, so this needs no change here.
|
|
115
138
|
- **Ghidra** is version-gated by REA (12.1.x today): update REA first, then check that it accepts a
|
|
116
139
|
newer Ghidra.
|
|
117
140
|
- **DeepSeek Harness**: a harness upgrade may change the MCP client's config schema — inspect the row
|
|
118
141
|
with `Config.listConfigs name=@deepseek-ai/dsh-mcp-client` and adjust the field names.
|
|
119
142
|
|
|
120
|
-
`check-updates.ps1` (Windows PowerShell) reports the state of all four at once
|
|
143
|
+
`check-updates.ps1` (Windows PowerShell) reports the state of all four at once, and
|
|
144
|
+
`.github/workflows/validate.yml` enforces the bundle's shape — including "the shipped patch must not
|
|
145
|
+
contain a machine-specific path" — in CI.
|
|
121
146
|
|
|
122
147
|
**License.** MIT (this adapter). REA is MIT and owned by its authors; Ghidra is Apache-2.0 and owned
|
|
123
148
|
by the NSA. No upstream code is redistributed here.
|
|
@@ -142,7 +167,7 @@ Android 设备(adb);JEB 项目;Android 资源;固件;软件包与资
|
|
|
142
167
|
EVM 字节码、已记录的 Linux 崩溃与已保存的网络捕获。
|
|
143
168
|
|
|
144
169
|
**本插件在此之上只增加两件事**:把该 MCP 服务注册进 DSH 的工具层(工具名 `mcp__rea__*`),
|
|
145
|
-
|
|
170
|
+
以及让引擎环境变量(`GHIDRA_INSTALL_DIR` 等)只作用于这个 MCP 子进程,而不是整个 harness。
|
|
146
171
|
|
|
147
172
|
**能做什么、不能做什么(重要)。** 分析能力由上游提供;这里只复述上游自己的契约,避免预期错位。
|
|
148
173
|
|
|
@@ -157,31 +182,54 @@ EVM 字节码、已记录的 Linux 崩溃与已保存的网络捕获。
|
|
|
157
182
|
- 适合做:理解行为、定位实现、互操作与兼容实现、安全审计、迁移参考。
|
|
158
183
|
**要拿到真正的源码,请走正规渠道**——上游代码仓库、厂商授权,或厂商自己的 SDK。
|
|
159
184
|
|
|
160
|
-
**已验证版本**(作者机器,2026-10-12):REA `6.4.0`、DeepSeek Harness 桌面运行时 `0.2.0-rc.2
|
|
161
|
-
Ghidra `12.1.4`、Node `24.21.0`、Windows 11 x64。行提供方
|
|
162
|
-
harness 自带(npm 最新 `0.0.1-rc.1
|
|
185
|
+
**已验证版本**(作者机器,2026-10-12/13):REA `6.4.0`、DeepSeek Harness 桌面运行时 `0.2.0-rc.2`
|
|
186
|
+
(自带 dsh CLI `0.1.7-rc.2`)、Ghidra `12.1.4`、Node `24.21.0`、Windows 11 x64。行提供方
|
|
187
|
+
`@deepseek-ai/dsh-mcp-client` 由 harness 自带(npm 最新 `0.0.1-rc.1`)。发布用的这一行**实测跑通过**:
|
|
188
|
+
`list_documents` 在 `cmd.exe` 形式下正常应答,`open_binary` 走 `ghidra` 提供方成功,
|
|
189
|
+
而引擎目录仅来自本机 profile 覆盖。
|
|
163
190
|
|
|
164
|
-
**前置条件。** 满足 REA 要求的 Node;全局安装 REA(`npm i -g rea-agents
|
|
165
|
-
Ghidra 12.1.x
|
|
166
|
-
|
|
191
|
+
**前置条件。** 满足 REA 要求的 Node;全局安装 REA(`npm i -g rea-agents`)。原生分析需要
|
|
192
|
+
Ghidra 12.1.x(Hopper / IDA 为替代方案,各自需授权);静态 JavaScript/Electron 与 .NET 分析
|
|
193
|
+
不需要引擎。
|
|
167
194
|
|
|
168
195
|
**安装。**
|
|
169
196
|
|
|
170
197
|
```
|
|
171
198
|
dsh plugin --profile <profile> add github:czcdr/dsh-plugin-rea
|
|
199
|
+
# 或从 npm 安装:
|
|
200
|
+
dsh plugin --profile <profile> add dsh-plugin-rea
|
|
172
201
|
```
|
|
173
202
|
|
|
174
203
|
[Releases](https://github.com/czcdr/dsh-plugin-rea/releases) 附带预构建 tarball(资产名不带版本号,
|
|
175
|
-
|
|
204
|
+
链接不会失效)。
|
|
176
205
|
|
|
177
|
-
|
|
206
|
+
**配置——通常什么都不用改。** 发布出去的那一行**不含任何机器相关路径**:
|
|
178
207
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
208
|
+
- Windows:`command: cmd.exe`、`args: ['/c', 'rea', 'mcp']` —— npm 的 shim 是 `.cmd`,必须经 shell。
|
|
209
|
+
- macOS/Linux:`command: rea`、`args: ['mcp']` —— 见
|
|
210
|
+
[`examples/cordis.patch.posix.yml`](examples/cordis.patch.posix.yml)。
|
|
211
|
+
|
|
212
|
+
唯一可选的是分析引擎。REA 从环境读取 `GHIDRA_INSTALL_DIR`,二选一:
|
|
213
|
+
|
|
214
|
+
1. 设为**系统级环境变量**,然后重启 harness(让 MCP 子进程继承);
|
|
215
|
+
2. 只为这个 MCP 子进程指定 —— 见
|
|
216
|
+
[`examples/cordis.patch.with-env.yml`](examples/cordis.patch.with-env.yml)。
|
|
217
|
+
|
|
218
|
+
两种方式都不需要在插件里写死路径:客户端会把父进程环境传给子进程(只剔除名字像密钥的变量),
|
|
219
|
+
而补丁方言支持 `!!js` 表达式,所以 `GHIDRA_INSTALL_DIR: !!js process.env.GHIDRA_INSTALL_DIR`
|
|
220
|
+
同样可用。
|
|
221
|
+
|
|
222
|
+
**机器相关值不要写进插件。** 用你自己的 profile `cordis.patch.yml` **按 id 覆盖**这一行即可;
|
|
223
|
+
该文件只在你本机、永不随插件发布:
|
|
224
|
+
|
|
225
|
+
```yaml
|
|
226
|
+
- id: mcp-rea
|
|
227
|
+
config:
|
|
228
|
+
env:
|
|
229
|
+
GHIDRA_INSTALL_DIR: '<你的 Ghidra 12.1.x 目录>'
|
|
230
|
+
```
|
|
182
231
|
|
|
183
|
-
`
|
|
184
|
-
可选,仅当 `java` 不在 PATH 上时需要。
|
|
232
|
+
同一 profile 内 `serverName: rea` 只能有一条记录。
|
|
185
233
|
|
|
186
234
|
**验证。** 调用任一 `mcp__rea__*` 工具:`binary_session` 会给出引擎检查项
|
|
187
235
|
(configuration / installation / headless / native_decompiler / java),应全部 `ok: true`;
|
|
@@ -201,7 +249,8 @@ dsh plugin --profile <profile> add github:czcdr/dsh-plugin-rea
|
|
|
201
249
|
- **DeepSeek Harness**:升级可能改变 MCP 客户端配置结构,用
|
|
202
250
|
`Config.listConfigs name=@deepseek-ai/dsh-mcp-client` 看该行 schema 并调整字段名。
|
|
203
251
|
|
|
204
|
-
`check-updates.ps1`(Windows PowerShell
|
|
252
|
+
`check-updates.ps1`(Windows PowerShell)会把上述四项一次跑完;
|
|
253
|
+
`.github/workflows/validate.yml` 在 CI 里守住 bundle 的形状(含「发布物不得含机器路径」这一条)。
|
|
205
254
|
|
|
206
255
|
**许可。** 本适配器为 MIT;REA 为 MIT,版权归其作者;Ghidra 为 Apache-2.0,版权归 NSA。
|
|
207
256
|
本仓库不再分发上游代码。
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
<#
|
|
2
|
+
生成市场展示图(assets/screenshot-*.png)。
|
|
3
|
+
可复现:改完文案后重跑本脚本即可,无需设计工具。
|
|
4
|
+
|
|
5
|
+
运行方式:
|
|
6
|
+
Windows PowerShell 5.1 : powershell -NoProfile -File .\make-screenshots.ps1
|
|
7
|
+
PowerShell 7 (pwsh) : pwsh -NoProfile -File ./make-screenshots.ps1
|
|
8
|
+
两者都可用;脚本内部用 OutDir 参数,默认写到本文件所在目录。
|
|
9
|
+
|
|
10
|
+
注意:Windows PowerShell 5.1 按 ANSI 读取 .ps1,本文件必须保存为 UTF-8 with BOM
|
|
11
|
+
(用 pwsh 7 编辑则无此限制,但保持 BOM 对两者都安全)。
|
|
12
|
+
#>
|
|
13
|
+
[CmdletBinding()]
|
|
14
|
+
param([string]$OutDir = (Join-Path $PSScriptRoot '.'))
|
|
15
|
+
|
|
16
|
+
Add-Type -AssemblyName System.Drawing
|
|
17
|
+
|
|
18
|
+
$W = 1280; $H = 720
|
|
19
|
+
$bg = [System.Drawing.Color]::FromArgb(255, 248, 250, 252)
|
|
20
|
+
$ink = [System.Drawing.Color]::FromArgb(255, 15, 23, 42)
|
|
21
|
+
$muted = [System.Drawing.Color]::FromArgb(255, 100, 116, 139)
|
|
22
|
+
$accent = [System.Drawing.Color]::FromArgb(255, 37, 99, 235)
|
|
23
|
+
$accent2 = [System.Drawing.Color]::FromArgb(255, 22, 163, 74)
|
|
24
|
+
$warn = [System.Drawing.Color]::FromArgb(255, 220, 38, 38)
|
|
25
|
+
$line = [System.Drawing.Color]::FromArgb(255, 203, 213, 225)
|
|
26
|
+
|
|
27
|
+
$fTitle = New-Object System.Drawing.Font('Microsoft YaHei UI', 30, [System.Drawing.FontStyle]::Bold)
|
|
28
|
+
$fSub = New-Object System.Drawing.Font('Microsoft YaHei UI', 15)
|
|
29
|
+
$fBox = New-Object System.Drawing.Font('Microsoft YaHei UI', 15, [System.Drawing.FontStyle]::Bold)
|
|
30
|
+
$fBody = New-Object System.Drawing.Font('Microsoft YaHei UI', 13)
|
|
31
|
+
$fSmall = New-Object System.Drawing.Font('Microsoft YaHei UI', 11)
|
|
32
|
+
$fChip = New-Object System.Drawing.Font('Microsoft YaHei UI', 13)
|
|
33
|
+
|
|
34
|
+
function New-Canvas {
|
|
35
|
+
$bmp = New-Object System.Drawing.Bitmap $W, $H
|
|
36
|
+
$g = [System.Drawing.Graphics]::FromImage($bmp)
|
|
37
|
+
$g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias
|
|
38
|
+
$g.TextRenderingHint = [System.Drawing.Text.TextRenderingHint]::ClearTypeGridFit
|
|
39
|
+
$g.Clear($bg)
|
|
40
|
+
return @($bmp, $g)
|
|
41
|
+
}
|
|
42
|
+
function Draw-Text($g, $text, $font, $color, $x, $y, $w = 0) {
|
|
43
|
+
$br = New-Object System.Drawing.SolidBrush $color
|
|
44
|
+
if ($w -gt 0) { $r = New-Object System.Drawing.RectangleF $x, $y, $w, 400; $g.DrawString($text, $font, $br, $r) }
|
|
45
|
+
else { $g.DrawString($text, $font, $br, $x, $y) }
|
|
46
|
+
$br.Dispose()
|
|
47
|
+
}
|
|
48
|
+
function Draw-Box($g, $x, $y, $w, $h, $fill, $border, $radius = 12) {
|
|
49
|
+
$path = New-Object System.Drawing.Drawing2D.GraphicsPath
|
|
50
|
+
$d = $radius * 2
|
|
51
|
+
$path.AddArc($x, $y, $d, $d, 180, 90); $path.AddArc($x + $w - $d, $y, $d, $d, 270, 90)
|
|
52
|
+
$path.AddArc($x + $w - $d, $y + $h - $d, $d, $d, 0, 90); $path.AddArc($x, $y + $h - $d, $d, $d, 90, 90)
|
|
53
|
+
$path.CloseFigure()
|
|
54
|
+
$fb = New-Object System.Drawing.SolidBrush $fill
|
|
55
|
+
$g.FillPath($fb, $path)
|
|
56
|
+
$p = New-Object System.Drawing.Pen $border, 1.6
|
|
57
|
+
$g.DrawPath($p, $path)
|
|
58
|
+
$fb.Dispose(); $p.Dispose(); $path.Dispose()
|
|
59
|
+
}
|
|
60
|
+
function Draw-Arrow($g, $x1, $y1, $x2, $y2, $color, $width = 2.4) {
|
|
61
|
+
$p = New-Object System.Drawing.Pen $color, $width
|
|
62
|
+
$p.CustomEndCap = New-Object System.Drawing.Drawing2D.AdjustableArrowCap 6, 7
|
|
63
|
+
$g.DrawLine($p, $x1, $y1, $x2, $y2)
|
|
64
|
+
$p.Dispose()
|
|
65
|
+
}
|
|
66
|
+
function Draw-Line($g, $x1, $y1, $x2, $y2, $color, $width = 2.4) {
|
|
67
|
+
$p = New-Object System.Drawing.Pen $color, $width
|
|
68
|
+
$g.DrawLine($p, $x1, $y1, $x2, $y2)
|
|
69
|
+
$p.Dispose()
|
|
70
|
+
}
|
|
71
|
+
function Save-Png($bmp, $g, $path) { $g.Dispose(); $bmp.Save($path, [System.Drawing.Imaging.ImageFormat]::Png); $bmp.Dispose() }
|
|
72
|
+
|
|
73
|
+
# ---------------------------------------------------------------- 图 1:插件做了什么
|
|
74
|
+
$r = New-Canvas; $bmp = $r[0]; $g = $r[1]
|
|
75
|
+
Draw-Text $g 'dsh-plugin-rea:把 REA 接入 DeepSeek Harness' $fTitle $ink 60 46
|
|
76
|
+
Draw-Text $g '第三方适配 · 自身不做逆向分析 · 只插入一条 MCP 客户端记录,并把引擎环境变量限制在该子进程内' $fSub $muted 62 98
|
|
77
|
+
|
|
78
|
+
$rowY = 180; $boxH = 158; $boxW = 250
|
|
79
|
+
Draw-Box $g 60 $rowY $boxW $boxH $([System.Drawing.Color]::White) $line
|
|
80
|
+
Draw-Text $g 'DeepSeek Harness 会话' $fBox $ink 80 ($rowY + 18)
|
|
81
|
+
Draw-Text $g "mcp__rea__* 工具`n(6.4.0 暴露 170+)`n工具随会话注入`n按 DSH 权限策略执行" $fBody $muted 80 ($rowY + 50)
|
|
82
|
+
|
|
83
|
+
Draw-Box $g 360 $rowY $boxW $boxH $([System.Drawing.Color]::FromArgb(255,239,246,255)) $accent
|
|
84
|
+
Draw-Text $g '官方 MCP 客户端行' $fBox $accent 380 ($rowY + 18)
|
|
85
|
+
Draw-Text $g "@deepseek-ai/dsh-mcp-client`nserverName = rea`ntransport = stdio`ncommand = node" $fBody $muted 380 ($rowY + 50)
|
|
86
|
+
Draw-Text $g '↑ 本插件插入的就是这一行' $fSmall $accent 360 ($rowY + $boxH + 8)
|
|
87
|
+
|
|
88
|
+
Draw-Box $g 660 $rowY $boxW $boxH $([System.Drawing.Color]::White) $line
|
|
89
|
+
Draw-Text $g 'rea mcp(本机进程)' $fBox $ink 680 ($rowY + 18)
|
|
90
|
+
Draw-Text $g "node …`n \rea-agents\scripts`n \rea.mjs mcp`nenv: GHIDRA_INSTALL_DIR`n JAVA_HOME(仅此处)" $fBody $muted 680 ($rowY + 50)
|
|
91
|
+
|
|
92
|
+
Draw-Box $g 960 $rowY $boxW $boxH $([System.Drawing.Color]::FromArgb(255,240,253,244)) $accent2
|
|
93
|
+
Draw-Text $g '分析引擎' $fBox $accent2 980 ($rowY + 18)
|
|
94
|
+
Draw-Text $g "Ghidra 12.1.4(本机已装)`nHopper / IDA(可选,`n各自需授权)`n静态 JS / .NET 无需引擎" $fBody $muted 980 ($rowY + 50)
|
|
95
|
+
|
|
96
|
+
Draw-Arrow $g 310 ($rowY + 40) 358 ($rowY + 40) $muted
|
|
97
|
+
Draw-Arrow $g 610 ($rowY + 40) 658 ($rowY + 40) $muted
|
|
98
|
+
Draw-Arrow $g 910 ($rowY + 40) 958 ($rowY + 40) $muted
|
|
99
|
+
|
|
100
|
+
# Evidence 回传:引擎 → 结果框 → 会话(左侧折返)
|
|
101
|
+
Draw-Box $g 360 404 850 84 $([System.Drawing.Color]::FromArgb(255,254,249,195)) $([System.Drawing.Color]::FromArgb(255,202,138,4))
|
|
102
|
+
Draw-Text $g 'Evidence 回到会话(置信度 observed / derived / inferred + 明确的 limitations)' $fBox $ink 380 416
|
|
103
|
+
Draw-Text $g '反编译器输出的是伪代码与汇编 —— 不是原始源码,也不保证文本等价' $fBody $muted 380 448
|
|
104
|
+
Draw-Arrow $g 1085 340 1085 400 $muted
|
|
105
|
+
Draw-Line $g 358 446 150 446 $muted
|
|
106
|
+
Draw-Arrow $g 150 446 150 342 $muted
|
|
107
|
+
|
|
108
|
+
Draw-Text $g '上游 REA(MIT):github.com/morluto/rea 本插件:github.com/czcdr/dsh-plugin-rea' $fSmall $muted 60 620
|
|
109
|
+
Draw-Text $g '实测 REA 6.4.0 + DSH 桌面运行时 0.2.0-rc.2 + Ghidra 12.1.4 + Node 24.21.0(Windows 11 x64,2026-10-12)' $fSmall $muted 60 646
|
|
110
|
+
Draw-Text $g 'Ghidra 为 Apache-2.0(NSA);REA 为 MIT。本仓库不分发上游代码。' $fSmall $muted 60 672
|
|
111
|
+
Save-Png $bmp $g (Join-Path $OutDir 'screenshot-1.png')
|
|
112
|
+
|
|
113
|
+
# ---------------------------------------------------------------- 图 2:范围与边界
|
|
114
|
+
$r = New-Canvas; $bmp = $r[0]; $g = $r[1]
|
|
115
|
+
Draw-Text $g '上游 REA 的分析范围(插件原样提供)' $fTitle $ink 60 44
|
|
116
|
+
Draw-Text $g '下列目标类型来自上游 README「可以分析什么」;本插件不改变、不扩展这些能力' $fSub $muted 62 96
|
|
117
|
+
|
|
118
|
+
$chips = @(
|
|
119
|
+
'原生二进制:伪代码/汇编/字符串/符号/调用与引用',
|
|
120
|
+
'JavaScript / Electron:模块、导入、source map、路由、IPC',
|
|
121
|
+
'.NET 程序集:元数据、CIL、原生依赖声明',
|
|
122
|
+
'网站:页面结构、脚本、网络观察、截图',
|
|
123
|
+
'Android APK:清单、类、反编译的方法、引用',
|
|
124
|
+
'Android 设备:adb 包/进程/日志/截图/文件传输',
|
|
125
|
+
'JEB 项目:单元、工件摘要、类型与方法伪代码',
|
|
126
|
+
'Android 资源:解码清单、字符串表、语言区域',
|
|
127
|
+
'固件:区域、提取结果、转交原生分析',
|
|
128
|
+
'软件包与资源:清单、摘要、plist、Apple bundle',
|
|
129
|
+
'进程行为:终端输出、交互、退出、文件系统观察',
|
|
130
|
+
'离线 ELF 布局:节、段、符号/重定位、防护候选项',
|
|
131
|
+
'EVM 字节码:分派选择器、字节偏移、可变性',
|
|
132
|
+
'已记录的 Linux 崩溃:note、线程寄存器、映射候选',
|
|
133
|
+
'已保存的网络捕获:HAR / mitmproxy 记录'
|
|
134
|
+
)
|
|
135
|
+
$cx = 60; $cy = 146; $cw = 570; $ch = 40; $gap = 8
|
|
136
|
+
for ($i = 0; $i -lt $chips.Count; $i++) {
|
|
137
|
+
$col = $i % 2; $rowi = [math]::Floor($i / 2)
|
|
138
|
+
$x = $cx + $col * ($cw + 20); $y = $cy + $rowi * ($ch + $gap)
|
|
139
|
+
Draw-Box $g $x $y $cw $ch $([System.Drawing.Color]::White) $line 8
|
|
140
|
+
Draw-Text $g $chips[$i] $fChip $ink ($x + 14) ($y + 9)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
$by = $cy + 8 * ($ch + $gap) + 16
|
|
144
|
+
Draw-Box $g 60 $by 1190 92 $([System.Drawing.Color]::FromArgb(255,254,242,242)) $warn
|
|
145
|
+
Draw-Text $g '不能完整还原源代码' $fBox $warn 80 ($by + 10)
|
|
146
|
+
Draw-Text $g '返回的是伪代码/汇编/反编译方法,不是原始源码;标识符、类型、注释、宏与模板、构建脚本与资源多不可恢复;不保证文本等价或可直接编译。' $fBody $ink 80 ($by + 38)
|
|
147
|
+
Draw-Text $g '优化(内联/重排)、strip、混淆、加壳与 VM 保护会让可读性更差。要真正的源码,请走上游仓库、厂商授权或官方 SDK。' $fBody $muted 80 ($by + 60)
|
|
148
|
+
|
|
149
|
+
Draw-Text $g '上游 REA(MIT):github.com/morluto/rea 本插件:github.com/czcdr/dsh-plugin-rea' $fSmall $muted 60 686
|
|
150
|
+
Save-Png $bmp $g (Join-Path $OutDir 'screenshot-2.png')
|
|
151
|
+
|
|
152
|
+
Write-Host "written: $(Join-Path $OutDir 'screenshot-1.png')"
|
|
153
|
+
Write-Host "written: $(Join-Path $OutDir 'screenshot-2.png')"
|
|
Binary file
|
|
Binary file
|
package/check-updates.ps1
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<#
|
|
2
2
|
.SYNOPSIS
|
|
3
|
-
检查 dsh-plugin-rea
|
|
3
|
+
检查 dsh-plugin-rea 整条链路是否需要跟进上游更新。
|
|
4
4
|
|
|
5
5
|
.DESCRIPTION
|
|
6
6
|
覆盖 4 类上游:REA(npm) / Node 运行时 / Ghidra 引擎 / DSH 插件登记。
|
|
7
7
|
只读:不安装、不修改任何配置,只报告现状与建议动作。
|
|
8
|
+
对 PATH 缺失、profile 结构缺失、预发布版本号均有防御。
|
|
8
9
|
|
|
9
10
|
.EXAMPLE
|
|
10
11
|
powershell -NoProfile -File .\check-updates.ps1
|
|
@@ -20,63 +21,111 @@ param(
|
|
|
20
21
|
[string]$ProfileDir
|
|
21
22
|
)
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
$ErrorActionPreference = 'Continue'
|
|
25
|
+
function Head($t) { Write-Host "`n=== $t ===" -ForegroundColor Cyan }
|
|
26
|
+
function Ok($t) { Write-Host " [OK] $t" -ForegroundColor Green }
|
|
27
|
+
function Warn($t) { Write-Host " [注意] $t" -ForegroundColor Yellow }
|
|
28
|
+
function Bad($t) { Write-Host " [动作] $t" -ForegroundColor Red }
|
|
29
|
+
function Info($t) { Write-Host " $t" -ForegroundColor Gray }
|
|
30
|
+
|
|
31
|
+
$actions = [System.Collections.Generic.List[string]]::new()
|
|
32
|
+
|
|
33
|
+
# 只取数字部分,丢掉 -rc.1 / +build 之类的后缀,避免 [version] 转换抛异常
|
|
34
|
+
function Get-NumericVersion([string]$v) {
|
|
35
|
+
if (-not $v) { return $null }
|
|
36
|
+
$core = ($v -replace '^v', '') -replace '[-+].*$', ''
|
|
37
|
+
try { return [version]$core } catch { return $null }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# 判断 Node 版本是否满足 engines 字符串(支持 ^X.Y.Z / ~X.Y.Z / >=X.Y.Z,用 || 分隔)
|
|
41
|
+
# 参数收 string 不收 [version]:类型约束在函数体之前生效,调用方一旦传入
|
|
42
|
+
# 'abc' / '' / 'v24.21.0' 这类值就会抛 ParameterBindingArgumentTransformationException。
|
|
43
|
+
function Test-NodeEngines([string]$node, [string]$engines) {
|
|
44
|
+
if (-not $engines -or -not $node) { return $null }
|
|
45
|
+
# 必须用新变量接收:$node 带 [string] 约束,赋 [version] 会被强制转回字符串,
|
|
46
|
+
# 之后 $node.Major 为 $null,所有 ^ / ~ 分支都会判假(曾因此把 Node 24 判成不满足)。
|
|
47
|
+
$v = Get-NumericVersion $node
|
|
48
|
+
if (-not $v) { return $null }
|
|
49
|
+
foreach ($term in ($engines -split '\|\|')) {
|
|
50
|
+
$t = $term.Trim()
|
|
51
|
+
if ($t -match '^\^(\d+\.\d+\.\d+)$') {
|
|
52
|
+
$base = [version]$Matches[1]
|
|
53
|
+
if ($v.Major -eq $base.Major -and $v -ge $base) { return $true }
|
|
54
|
+
} elseif ($t -match '^>=(\d+\.\d+\.\d+)$') {
|
|
55
|
+
if ($v -ge [version]$Matches[1]) { return $true }
|
|
56
|
+
} elseif ($t -match '^~(\d+\.\d+\.\d+)$') {
|
|
57
|
+
$base = [version]$Matches[1]
|
|
58
|
+
if ($v.Major -eq $base.Major -and $v.Minor -eq $base.Minor -and $v -ge $base) { return $true }
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return $false
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# ------------------------------------------------------- 定位 REA 与 profile
|
|
24
65
|
if (-not $ReaPackageDir) {
|
|
25
66
|
$npmRoot = $null
|
|
26
|
-
|
|
67
|
+
if (Get-Command npm -ErrorAction SilentlyContinue) {
|
|
68
|
+
try { $npmRoot = (& npm root -g 2>$null | Select-Object -First 1).Trim() } catch { }
|
|
69
|
+
}
|
|
27
70
|
$ReaPackageDir = if ($npmRoot) { Join-Path $npmRoot 'rea-agents' } else { Join-Path $env:APPDATA 'npm\node_modules\rea-agents' }
|
|
28
71
|
}
|
|
29
72
|
if (-not $ProfileDir) {
|
|
30
73
|
if ($env:DSH_PROFILE_DIR) { $ProfileDir = $env:DSH_PROFILE_DIR }
|
|
31
74
|
else {
|
|
32
|
-
$profiles = @(Get-ChildItem
|
|
33
|
-
$ProfileDir = if ($profiles.Count -gt 0) { $profiles[0].FullName } else {
|
|
75
|
+
$profiles = @(Get-ChildItem (Join-Path $env:USERPROFILE '.dsh\profiles') -Directory -ErrorAction SilentlyContinue)
|
|
76
|
+
$ProfileDir = if ($profiles.Count -gt 0) { $profiles[0].FullName } else { Join-Path $env:USERPROFILE '.dsh\profiles\desktop' }
|
|
34
77
|
}
|
|
35
78
|
}
|
|
36
79
|
|
|
37
|
-
$ErrorActionPreference = 'Continue'
|
|
38
|
-
function Head($t) { Write-Host "`n=== $t ===" -ForegroundColor Cyan }
|
|
39
|
-
function Ok($t) { Write-Host " [OK] $t" -ForegroundColor Green }
|
|
40
|
-
function Warn($t) { Write-Host " [注意] $t" -ForegroundColor Yellow }
|
|
41
|
-
function Bad($t) { Write-Host " [动作] $t" -ForegroundColor Red }
|
|
42
|
-
function Info($t) { Write-Host " $t" -ForegroundColor Gray }
|
|
43
|
-
|
|
44
|
-
$actions = [System.Collections.Generic.List[string]]::new()
|
|
45
|
-
|
|
46
80
|
# ---------------------------------------------------------------- REA (npm)
|
|
47
81
|
Head 'REA 本体(npm 包 rea-agents)'
|
|
48
|
-
$installed = $null; $engines = $null; $binPath = $null
|
|
82
|
+
$installed = $null; $engines = $null; $binPath = $null; $reaEntry = $null
|
|
49
83
|
$pkgFile = Join-Path $ReaPackageDir 'package.json'
|
|
50
84
|
if (Test-Path $pkgFile) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
85
|
+
try {
|
|
86
|
+
$pkg = Get-Content $pkgFile -Raw -Encoding UTF8 | ConvertFrom-Json
|
|
87
|
+
$installed = $pkg.version; $engines = $pkg.engines.node
|
|
88
|
+
$binPath = ($pkg.bin.PSObject.Properties | Select-Object -First 1).Value
|
|
89
|
+
if ($binPath) { $reaEntry = Join-Path $ReaPackageDir ($binPath -replace '/', '\') }
|
|
90
|
+
Ok "本地已安装: $installed"
|
|
91
|
+
Info "入口(bin): $binPath ← 插件通过 PATH 上的 rea 调用它,跨版本稳定"
|
|
92
|
+
if ($engines) { Info "Node 要求: $engines" }
|
|
93
|
+
} catch { Bad "package.json 解析失败: $($_.Exception.Message)" }
|
|
57
94
|
} else { Bad "找不到 $pkgFile —— REA 全局包丢了?重装: npm i -g rea-agents" }
|
|
58
95
|
|
|
59
96
|
$latest = $null
|
|
60
97
|
foreach ($r in @($Registry, 'https://registry.npmjs.org')) {
|
|
98
|
+
if (-not $r) { continue }
|
|
61
99
|
try { $latest = (Invoke-RestMethod "$r/rea-agents/latest" -TimeoutSec 20).version; Info "最新版本($r): $latest"; break }
|
|
62
100
|
catch { Warn "查询失败 $r : $($_.Exception.Message)" }
|
|
63
101
|
}
|
|
64
102
|
if ($installed -and $latest) {
|
|
65
|
-
|
|
103
|
+
$vi = Get-NumericVersion $installed; $vl = Get-NumericVersion $latest
|
|
104
|
+
if ($vi -and $vl -and $vl -gt $vi) {
|
|
66
105
|
Warn "有新版本:$installed → $latest"
|
|
67
|
-
$actions.Add("升级上游 REA: npm i -g rea-agents@$latest (只更新 REA
|
|
106
|
+
$actions.Add("升级上游 REA: npm i -g rea-agents@$latest (只更新 REA;本插件不会自动更新——从市场装的在市场里更新,file: 装的覆盖目录后重装)")
|
|
107
|
+
} elseif ($vi -and $vl -and $vl -eq $vi -and $installed -ne $latest) {
|
|
108
|
+
Warn "同版本号但通道不同:$installed → $latest(预发布/正式)"
|
|
68
109
|
} else { Ok '已是最新版本' }
|
|
110
|
+
} else {
|
|
111
|
+
Warn '未能取到上游最新版本(两个 registry 都查不通?)—— 已跳过版本比对'
|
|
69
112
|
}
|
|
70
113
|
|
|
71
114
|
# ------------------------------------------------------------- Node 运行时
|
|
72
115
|
Head 'Node 运行时'
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
116
|
+
if (Get-Command node -ErrorAction SilentlyContinue) {
|
|
117
|
+
$nodeRaw = (& node -v 2>$null) -replace '^v', ''
|
|
118
|
+
$nodeV = Get-NumericVersion $nodeRaw
|
|
119
|
+
Info "当前 node: $nodeRaw"
|
|
120
|
+
if ($nodeV -and $engines) {
|
|
121
|
+
$ok = Test-NodeEngines $nodeV $engines
|
|
122
|
+
if ($ok -eq $true) { Ok "满足当前 engines($engines)" }
|
|
123
|
+
elseif ($ok -eq $false) { Bad "不满足 engines($engines)—— 请升级 Node;插件侧走 PATH,无需改配置" }
|
|
124
|
+
else { Warn "无法解析 engines:$engines" }
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
Warn 'node 不在 PATH —— 跳过 Node 检查;若 harness 也看不到它,MCP 服务器将无法启动'
|
|
128
|
+
$actions.Add('把 node 加入 PATH,或在本机 profile 覆盖里给 mcp-rea 的 command 写绝对路径')
|
|
80
129
|
}
|
|
81
130
|
|
|
82
131
|
# ------------------------------------------------------------ Ghidra 引擎
|
|
@@ -89,48 +138,82 @@ if ($gd -and (Test-Path $gd)) {
|
|
|
89
138
|
if (Test-Path $props) {
|
|
90
139
|
$v = (Select-String -Path $props -Pattern '^application\.version=' | Select-Object -First 1).Line -replace '^application\.version=', ''
|
|
91
140
|
Ok "已安装版本: $v"
|
|
92
|
-
if ($v -notmatch '^12\.1\.') { Bad "REA 当前要求 Ghidra 12.1.x
|
|
93
|
-
} else { Bad
|
|
94
|
-
} else {
|
|
95
|
-
|
|
141
|
+
if ($v -notmatch '^12\.1\.') { Bad "REA 当前要求 Ghidra 12.1.x,当前为 $v —— 先确认新版 REA 是否放开版本门槛" }
|
|
142
|
+
} else { Bad '缺少 Ghidra\application.properties —— 目录不完整' }
|
|
143
|
+
} else {
|
|
144
|
+
Warn "GHIDRA_INSTALL_DIR 未设置或目录不存在(当前值: $gd)"
|
|
145
|
+
Info '原生分析会报引擎不可用;静态 JavaScript/Electron 与 .NET 分析不受影响'
|
|
146
|
+
}
|
|
96
147
|
try {
|
|
97
148
|
$rel = Invoke-RestMethod 'https://api.github.com/repos/NationalSecurityAgency/ghidra/releases/latest' -TimeoutSec 25 -Headers @{ 'User-Agent' = 'rea-check' }
|
|
98
149
|
Info "Ghidra 官方最新: $($rel.tag_name) ($($rel.published_at))"
|
|
99
|
-
if ($rel.tag_name -notmatch 'Ghidra_12\.1') { Warn '
|
|
150
|
+
if ($rel.tag_name -notmatch 'Ghidra_12\.1') { Warn '官方已有更新;升级前先确认 REA 是否接受该版本' }
|
|
100
151
|
} catch { Warn "GitHub API 查询失败(可跳过): $($_.Exception.Message)" }
|
|
101
152
|
|
|
102
153
|
# --------------------------------------------------------- REA 引擎自检
|
|
103
154
|
Head 'REA 引擎自检(rea doctor)'
|
|
104
155
|
$env:GHIDRA_INSTALL_DIR = $gd
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
|
|
156
|
+
# 优先取 .cmd:发布出去的那一行是 `cmd.exe /c rea mcp`(走 cmd 的 PATHEXT,命中 rea.cmd),
|
|
157
|
+
# 而 PowerShell 的 Get-Command rea 会先命中同目录的 rea.ps1 垫片,两者行为(尤其退出码)并不相同。
|
|
158
|
+
$reaCmd = (Get-Command 'rea.cmd' -ErrorAction SilentlyContinue).Source
|
|
159
|
+
if (-not $reaCmd) { $reaCmd = (Get-Command rea -ErrorAction SilentlyContinue).Source }
|
|
160
|
+
$reaArgs = @()
|
|
161
|
+
if (-not $reaCmd) {
|
|
162
|
+
if ($reaEntry -and (Test-Path $reaEntry) -and (Get-Command node -ErrorAction SilentlyContinue)) {
|
|
163
|
+
$reaCmd = 'node'; $reaArgs = @($reaEntry)
|
|
164
|
+
Warn 'rea 不在 PATH —— 回退到 node <包内入口>'
|
|
165
|
+
} else { Warn 'rea 与 node 均不可用 —— 跳过引擎自检' }
|
|
166
|
+
}
|
|
167
|
+
if ($reaCmd) {
|
|
168
|
+
try {
|
|
169
|
+
$raw = & $reaCmd @reaArgs doctor --format json 2>$null
|
|
170
|
+
if ($LASTEXITCODE -ne 0) { Warn "rea doctor 退出码 $LASTEXITCODE —— 报告了不健康状态,下面按输出解析" }
|
|
171
|
+
$doc = ($raw -join "`n") | ConvertFrom-Json
|
|
172
|
+
$g = @($doc.providerInspections) | Where-Object { $_.id -eq 'ghidra' }
|
|
173
|
+
if ($g) {
|
|
174
|
+
if ($g.available) { Ok "ghidra provider 可用,版本 $($g.providerVersion)" }
|
|
175
|
+
else { Bad 'ghidra provider 不可用 —— 运行 rea doctor 看 remediation' }
|
|
176
|
+
$fails = @($g.checks | Where-Object { -not $_.ok })
|
|
177
|
+
if ($fails.Count -eq 0) { Ok '全部子项通过(configuration/installation/headless/native_decompiler/java)' }
|
|
178
|
+
else { $fails | ForEach-Object { Bad "$($_.name): $($_.detail)" } }
|
|
179
|
+
}
|
|
180
|
+
if ($doc.identity.cli_package_version) {
|
|
181
|
+
$toolCount = $null
|
|
182
|
+
if ($doc.identity.catalog -and $doc.identity.catalog.counts) { $toolCount = $doc.identity.catalog.counts.mcp_tools }
|
|
183
|
+
Info "doctor 识别到的 CLI 版本: $($doc.identity.cli_package_version)$(if ($toolCount) { ",MCP 工具数: $toolCount" })"
|
|
184
|
+
}
|
|
185
|
+
} catch { Warn "rea doctor 解析失败,请手动运行: rea doctor" }
|
|
186
|
+
}
|
|
117
187
|
|
|
118
188
|
# ---------------------------------------------------- DSH 插件登记状态
|
|
119
189
|
Head 'DSH 插件登记'
|
|
120
190
|
$profPkg = Join-Path $ProfileDir 'package.json'
|
|
121
191
|
if (Test-Path $profPkg) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
192
|
+
try {
|
|
193
|
+
$p = Get-Content $profPkg -Raw -Encoding UTF8 | ConvertFrom-Json
|
|
194
|
+
$dep = $null
|
|
195
|
+
if ($p.PSObject.Properties.Name -contains 'dependencies' -and $p.dependencies) { $dep = $p.dependencies.'dsh-plugin-rea' }
|
|
196
|
+
$bundles = @()
|
|
197
|
+
if ($p.PSObject.Properties.Name -contains 'dsh' -and $p.dsh -and $p.dsh.profile -and $p.dsh.profile.bundles) { $bundles = @($p.dsh.profile.bundles) }
|
|
198
|
+
if ($dep) { Ok "依赖已登记: dsh-plugin-rea = $dep" } else { Bad '依赖未登记 —— 用插件管理器重新安装本插件' }
|
|
199
|
+
if ($bundles -contains 'dsh-plugin-rea') { Ok '已列入 dsh.profile.bundles(装载层已生效)' }
|
|
200
|
+
elseif ($bundles.Count -eq 0) { Warn '未读到 dsh.profile.bundles(profile 结构可能不同)' }
|
|
201
|
+
else { Bad '未列入 bundles —— 插件不会加载' }
|
|
202
|
+
Info '本插件不会自动更新:从插件市场安装的在市场里更新;本地 file: 目录方式则覆盖目录后在插件管理器里重装'
|
|
203
|
+
if ($dep -like 'file:*') {
|
|
204
|
+
$p2 = $dep -replace '^file:', ''
|
|
205
|
+
if (Test-Path $p2) { Ok "插件目录存在: $p2" } else { Bad "插件目录不存在: $p2 —— 移走目录会加载失败" }
|
|
206
|
+
}
|
|
207
|
+
} catch { Warn "profile package.json 解析失败: $($_.Exception.Message)" }
|
|
132
208
|
} else { Warn "找不到 profile: $profPkg" }
|
|
133
209
|
|
|
210
|
+
$profPatch = Join-Path $ProfileDir 'cordis.patch.yml'
|
|
211
|
+
if (Test-Path $profPatch) {
|
|
212
|
+
if (Select-String -Path $profPatch -Pattern 'id:\s*mcp-rea' -Quiet) {
|
|
213
|
+
Info '检测到本机 profile 覆盖了 mcp-rea(机器相关值应放在这里,不随插件发布)'
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
134
217
|
# ------------------------------------------------------------------ 汇总
|
|
135
218
|
Head '结论'
|
|
136
219
|
if ($actions.Count -eq 0) { Ok '无需动作:整条链路与上游保持一致' }
|
package/cordis.patch.yml
CHANGED
|
@@ -5,21 +5,28 @@
|
|
|
5
5
|
# stdio server; the model then sees mcp__rea__<tool>.
|
|
6
6
|
#
|
|
7
7
|
# ---------------------------------------------------------------------------
|
|
8
|
-
#
|
|
8
|
+
# PORTABLE BY DEFAULT — this file carries no machine-specific path.
|
|
9
9
|
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# then append: \rea-agents\scripts\rea.mjs
|
|
13
|
-
# (POSIX: <npm root -g>/rea-agents/scripts/rea.mjs)
|
|
10
|
+
# Prerequisite: `rea` must be reachable from the PATH the harness sees.
|
|
11
|
+
# (`npm i -g rea-agents` puts it there.)
|
|
14
12
|
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
# Leave it out only if you do not use Ghidra.
|
|
13
|
+
# Windows : command: cmd.exe args: ['/c', 'rea', 'mcp'] (as below)
|
|
14
|
+
# macOS/Linux: command: 'rea' args: ['mcp']
|
|
15
|
+
# → see examples/cordis.patch.posix.yml
|
|
19
16
|
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
17
|
+
# Analysis engines: REA reads GHIDRA_INSTALL_DIR from its environment.
|
|
18
|
+
# - Option 1 (recommended): set it as an OS-level environment variable,
|
|
19
|
+
# then start/restart the harness so the MCP child inherits it.
|
|
20
|
+
# - Option 2: put an `env:` block in the row —
|
|
21
|
+
# see examples/cordis.patch.with-env.yml.
|
|
22
|
+
# Without it, native analysis reports the engine as unavailable while every
|
|
23
|
+
# other REA capability keeps working. Static JavaScript/Electron and .NET
|
|
24
|
+
# analysis need no engine at all.
|
|
25
|
+
#
|
|
26
|
+
# Only ONE row may use serverName: rea in a profile. To adapt this bundle for
|
|
27
|
+
# your machine without touching the upstream file, override `mcp-rea` from
|
|
28
|
+
# your profile's own cordis.patch.yml (id-targeted config override) — that
|
|
29
|
+
# file is never published.
|
|
23
30
|
# ---------------------------------------------------------------------------
|
|
24
31
|
|
|
25
32
|
- insert:
|
|
@@ -28,11 +35,9 @@
|
|
|
28
35
|
config:
|
|
29
36
|
serverName: rea
|
|
30
37
|
transport: stdio
|
|
31
|
-
command: '
|
|
38
|
+
command: 'cmd.exe'
|
|
32
39
|
args:
|
|
33
|
-
- '
|
|
34
|
-
-
|
|
35
|
-
|
|
36
|
-
GHIDRA_INSTALL_DIR: 'D:\ghidra\ghidra_12.1.4_PUBLIC'
|
|
37
|
-
JAVA_HOME: 'F:\game\xbox'
|
|
40
|
+
- '/c'
|
|
41
|
+
- 'rea'
|
|
42
|
+
- 'mcp'
|
|
38
43
|
failOnStartupError: false
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# macOS / Linux variant of the row.
|
|
2
|
+
#
|
|
3
|
+
# `npm i -g rea-agents` installs a `rea` executable on PATH, so no shell wrapper
|
|
4
|
+
# is needed here (on Windows the shim is a .cmd/.ps1 file, which is why the
|
|
5
|
+
# default cordis.patch.yml goes through cmd.exe).
|
|
6
|
+
#
|
|
7
|
+
# Copy the block below into cordis.patch.yml, replacing the Windows row.
|
|
8
|
+
|
|
9
|
+
- insert:
|
|
10
|
+
- id: mcp-rea
|
|
11
|
+
name: '@deepseek-ai/dsh-mcp-client'
|
|
12
|
+
config:
|
|
13
|
+
serverName: rea
|
|
14
|
+
transport: stdio
|
|
15
|
+
command: 'rea'
|
|
16
|
+
args:
|
|
17
|
+
- 'mcp'
|
|
18
|
+
failOnStartupError: false
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Windows variant that also pins the analysis-engine environment for the MCP child.
|
|
2
|
+
#
|
|
3
|
+
# Use this when GHIDRA_INSTALL_DIR is NOT set as an OS-level environment variable
|
|
4
|
+
# the harness can inherit — for example after setting it up just now, without
|
|
5
|
+
# restarting the harness.
|
|
6
|
+
#
|
|
7
|
+
# The value below is a placeholder in angle brackets, not a real directory:
|
|
8
|
+
# replace it with your own, or use the `!!js` form to read the variable the
|
|
9
|
+
# harness already has. REA reads only GHIDRA_INSTALL_DIR; `java` comes from PATH
|
|
10
|
+
# or JAVA_HOME.
|
|
11
|
+
#
|
|
12
|
+
# Copy the block into cordis.patch.yml, or — better — keep it out of the plugin
|
|
13
|
+
# entirely and override the row from your profile's own cordis.patch.yml:
|
|
14
|
+
#
|
|
15
|
+
# - id: mcp-rea
|
|
16
|
+
# config:
|
|
17
|
+
# env:
|
|
18
|
+
# GHIDRA_INSTALL_DIR: '<your Ghidra directory>'
|
|
19
|
+
#
|
|
20
|
+
# A profile-level override is machine-local and is never published.
|
|
21
|
+
|
|
22
|
+
- insert:
|
|
23
|
+
- id: mcp-rea
|
|
24
|
+
name: '@deepseek-ai/dsh-mcp-client'
|
|
25
|
+
config:
|
|
26
|
+
serverName: rea
|
|
27
|
+
transport: stdio
|
|
28
|
+
command: 'cmd.exe'
|
|
29
|
+
args:
|
|
30
|
+
- '/c'
|
|
31
|
+
- 'rea'
|
|
32
|
+
- 'mcp'
|
|
33
|
+
env:
|
|
34
|
+
# Replace with your own Ghidra 12.1.x extraction directory.
|
|
35
|
+
# Leaving the placeholder in place is harmless: REA then reports the
|
|
36
|
+
# native engine as unavailable, exactly as when the variable is unset.
|
|
37
|
+
GHIDRA_INSTALL_DIR: '<your Ghidra 12.1.x extraction directory>'
|
|
38
|
+
# Or read it from the environment the harness already has — the
|
|
39
|
+
# entry-list dialect evaluates `!!js` expressions at activation:
|
|
40
|
+
# GHIDRA_INSTALL_DIR: !!js process.env.GHIDRA_INSTALL_DIR
|
|
41
|
+
# JAVA_HOME: '<your JDK 21 or newer home>' # only when java is not on PATH
|
|
42
|
+
failOnStartupError: false
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-rea",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.5",
|
|
4
|
+
"description": "Registers the upstream REA MCP server into DeepSeek Harness as mcp__rea__* tools — a third-party adapter, analysis is upstream's. · 把上游 REA 的 MCP 服务接入 DeepSeek Harness,提供 mcp__rea__* 工具(第三方适配,分析能力属上游)。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "czcdr",
|
|
@@ -32,7 +32,10 @@
|
|
|
32
32
|
"README.md",
|
|
33
33
|
"LICENSE",
|
|
34
34
|
"CHANGELOG.md",
|
|
35
|
-
"check-updates.ps1"
|
|
35
|
+
"check-updates.ps1",
|
|
36
|
+
"screenshots.json",
|
|
37
|
+
"assets/",
|
|
38
|
+
"examples/"
|
|
36
39
|
],
|
|
37
40
|
"dsh": {
|
|
38
41
|
"bundle": {
|
package/screenshots.json
ADDED