windows-exe-decompiler-mcp-server 0.1.0 → 0.1.3
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/CLAUDE_INSTALLATION.md +129 -0
- package/CODEX_INSTALLATION.md +25 -1
- package/COPILOT_INSTALLATION.md +29 -1
- package/LICENSE +21 -21
- package/README.md +232 -110
- package/dist/analysis-provenance.d.ts +50 -2
- package/dist/analysis-provenance.js +1 -0
- package/dist/analysis-task-runner.js +92 -0
- package/dist/config.d.ts +35 -16
- package/dist/config.js +37 -3
- package/dist/database.js +115 -115
- package/dist/decompiler-worker.d.ts +10 -5
- package/dist/decompiler-worker.js +240 -58
- package/dist/dynamic-trace.d.ts +6 -0
- package/dist/dynamic-trace.js +52 -1
- package/dist/ghidra-config.js +17 -1
- package/dist/index.js +38 -8
- package/dist/pe-runtime-functions.d.ts +90 -0
- package/dist/pe-runtime-functions.js +452 -0
- package/dist/prompts/module-reconstruction-review.d.ts +5 -0
- package/dist/prompts/module-reconstruction-review.js +65 -0
- package/dist/runtime-correlation.d.ts +5 -0
- package/dist/runtime-correlation.js +179 -2
- package/dist/sample-workspace.d.ts +28 -0
- package/dist/sample-workspace.js +186 -0
- package/dist/semantic-name-suggestion-artifacts.d.ts +56 -0
- package/dist/semantic-name-suggestion-artifacts.js +87 -0
- package/dist/server.js +1 -1
- package/dist/setup-guidance.d.ts +73 -0
- package/dist/setup-guidance.js +211 -0
- package/dist/tools/artifact-read.d.ts +10 -10
- package/dist/tools/artifacts-diff.d.ts +8 -8
- package/dist/tools/artifacts-list.d.ts +16 -16
- package/dist/tools/attack-map.d.ts +8 -8
- package/dist/tools/binary-role-profile.d.ts +1197 -0
- package/dist/tools/binary-role-profile.js +575 -0
- package/dist/tools/code-function-explain-apply.d.ts +12 -12
- package/dist/tools/code-function-explain-prepare.d.ts +12 -12
- package/dist/tools/code-function-explain-review.d.ts +58 -58
- package/dist/tools/code-function-rename-apply.d.ts +12 -12
- package/dist/tools/code-function-rename-prepare.d.ts +14 -14
- package/dist/tools/code-function-rename-review.d.ts +66 -66
- package/dist/tools/code-functions-define.d.ts +337 -0
- package/dist/tools/code-functions-define.js +337 -0
- package/dist/tools/code-functions-list.js +1 -1
- package/dist/tools/code-functions-rank.js +1 -1
- package/dist/tools/code-functions-reconstruct.d.ts +368 -58
- package/dist/tools/code-functions-reconstruct.js +130 -10
- package/dist/tools/code-functions-smart-recover.d.ts +352 -0
- package/dist/tools/code-functions-smart-recover.js +190 -0
- package/dist/tools/code-module-review-apply.d.ts +233 -0
- package/dist/tools/code-module-review-apply.js +209 -0
- package/dist/tools/code-module-review-prepare.d.ts +756 -0
- package/dist/tools/code-module-review-prepare.js +343 -0
- package/dist/tools/code-module-review.d.ts +474 -0
- package/dist/tools/code-module-review.js +566 -0
- package/dist/tools/code-reconstruct-export.d.ts +193 -21
- package/dist/tools/code-reconstruct-export.js +578 -21
- package/dist/tools/code-reconstruct-plan.d.ts +20 -20
- package/dist/tools/com-role-profile.d.ts +353 -0
- package/dist/tools/com-role-profile.js +186 -0
- package/dist/tools/dll-export-profile.d.ts +625 -0
- package/dist/tools/dll-export-profile.js +230 -0
- package/dist/tools/dotnet-metadata-extract.d.ts +122 -122
- package/dist/tools/dotnet-reconstruct-export.d.ts +49 -49
- package/dist/tools/dotnet-types-list.d.ts +66 -66
- package/dist/tools/dynamic-dependencies.d.ts +144 -8
- package/dist/tools/dynamic-dependencies.js +20 -1
- package/dist/tools/dynamic-memory-import.js +105 -2
- package/dist/tools/ghidra-analyze.d.ts +20 -0
- package/dist/tools/ghidra-analyze.js +10 -2
- package/dist/tools/ghidra-health.d.ts +177 -0
- package/dist/tools/ghidra-health.js +28 -0
- package/dist/tools/ioc-export.d.ts +8 -8
- package/dist/tools/packer-detect.d.ts +14 -14
- package/dist/tools/packer-detect.js +6 -9
- package/dist/tools/pe-exports-extract.d.ts +8 -8
- package/dist/tools/pe-exports-extract.js +6 -9
- package/dist/tools/pe-fingerprint.d.ts +36 -36
- package/dist/tools/pe-imports-extract.d.ts +8 -8
- package/dist/tools/pe-imports-extract.js +6 -9
- package/dist/tools/pe-pdata-extract.d.ts +448 -0
- package/dist/tools/pe-pdata-extract.js +219 -0
- package/dist/tools/pe-symbols-recover.d.ts +227 -0
- package/dist/tools/pe-symbols-recover.js +316 -0
- package/dist/tools/report-generate.d.ts +15 -1
- package/dist/tools/report-generate.js +139 -16
- package/dist/tools/report-summarize.d.ts +2242 -8
- package/dist/tools/report-summarize.js +246 -10
- package/dist/tools/runtime-detect.d.ts +8 -8
- package/dist/tools/runtime-detect.js +2 -12
- package/dist/tools/rust-binary-analyze.d.ts +2047 -0
- package/dist/tools/rust-binary-analyze.js +443 -0
- package/dist/tools/sample-profile-get.d.ts +135 -16
- package/dist/tools/sample-profile-get.js +35 -32
- package/dist/tools/sandbox-execute.d.ts +10 -10
- package/dist/tools/strings-extract.d.ts +8 -8
- package/dist/tools/strings-extract.js +2 -12
- package/dist/tools/strings-floss-decode.d.ts +8 -8
- package/dist/tools/system-health.d.ts +172 -36
- package/dist/tools/system-health.js +14 -0
- package/dist/tools/system-setup-guide.d.ts +179 -0
- package/dist/tools/system-setup-guide.js +62 -0
- package/dist/tools/tool-help.d.ts +16 -16
- package/dist/tools/tool-help.js +172 -0
- package/dist/tools/yara-scan.d.ts +8 -8
- package/dist/types.d.ts +2 -0
- package/dist/workflows/function-explanation-review.d.ts +3034 -76
- package/dist/workflows/function-explanation-review.js +172 -42
- package/dist/workflows/function-index-recover.d.ts +333 -0
- package/dist/workflows/function-index-recover.js +291 -0
- package/dist/workflows/module-reconstruction-review.d.ts +3537 -0
- package/dist/workflows/module-reconstruction-review.js +354 -0
- package/dist/workflows/reconstruct.d.ts +2182 -223
- package/dist/workflows/reconstruct.js +575 -32
- package/dist/workflows/semantic-name-review.d.ts +1436 -85
- package/dist/workflows/semantic-name-review.js +150 -58
- package/dist/workflows/triage.d.ts +8 -8
- package/ghidra_scripts/DecompileFunction.java +487 -487
- package/ghidra_scripts/ExtractCFG.java +256 -256
- package/ghidra_scripts/ExtractFunctions.java +442 -442
- package/ghidra_scripts/README.md +112 -112
- package/ghidra_scripts/SearchFunctionReferences.java +380 -380
- package/helpers/DotNetMetadataProbe/DotNetMetadataProbe.csproj +9 -9
- package/helpers/DotNetMetadataProbe/Program.cs +566 -566
- package/install-to-claude.ps1 +432 -0
- package/install-to-codex.ps1 +256 -178
- package/install-to-copilot.ps1 +389 -303
- package/package.json +4 -2
- package/requirements.txt +9 -9
- package/workers/requirements-dynamic.txt +11 -11
- package/workers/requirements.txt +8 -8
- package/workers/speakeasy_compat.py +175 -175
- package/workers/static_worker.py +3474 -3474
package/README.md
CHANGED
|
@@ -1,44 +1,43 @@
|
|
|
1
1
|
# Windows EXE Decompiler MCP Server
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Chinese version: [`README_zh.md`](./README_zh.md)
|
|
4
4
|
|
|
5
|
-
An MCP server for Windows
|
|
5
|
+
An MCP server for Windows reverse engineering. It exposes PE triage, Ghidra-backed inspection, DLL/COM profiling, runtime evidence ingestion, Rust/.NET recovery, source-like reconstruction, and LLM-assisted review as reusable MCP tools for any tool-calling LLM.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
inspection, runtime evidence import, reconstruction workflows, and report
|
|
9
|
-
generation as MCP tools that any tool-calling LLM can consume.
|
|
7
|
+
## What this server is for
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
This project is meant to be a reusable reverse-engineering tool surface, not a pile of one-off local scripts.
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
over MCP instead of one-off local scripts.
|
|
11
|
+
It is designed to help MCP clients:
|
|
15
12
|
|
|
16
|
-
|
|
13
|
+
- triage Windows PE samples quickly
|
|
14
|
+
- inspect imports, exports, strings, packers, runtime hints, and binary role
|
|
15
|
+
- use Ghidra when available for decompile, CFG, search, and reconstruction
|
|
16
|
+
- recover usable function indexes when Ghidra function extraction fails
|
|
17
|
+
- correlate static evidence, runtime traces, memory snapshots, and semantic review artifacts
|
|
18
|
+
- export source-like reconstruction output with optional build and harness validation
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
- import / export / string / YARA analysis
|
|
20
|
-
- Ghidra-assisted decompile, CFG, and function search
|
|
21
|
-
- .NET metadata inspection
|
|
22
|
-
- runtime trace and memory snapshot import
|
|
23
|
-
- function naming and explanation review workflows
|
|
24
|
-
- source-like reconstruction export with validation harnesses
|
|
20
|
+
## Core capability areas
|
|
25
21
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
### Static analysis
|
|
22
|
+
### Sample and static analysis
|
|
29
23
|
|
|
30
24
|
- `sample.ingest`
|
|
31
25
|
- `sample.profile.get`
|
|
32
26
|
- `pe.fingerprint`
|
|
33
27
|
- `pe.imports.extract`
|
|
34
28
|
- `pe.exports.extract`
|
|
29
|
+
- `pe.pdata.extract`
|
|
30
|
+
- `dll.export.profile`
|
|
31
|
+
- `com.role.profile`
|
|
35
32
|
- `strings.extract`
|
|
36
33
|
- `strings.floss.decode`
|
|
37
34
|
- `yara.scan`
|
|
38
35
|
- `runtime.detect`
|
|
39
36
|
- `packer.detect`
|
|
37
|
+
- `binary.role.profile`
|
|
38
|
+
- `system.setup.guide`
|
|
40
39
|
|
|
41
|
-
### Ghidra and
|
|
40
|
+
### Ghidra and function analysis
|
|
42
41
|
|
|
43
42
|
- `ghidra.health`
|
|
44
43
|
- `ghidra.analyze`
|
|
@@ -50,18 +49,19 @@ Primary use cases:
|
|
|
50
49
|
- `code.function.cfg`
|
|
51
50
|
- `code.functions.reconstruct`
|
|
52
51
|
|
|
53
|
-
###
|
|
52
|
+
### Recovery for Rust and hard native samples
|
|
53
|
+
|
|
54
|
+
- `code.functions.smart_recover`
|
|
55
|
+
- `pe.symbols.recover`
|
|
56
|
+
- `code.functions.define`
|
|
57
|
+
- `rust_binary.analyze`
|
|
58
|
+
- `workflow.function_index_recover`
|
|
59
|
+
|
|
60
|
+
### .NET and managed inspection
|
|
54
61
|
|
|
55
|
-
- `code.reconstruct.plan`
|
|
56
|
-
- `code.reconstruct.export`
|
|
57
62
|
- `dotnet.metadata.extract`
|
|
58
63
|
- `dotnet.types.list`
|
|
59
64
|
- `dotnet.reconstruct.export`
|
|
60
|
-
- `workflow.triage`
|
|
61
|
-
- `workflow.deep_static`
|
|
62
|
-
- `workflow.reconstruct`
|
|
63
|
-
- `workflow.semantic_name_review`
|
|
64
|
-
- `workflow.function_explanation_review`
|
|
65
65
|
|
|
66
66
|
### Runtime evidence and reporting
|
|
67
67
|
|
|
@@ -78,6 +78,155 @@ Primary use cases:
|
|
|
78
78
|
- `artifacts.diff`
|
|
79
79
|
- `tool.help`
|
|
80
80
|
|
|
81
|
+
### Semantic review and reconstruction
|
|
82
|
+
|
|
83
|
+
- `code.function.rename.prepare`
|
|
84
|
+
- `code.function.rename.review`
|
|
85
|
+
- `code.function.rename.apply`
|
|
86
|
+
- `code.function.explain.prepare`
|
|
87
|
+
- `code.function.explain.review`
|
|
88
|
+
- `code.function.explain.apply`
|
|
89
|
+
- `code.module.review.prepare`
|
|
90
|
+
- `code.module.review`
|
|
91
|
+
- `code.module.review.apply`
|
|
92
|
+
- `code.reconstruct.plan`
|
|
93
|
+
- `code.reconstruct.export`
|
|
94
|
+
|
|
95
|
+
## High-level workflows
|
|
96
|
+
|
|
97
|
+
These are the main orchestration entrypoints for MCP clients.
|
|
98
|
+
|
|
99
|
+
### `workflow.triage`
|
|
100
|
+
|
|
101
|
+
Fast first-pass triage for PE samples. Use this when you want a quick answer before deeper recovery.
|
|
102
|
+
|
|
103
|
+
### `workflow.deep_static`
|
|
104
|
+
|
|
105
|
+
Long-running static pipeline for deeper analysis and ranking. Supports async job mode.
|
|
106
|
+
|
|
107
|
+
### `workflow.reconstruct`
|
|
108
|
+
|
|
109
|
+
The main high-level reconstruction workflow.
|
|
110
|
+
|
|
111
|
+
It can:
|
|
112
|
+
|
|
113
|
+
- run binary preflight
|
|
114
|
+
- detect Rust-oriented samples
|
|
115
|
+
- profile DLL lifecycle, export dispatch, callback surface, and COM activation hints
|
|
116
|
+
- auto-recover a function index when Ghidra function extraction is missing or degraded
|
|
117
|
+
- export native or .NET reconstruction output
|
|
118
|
+
- optionally validate build and run the generated harness
|
|
119
|
+
- tune export strategy based on role-aware preflight for native Rust, DLL, and COM-oriented samples
|
|
120
|
+
- carry runtime and semantic provenance through the result
|
|
121
|
+
|
|
122
|
+
### `workflow.function_index_recover`
|
|
123
|
+
|
|
124
|
+
High-level recovery chain for hard native binaries:
|
|
125
|
+
|
|
126
|
+
- `code.functions.smart_recover`
|
|
127
|
+
- `pe.symbols.recover`
|
|
128
|
+
- `code.functions.define`
|
|
129
|
+
|
|
130
|
+
Use this when Ghidra analysis exists but function extraction is empty or degraded.
|
|
131
|
+
|
|
132
|
+
### `workflow.semantic_name_review`
|
|
133
|
+
|
|
134
|
+
High-level semantic naming review workflow for external LLM clients. It can prepare evidence, request model review through MCP sampling when available, apply accepted names, and optionally refresh reconstruct/export output.
|
|
135
|
+
|
|
136
|
+
### `workflow.function_explanation_review`
|
|
137
|
+
|
|
138
|
+
High-level explanation workflow for external LLM clients. It can prepare evidence, request structured explanations, apply them, and optionally rerun reconstruct/export.
|
|
139
|
+
|
|
140
|
+
### `workflow.module_reconstruction_review`
|
|
141
|
+
|
|
142
|
+
High-level module review workflow for external LLM clients. It can prepare reconstructed modules for review, request structured module refinements through MCP sampling when available, apply accepted module summaries and guidance, and optionally refresh reconstruct/export output.
|
|
143
|
+
|
|
144
|
+
## Universal recovery model
|
|
145
|
+
|
|
146
|
+
This server does not assume Ghidra is always able to recover functions correctly.
|
|
147
|
+
|
|
148
|
+
For difficult native samples, especially Rust, Go, or heavily optimized binaries, the recovery path is:
|
|
149
|
+
|
|
150
|
+
1. `ghidra.analyze`
|
|
151
|
+
2. if Ghidra post-script extraction fails, use `pe.pdata.extract`
|
|
152
|
+
3. recover candidate function boundaries with `code.functions.smart_recover`
|
|
153
|
+
4. recover names with `pe.symbols.recover`
|
|
154
|
+
5. import the recovered boundaries with `code.functions.define`
|
|
155
|
+
6. continue with `code.functions.list`, `code.functions.rank`, `code.functions.reconstruct`, or `workflow.reconstruct`
|
|
156
|
+
|
|
157
|
+
This means `function_index` readiness is tracked separately from `decompile` and `cfg` readiness.
|
|
158
|
+
|
|
159
|
+
## Evidence scope, semantic scope, and replayability
|
|
160
|
+
|
|
161
|
+
Most high-level tools support explicit scope control so clients can choose between all history and the current session.
|
|
162
|
+
|
|
163
|
+
Runtime evidence selection:
|
|
164
|
+
|
|
165
|
+
- `evidence_scope=all`
|
|
166
|
+
- `evidence_scope=latest`
|
|
167
|
+
- `evidence_scope=session` with `evidence_session_tag`
|
|
168
|
+
|
|
169
|
+
Semantic naming / explanation / module-review selection:
|
|
170
|
+
|
|
171
|
+
- `semantic_scope=all`
|
|
172
|
+
- `semantic_scope=latest`
|
|
173
|
+
- `semantic_scope=session` with `semantic_session_tag`
|
|
174
|
+
|
|
175
|
+
Comparison-aware outputs are also supported through:
|
|
176
|
+
|
|
177
|
+
- `compare_evidence_scope`
|
|
178
|
+
- `compare_evidence_session_tag`
|
|
179
|
+
- `compare_semantic_scope`
|
|
180
|
+
- `compare_semantic_session_tag`
|
|
181
|
+
|
|
182
|
+
This allows MCP clients to ask not only "what is the current result?" but also "what changed compared with the previous evidence or semantic review session?"
|
|
183
|
+
|
|
184
|
+
## LLM review layers
|
|
185
|
+
|
|
186
|
+
This server supports multiple structured review layers for MCP clients with tool calling and optional sampling:
|
|
187
|
+
|
|
188
|
+
- function naming review
|
|
189
|
+
- function explanation review
|
|
190
|
+
- module reconstruction review
|
|
191
|
+
|
|
192
|
+
Each layer follows the same pattern:
|
|
193
|
+
|
|
194
|
+
1. prepare a structured evidence bundle
|
|
195
|
+
2. optionally ask the connected MCP client to perform a constrained review through sampling
|
|
196
|
+
3. apply accepted results as stable semantic artifacts
|
|
197
|
+
4. rerun reconstruct/export/report workflows against explicit semantic scope
|
|
198
|
+
|
|
199
|
+
## Async job model
|
|
200
|
+
|
|
201
|
+
Long-running workflows support queued execution and background completion:
|
|
202
|
+
|
|
203
|
+
- `workflow.deep_static`
|
|
204
|
+
- `workflow.reconstruct`
|
|
205
|
+
- `workflow.semantic_name_review`
|
|
206
|
+
- `workflow.function_explanation_review`
|
|
207
|
+
- `workflow.module_reconstruction_review`
|
|
208
|
+
|
|
209
|
+
Use these with:
|
|
210
|
+
|
|
211
|
+
- `task.status`
|
|
212
|
+
- `task.cancel`
|
|
213
|
+
- `task.sweep`
|
|
214
|
+
|
|
215
|
+
## Environment bootstrap and setup guidance
|
|
216
|
+
|
|
217
|
+
If a client starts using the server before Python, dynamic-analysis extras, or Ghidra are configured, use:
|
|
218
|
+
|
|
219
|
+
- `system.health`
|
|
220
|
+
- `dynamic.dependencies`
|
|
221
|
+
- `ghidra.health`
|
|
222
|
+
- `system.setup.guide`
|
|
223
|
+
|
|
224
|
+
These return structured setup actions and required user inputs so an MCP client can explicitly ask for:
|
|
225
|
+
|
|
226
|
+
- `python -m pip install ...`
|
|
227
|
+
- `GHIDRA_PATH` / `GHIDRA_INSTALL_DIR`
|
|
228
|
+
- optional dynamic-analysis extras such as Speakeasy/Frida dependencies
|
|
229
|
+
|
|
81
230
|
## Project layout
|
|
82
231
|
|
|
83
232
|
```text
|
|
@@ -90,6 +239,8 @@ tests/ unit and integration tests
|
|
|
90
239
|
workers/ Python worker, YARA rules, dynamic helpers
|
|
91
240
|
install-to-codex.ps1 local Codex MCP install helper
|
|
92
241
|
install-to-copilot.ps1 local GitHub Copilot MCP install helper
|
|
242
|
+
install-to-claude.ps1 local Claude Code MCP install helper
|
|
243
|
+
docs/QUALITY_EVALUATION.md evaluation checklist for regression and release readiness
|
|
93
244
|
```
|
|
94
245
|
|
|
95
246
|
## Prerequisites
|
|
@@ -108,7 +259,7 @@ Optional but strongly recommended:
|
|
|
108
259
|
- Python packages from [`requirements.txt`](./requirements.txt)
|
|
109
260
|
- Python worker packages from [`workers/requirements.txt`](./workers/requirements.txt)
|
|
110
261
|
|
|
111
|
-
## Local development
|
|
262
|
+
## Local development
|
|
112
263
|
|
|
113
264
|
Install JavaScript dependencies:
|
|
114
265
|
|
|
@@ -124,7 +275,7 @@ python -m pip install -r workers/requirements.txt
|
|
|
124
275
|
python -m pip install -r workers/requirements-dynamic.txt
|
|
125
276
|
```
|
|
126
277
|
|
|
127
|
-
Build
|
|
278
|
+
Build:
|
|
128
279
|
|
|
129
280
|
```bash
|
|
130
281
|
npm run build
|
|
@@ -136,7 +287,7 @@ Run tests:
|
|
|
136
287
|
npm test
|
|
137
288
|
```
|
|
138
289
|
|
|
139
|
-
Start
|
|
290
|
+
Start locally:
|
|
140
291
|
|
|
141
292
|
```bash
|
|
142
293
|
npm start
|
|
@@ -146,8 +297,6 @@ npm start
|
|
|
146
297
|
|
|
147
298
|
### Generic stdio config
|
|
148
299
|
|
|
149
|
-
Most MCP clients can start this server with:
|
|
150
|
-
|
|
151
300
|
```json
|
|
152
301
|
{
|
|
153
302
|
"mcpServers": {
|
|
@@ -166,19 +315,32 @@ Most MCP clients can start this server with:
|
|
|
166
315
|
|
|
167
316
|
### Local install helpers
|
|
168
317
|
|
|
169
|
-
This repository already includes local install scripts:
|
|
170
|
-
|
|
171
318
|
- Codex: [`install-to-codex.ps1`](./install-to-codex.ps1)
|
|
319
|
+
- Claude Code: [`install-to-claude.ps1`](./install-to-claude.ps1)
|
|
172
320
|
- GitHub Copilot: [`install-to-copilot.ps1`](./install-to-copilot.ps1)
|
|
173
321
|
|
|
174
322
|
Related docs:
|
|
175
323
|
|
|
176
324
|
- [`CODEX_INSTALLATION.md`](./CODEX_INSTALLATION.md)
|
|
177
325
|
- [`COPILOT_INSTALLATION.md`](./COPILOT_INSTALLATION.md)
|
|
326
|
+
- [`CLAUDE_INSTALLATION.md`](./CLAUDE_INSTALLATION.md)
|
|
327
|
+
|
|
328
|
+
## Persistent storage
|
|
329
|
+
|
|
330
|
+
By default, runtime state is stored under the user profile instead of the current working directory:
|
|
331
|
+
|
|
332
|
+
- Windows workspace root: `%USERPROFILE%/.windows-exe-decompiler-mcp-server/workspaces`
|
|
333
|
+
- SQLite database: `%USERPROFILE%/.windows-exe-decompiler-mcp-server/data/database.db`
|
|
334
|
+
- File cache: `%USERPROFILE%/.windows-exe-decompiler-mcp-server/cache`
|
|
335
|
+
- Audit log: `%USERPROFILE%/.windows-exe-decompiler-mcp-server/audit.log`
|
|
336
|
+
|
|
337
|
+
You can override these with environment variables or the user config file:
|
|
338
|
+
|
|
339
|
+
- `%USERPROFILE%/.windows-exe-decompiler-mcp-server/config.json`
|
|
178
340
|
|
|
179
341
|
## Sample ingest note
|
|
180
342
|
|
|
181
|
-
For local IDE clients such as VS Code or Copilot, prefer:
|
|
343
|
+
For local IDE clients such as VS Code or Copilot, prefer local file paths:
|
|
182
344
|
|
|
183
345
|
```json
|
|
184
346
|
{
|
|
@@ -189,23 +351,20 @@ For local IDE clients such as VS Code or Copilot, prefer:
|
|
|
189
351
|
}
|
|
190
352
|
```
|
|
191
353
|
|
|
192
|
-
Use `bytes_b64` only when the
|
|
193
|
-
the MCP server.
|
|
354
|
+
Use `bytes_b64` only when the client cannot access the same filesystem as the server.
|
|
194
355
|
|
|
195
356
|
## Publishing to npm
|
|
196
357
|
|
|
197
|
-
### What is included in the npm package
|
|
198
|
-
|
|
199
358
|
The published package includes:
|
|
200
359
|
|
|
201
360
|
- compiled `dist/`
|
|
202
|
-
-
|
|
361
|
+
- the CLI entrypoint in `bin/`
|
|
203
362
|
- Python workers and YARA rules
|
|
204
363
|
- Ghidra helper scripts
|
|
205
364
|
- the .NET metadata helper source
|
|
206
365
|
- MCP client install scripts
|
|
207
366
|
|
|
208
|
-
It
|
|
367
|
+
It excludes:
|
|
209
368
|
|
|
210
369
|
- tests
|
|
211
370
|
- local workspaces
|
|
@@ -213,68 +372,49 @@ It intentionally excludes:
|
|
|
213
372
|
- generated reports
|
|
214
373
|
- scratch documents and internal progress notes
|
|
215
374
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
1. Pick a package name that is available on npm.
|
|
219
|
-
2. Update the version in [`package.json`](./package.json).
|
|
220
|
-
3. Run:
|
|
221
|
-
|
|
222
|
-
```bash
|
|
223
|
-
npm run release:check
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
4. Inspect the dry-run pack list:
|
|
227
|
-
|
|
228
|
-
```bash
|
|
229
|
-
npm run pack:dry-run
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
5. Log in to npm:
|
|
233
|
-
|
|
234
|
-
```bash
|
|
235
|
-
npm login
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
6. Publish:
|
|
375
|
+
Pre-publish checklist:
|
|
239
376
|
|
|
240
|
-
|
|
241
|
-
npm
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
This repository now includes:
|
|
377
|
+
1. Update the version in [`package.json`](./package.json).
|
|
378
|
+
2. Run `npm run release:check`.
|
|
379
|
+
3. Inspect `npm run pack:dry-run`.
|
|
380
|
+
4. Log in with `npm login`.
|
|
381
|
+
5. Publish with `npm publish --access public`.
|
|
247
382
|
|
|
248
|
-
|
|
249
|
-
- [`publish-npm.yml`](./.github/workflows/publish-npm.yml): publish on `v*` tags or manual dispatch, then create a GitHub Release with the npm tarball attached
|
|
250
|
-
- [`dependabot.yml`](./.github/dependabot.yml): weekly npm and GitHub Actions dependency updates
|
|
383
|
+
GitHub automation included in this repository:
|
|
251
384
|
|
|
252
|
-
|
|
385
|
+
- [`ci.yml`](./.github/workflows/ci.yml)
|
|
386
|
+
- [`publish-npm.yml`](./.github/workflows/publish-npm.yml)
|
|
387
|
+
- [`dependabot.yml`](./.github/dependabot.yml)
|
|
253
388
|
|
|
254
|
-
|
|
389
|
+
For GitHub Actions publishing, configure the `NPM_TOKEN` repository secret.
|
|
255
390
|
|
|
256
|
-
|
|
391
|
+
## Security boundaries
|
|
257
392
|
|
|
258
|
-
|
|
259
|
-
npm version patch
|
|
260
|
-
git push origin main --follow-tags
|
|
261
|
-
```
|
|
393
|
+
This project is for analysis workflows, not live malware operations.
|
|
262
394
|
|
|
263
|
-
|
|
395
|
+
Current strengths:
|
|
264
396
|
|
|
265
|
-
|
|
397
|
+
- PE triage and classification support
|
|
398
|
+
- reverse-engineering evidence extraction
|
|
399
|
+
- IOC and ATT&CK export
|
|
400
|
+
- runtime evidence import and correlation
|
|
401
|
+
- source-like reconstruction and review
|
|
266
402
|
|
|
267
|
-
|
|
268
|
-
setup, validation, and release steps.
|
|
403
|
+
Current non-goals:
|
|
269
404
|
|
|
270
|
-
|
|
405
|
+
- original source recovery for complex native binaries
|
|
406
|
+
- guaranteed malware family attribution from static evidence alone
|
|
407
|
+
- fully automatic unpacking for every packer
|
|
408
|
+
- high-confidence semantic recovery of every function in heavily optimized code
|
|
271
409
|
|
|
272
|
-
|
|
273
|
-
and operational boundaries.
|
|
410
|
+
## Contributing and release process
|
|
274
411
|
|
|
275
|
-
|
|
412
|
+
- Contributor guide: [`CONTRIBUTING.md`](./CONTRIBUTING.md)
|
|
413
|
+
- Quality evaluation notes: [`docs/QUALITY_EVALUATION.md`](./docs/QUALITY_EVALUATION.md)
|
|
414
|
+
- Example benchmark corpus: [`examples/benchmark-corpus.example.json`](./examples/benchmark-corpus.example.json)
|
|
415
|
+
- Security policy: [`SECURITY.md`](./SECURITY.md)
|
|
276
416
|
|
|
277
|
-
|
|
417
|
+
## Using the published package
|
|
278
418
|
|
|
279
419
|
```json
|
|
280
420
|
{
|
|
@@ -291,24 +431,6 @@ Once published, an MCP client can use `npx`:
|
|
|
291
431
|
}
|
|
292
432
|
```
|
|
293
433
|
|
|
294
|
-
## Security boundaries
|
|
295
|
-
|
|
296
|
-
This project is designed for analysis workflows, not for live malware
|
|
297
|
-
operations. Current practical strengths are:
|
|
298
|
-
|
|
299
|
-
- triage and classification support
|
|
300
|
-
- reverse-engineering evidence extraction
|
|
301
|
-
- IOC and ATT&CK export
|
|
302
|
-
- runtime evidence import and correlation
|
|
303
|
-
- source-like reconstruction and review
|
|
304
|
-
|
|
305
|
-
Current non-goals:
|
|
306
|
-
|
|
307
|
-
- original source recovery for complex native binaries
|
|
308
|
-
- guaranteed malware family attribution from static evidence alone
|
|
309
|
-
- full automatic unpacking for all packers
|
|
310
|
-
- high-confidence semantic recovery of every function in heavily optimized code
|
|
311
|
-
|
|
312
434
|
## License
|
|
313
435
|
|
|
314
|
-
|
|
436
|
+
Released under the MIT license. See [`LICENSE`](./LICENSE).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { DynamicEvidenceScope, DynamicTraceSummary } from './dynamic-trace.js';
|
|
3
|
-
import type { SemanticArtifactScope, SemanticFunctionExplanationIndex, SemanticNameSuggestionIndex } from './semantic-name-suggestion-artifacts.js';
|
|
3
|
+
import type { SemanticArtifactScope, SemanticFunctionExplanationIndex, SemanticModuleReviewIndex, SemanticNameSuggestionIndex } from './semantic-name-suggestion-artifacts.js';
|
|
4
4
|
export declare const ArtifactSelectionProvenanceSchema: z.ZodObject<{
|
|
5
5
|
scope: z.ZodEnum<["all", "latest", "session"]>;
|
|
6
6
|
session_selector: z.ZodNullable<z.ZodString>;
|
|
@@ -114,6 +114,34 @@ export declare const AnalysisProvenanceSchema: z.ZodObject<{
|
|
|
114
114
|
earliest_artifact_at: string | null;
|
|
115
115
|
latest_artifact_at: string | null;
|
|
116
116
|
}>>;
|
|
117
|
+
semantic_module_reviews: z.ZodOptional<z.ZodObject<{
|
|
118
|
+
scope: z.ZodEnum<["all", "latest", "session"]>;
|
|
119
|
+
session_selector: z.ZodNullable<z.ZodString>;
|
|
120
|
+
artifact_count: z.ZodNumber;
|
|
121
|
+
artifact_ids: z.ZodArray<z.ZodString, "many">;
|
|
122
|
+
session_tags: z.ZodArray<z.ZodString, "many">;
|
|
123
|
+
earliest_artifact_at: z.ZodNullable<z.ZodString>;
|
|
124
|
+
latest_artifact_at: z.ZodNullable<z.ZodString>;
|
|
125
|
+
scope_note: z.ZodString;
|
|
126
|
+
}, "strip", z.ZodTypeAny, {
|
|
127
|
+
artifact_count: number;
|
|
128
|
+
scope_note: string;
|
|
129
|
+
artifact_ids: string[];
|
|
130
|
+
session_selector: string | null;
|
|
131
|
+
session_tags: string[];
|
|
132
|
+
scope: "all" | "latest" | "session";
|
|
133
|
+
earliest_artifact_at: string | null;
|
|
134
|
+
latest_artifact_at: string | null;
|
|
135
|
+
}, {
|
|
136
|
+
artifact_count: number;
|
|
137
|
+
scope_note: string;
|
|
138
|
+
artifact_ids: string[];
|
|
139
|
+
session_selector: string | null;
|
|
140
|
+
session_tags: string[];
|
|
141
|
+
scope: "all" | "latest" | "session";
|
|
142
|
+
earliest_artifact_at: string | null;
|
|
143
|
+
latest_artifact_at: string | null;
|
|
144
|
+
}>>;
|
|
117
145
|
}, "strip", z.ZodTypeAny, {
|
|
118
146
|
runtime: {
|
|
119
147
|
artifact_count: number;
|
|
@@ -125,6 +153,16 @@ export declare const AnalysisProvenanceSchema: z.ZodObject<{
|
|
|
125
153
|
earliest_artifact_at: string | null;
|
|
126
154
|
latest_artifact_at: string | null;
|
|
127
155
|
};
|
|
156
|
+
semantic_module_reviews?: {
|
|
157
|
+
artifact_count: number;
|
|
158
|
+
scope_note: string;
|
|
159
|
+
artifact_ids: string[];
|
|
160
|
+
session_selector: string | null;
|
|
161
|
+
session_tags: string[];
|
|
162
|
+
scope: "all" | "latest" | "session";
|
|
163
|
+
earliest_artifact_at: string | null;
|
|
164
|
+
latest_artifact_at: string | null;
|
|
165
|
+
} | undefined;
|
|
128
166
|
semantic_names?: {
|
|
129
167
|
artifact_count: number;
|
|
130
168
|
scope_note: string;
|
|
@@ -156,6 +194,16 @@ export declare const AnalysisProvenanceSchema: z.ZodObject<{
|
|
|
156
194
|
earliest_artifact_at: string | null;
|
|
157
195
|
latest_artifact_at: string | null;
|
|
158
196
|
};
|
|
197
|
+
semantic_module_reviews?: {
|
|
198
|
+
artifact_count: number;
|
|
199
|
+
scope_note: string;
|
|
200
|
+
artifact_ids: string[];
|
|
201
|
+
session_selector: string | null;
|
|
202
|
+
session_tags: string[];
|
|
203
|
+
scope: "all" | "latest" | "session";
|
|
204
|
+
earliest_artifact_at: string | null;
|
|
205
|
+
latest_artifact_at: string | null;
|
|
206
|
+
} | undefined;
|
|
159
207
|
semantic_names?: {
|
|
160
208
|
artifact_count: number;
|
|
161
209
|
scope_note: string;
|
|
@@ -179,6 +227,6 @@ export declare const AnalysisProvenanceSchema: z.ZodObject<{
|
|
|
179
227
|
}>;
|
|
180
228
|
type ArtifactSelectionProvenance = z.infer<typeof ArtifactSelectionProvenanceSchema>;
|
|
181
229
|
export declare function buildRuntimeArtifactProvenance(dynamicEvidence: DynamicTraceSummary | null | undefined, scope: DynamicEvidenceScope, sessionTag?: string | null): ArtifactSelectionProvenance;
|
|
182
|
-
export declare function buildSemanticArtifactProvenance(label: 'semantic naming artifacts' | 'semantic explanation artifacts', index: SemanticNameSuggestionIndex | SemanticFunctionExplanationIndex | null | undefined, scope: SemanticArtifactScope, sessionTag?: string | null): ArtifactSelectionProvenance;
|
|
230
|
+
export declare function buildSemanticArtifactProvenance(label: 'semantic naming artifacts' | 'semantic explanation artifacts' | 'semantic module review artifacts', index: SemanticNameSuggestionIndex | SemanticFunctionExplanationIndex | SemanticModuleReviewIndex | null | undefined, scope: SemanticArtifactScope, sessionTag?: string | null): ArtifactSelectionProvenance;
|
|
183
231
|
export {};
|
|
184
232
|
//# sourceMappingURL=analysis-provenance.d.ts.map
|
|
@@ -13,6 +13,7 @@ export const AnalysisProvenanceSchema = z.object({
|
|
|
13
13
|
runtime: ArtifactSelectionProvenanceSchema,
|
|
14
14
|
semantic_names: ArtifactSelectionProvenanceSchema.optional(),
|
|
15
15
|
semantic_explanations: ArtifactSelectionProvenanceSchema.optional(),
|
|
16
|
+
semantic_module_reviews: ArtifactSelectionProvenanceSchema.optional(),
|
|
16
17
|
});
|
|
17
18
|
function emptyScopeNote(label, scope, sessionTag) {
|
|
18
19
|
if (scope === 'session' && sessionTag?.trim()) {
|
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
import { DecompilerWorker, GhidraProcessError } from './decompiler-worker.js';
|
|
6
6
|
import { logger } from './logger.js';
|
|
7
7
|
import { deepStaticWorkflow } from './workflows/deep-static.js';
|
|
8
|
+
import { createReconstructWorkflowHandler } from './workflows/reconstruct.js';
|
|
9
|
+
import { createSemanticNameReviewWorkflowHandler } from './workflows/semantic-name-review.js';
|
|
10
|
+
import { createFunctionExplanationReviewWorkflowHandler } from './workflows/function-explanation-review.js';
|
|
11
|
+
import { createModuleReconstructionReviewWorkflowHandler } from './workflows/module-reconstruction-review.js';
|
|
8
12
|
export class AnalysisTaskRunner {
|
|
9
13
|
jobQueue;
|
|
10
14
|
decompilerWorker;
|
|
@@ -120,6 +124,10 @@ export class AnalysisTaskRunner {
|
|
|
120
124
|
timeout: job.timeout,
|
|
121
125
|
maxCpu: options.max_cpu || '4',
|
|
122
126
|
projectKey: options.project_key,
|
|
127
|
+
processor: options.processor,
|
|
128
|
+
languageId: options.language_id,
|
|
129
|
+
cspec: options.cspec,
|
|
130
|
+
scriptPaths: options.script_paths,
|
|
123
131
|
abortSignal,
|
|
124
132
|
});
|
|
125
133
|
return this.decompilerWorker.createJobResult(analysisResult, 0);
|
|
@@ -154,6 +162,90 @@ export class AnalysisTaskRunner {
|
|
|
154
162
|
},
|
|
155
163
|
};
|
|
156
164
|
}
|
|
165
|
+
if (job.tool === 'workflow.reconstruct') {
|
|
166
|
+
if (!this.cacheManager) {
|
|
167
|
+
throw new Error('workflow.reconstruct requires cache manager for queued execution');
|
|
168
|
+
}
|
|
169
|
+
this.jobQueue.updateProgress(job.id, 5);
|
|
170
|
+
const handler = createReconstructWorkflowHandler(this.workspaceManager, this.database, this.cacheManager);
|
|
171
|
+
const result = await handler(job.args || {});
|
|
172
|
+
this.jobQueue.updateProgress(job.id, 100);
|
|
173
|
+
return {
|
|
174
|
+
jobId: job.id,
|
|
175
|
+
ok: result.ok,
|
|
176
|
+
data: result.data,
|
|
177
|
+
errors: result.errors || [],
|
|
178
|
+
warnings: result.warnings || [],
|
|
179
|
+
artifacts: result.artifacts || [],
|
|
180
|
+
metrics: {
|
|
181
|
+
elapsedMs: typeof result.metrics?.elapsed_ms === 'number' ? result.metrics.elapsed_ms : 0,
|
|
182
|
+
peakRssMb: 0,
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
if (job.tool === 'workflow.semantic_name_review') {
|
|
187
|
+
if (!this.cacheManager) {
|
|
188
|
+
throw new Error('workflow.semantic_name_review requires cache manager for queued execution');
|
|
189
|
+
}
|
|
190
|
+
this.jobQueue.updateProgress(job.id, 5);
|
|
191
|
+
const handler = createSemanticNameReviewWorkflowHandler(this.workspaceManager, this.database, this.cacheManager);
|
|
192
|
+
const result = await handler(job.args || {});
|
|
193
|
+
this.jobQueue.updateProgress(job.id, 100);
|
|
194
|
+
return {
|
|
195
|
+
jobId: job.id,
|
|
196
|
+
ok: result.ok,
|
|
197
|
+
data: result.data,
|
|
198
|
+
errors: result.errors || [],
|
|
199
|
+
warnings: result.warnings || [],
|
|
200
|
+
artifacts: result.artifacts || [],
|
|
201
|
+
metrics: {
|
|
202
|
+
elapsedMs: typeof result.metrics?.elapsed_ms === 'number' ? result.metrics.elapsed_ms : 0,
|
|
203
|
+
peakRssMb: 0,
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
if (job.tool === 'workflow.function_explanation_review') {
|
|
208
|
+
if (!this.cacheManager) {
|
|
209
|
+
throw new Error('workflow.function_explanation_review requires cache manager for queued execution');
|
|
210
|
+
}
|
|
211
|
+
this.jobQueue.updateProgress(job.id, 5);
|
|
212
|
+
const handler = createFunctionExplanationReviewWorkflowHandler(this.workspaceManager, this.database, this.cacheManager);
|
|
213
|
+
const result = await handler(job.args || {});
|
|
214
|
+
this.jobQueue.updateProgress(job.id, 100);
|
|
215
|
+
return {
|
|
216
|
+
jobId: job.id,
|
|
217
|
+
ok: result.ok,
|
|
218
|
+
data: result.data,
|
|
219
|
+
errors: result.errors || [],
|
|
220
|
+
warnings: result.warnings || [],
|
|
221
|
+
artifacts: result.artifacts || [],
|
|
222
|
+
metrics: {
|
|
223
|
+
elapsedMs: typeof result.metrics?.elapsed_ms === 'number' ? result.metrics.elapsed_ms : 0,
|
|
224
|
+
peakRssMb: 0,
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
if (job.tool === 'workflow.module_reconstruction_review') {
|
|
229
|
+
if (!this.cacheManager) {
|
|
230
|
+
throw new Error('workflow.module_reconstruction_review requires cache manager for queued execution');
|
|
231
|
+
}
|
|
232
|
+
this.jobQueue.updateProgress(job.id, 5);
|
|
233
|
+
const handler = createModuleReconstructionReviewWorkflowHandler(this.workspaceManager, this.database, this.cacheManager);
|
|
234
|
+
const result = await handler(job.args || {});
|
|
235
|
+
this.jobQueue.updateProgress(job.id, 100);
|
|
236
|
+
return {
|
|
237
|
+
jobId: job.id,
|
|
238
|
+
ok: result.ok,
|
|
239
|
+
data: result.data,
|
|
240
|
+
errors: result.errors || [],
|
|
241
|
+
warnings: result.warnings || [],
|
|
242
|
+
artifacts: result.artifacts || [],
|
|
243
|
+
metrics: {
|
|
244
|
+
elapsedMs: typeof result.metrics?.elapsed_ms === 'number' ? result.metrics.elapsed_ms : 0,
|
|
245
|
+
peakRssMb: 0,
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
}
|
|
157
249
|
throw new Error(`Unsupported queued tool: ${job.tool}`);
|
|
158
250
|
}
|
|
159
251
|
}
|