windows-exe-decompiler-mcp-server 0.1.0
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/CODEX_INSTALLATION.md +69 -0
- package/COPILOT_INSTALLATION.md +77 -0
- package/LICENSE +21 -0
- package/README.md +314 -0
- package/bin/windows-exe-decompiler-mcp-server.js +3 -0
- package/dist/analysis-provenance.d.ts +184 -0
- package/dist/analysis-provenance.js +74 -0
- package/dist/analysis-task-runner.d.ts +31 -0
- package/dist/analysis-task-runner.js +160 -0
- package/dist/artifact-inventory.d.ts +23 -0
- package/dist/artifact-inventory.js +175 -0
- package/dist/cache-manager.d.ts +128 -0
- package/dist/cache-manager.js +454 -0
- package/dist/confidence-semantics.d.ts +66 -0
- package/dist/confidence-semantics.js +122 -0
- package/dist/config.d.ts +335 -0
- package/dist/config.js +193 -0
- package/dist/database.d.ts +227 -0
- package/dist/database.js +601 -0
- package/dist/decompiler-worker.d.ts +441 -0
- package/dist/decompiler-worker.js +1962 -0
- package/dist/dynamic-trace.d.ts +95 -0
- package/dist/dynamic-trace.js +629 -0
- package/dist/env-validator.d.ts +15 -0
- package/dist/env-validator.js +249 -0
- package/dist/error-handler.d.ts +28 -0
- package/dist/error-handler.example.d.ts +22 -0
- package/dist/error-handler.example.js +141 -0
- package/dist/error-handler.js +139 -0
- package/dist/ghidra-analysis-status.d.ts +49 -0
- package/dist/ghidra-analysis-status.js +178 -0
- package/dist/ghidra-config.d.ts +134 -0
- package/dist/ghidra-config.js +464 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +200 -0
- package/dist/job-queue.d.ts +169 -0
- package/dist/job-queue.js +407 -0
- package/dist/logger.d.ts +106 -0
- package/dist/logger.js +176 -0
- package/dist/policy-guard.d.ts +115 -0
- package/dist/policy-guard.js +243 -0
- package/dist/process-output.d.ts +15 -0
- package/dist/process-output.js +90 -0
- package/dist/prompts/function-explanation-review.d.ts +5 -0
- package/dist/prompts/function-explanation-review.js +64 -0
- package/dist/prompts/semantic-name-review.d.ts +5 -0
- package/dist/prompts/semantic-name-review.js +63 -0
- package/dist/runtime-correlation.d.ts +34 -0
- package/dist/runtime-correlation.js +279 -0
- package/dist/runtime-paths.d.ts +3 -0
- package/dist/runtime-paths.js +11 -0
- package/dist/selection-diff.d.ts +667 -0
- package/dist/selection-diff.js +53 -0
- package/dist/semantic-name-suggestion-artifacts.d.ts +116 -0
- package/dist/semantic-name-suggestion-artifacts.js +314 -0
- package/dist/server.d.ts +129 -0
- package/dist/server.js +578 -0
- package/dist/tools/artifact-read.d.ts +235 -0
- package/dist/tools/artifact-read.js +317 -0
- package/dist/tools/artifacts-diff.d.ts +728 -0
- package/dist/tools/artifacts-diff.js +304 -0
- package/dist/tools/artifacts-list.d.ts +515 -0
- package/dist/tools/artifacts-list.js +389 -0
- package/dist/tools/attack-map.d.ts +290 -0
- package/dist/tools/attack-map.js +519 -0
- package/dist/tools/cache-observability.d.ts +4 -0
- package/dist/tools/cache-observability.js +36 -0
- package/dist/tools/code-function-cfg.d.ts +50 -0
- package/dist/tools/code-function-cfg.js +102 -0
- package/dist/tools/code-function-decompile.d.ts +55 -0
- package/dist/tools/code-function-decompile.js +103 -0
- package/dist/tools/code-function-disassemble.d.ts +43 -0
- package/dist/tools/code-function-disassemble.js +185 -0
- package/dist/tools/code-function-explain-apply.d.ts +255 -0
- package/dist/tools/code-function-explain-apply.js +225 -0
- package/dist/tools/code-function-explain-prepare.d.ts +535 -0
- package/dist/tools/code-function-explain-prepare.js +276 -0
- package/dist/tools/code-function-explain-review.d.ts +397 -0
- package/dist/tools/code-function-explain-review.js +589 -0
- package/dist/tools/code-function-rename-apply.d.ts +248 -0
- package/dist/tools/code-function-rename-apply.js +220 -0
- package/dist/tools/code-function-rename-prepare.d.ts +506 -0
- package/dist/tools/code-function-rename-prepare.js +279 -0
- package/dist/tools/code-function-rename-review.d.ts +574 -0
- package/dist/tools/code-function-rename-review.js +761 -0
- package/dist/tools/code-functions-list.d.ts +37 -0
- package/dist/tools/code-functions-list.js +91 -0
- package/dist/tools/code-functions-rank.d.ts +34 -0
- package/dist/tools/code-functions-rank.js +90 -0
- package/dist/tools/code-functions-reconstruct.d.ts +2725 -0
- package/dist/tools/code-functions-reconstruct.js +2807 -0
- package/dist/tools/code-functions-search.d.ts +39 -0
- package/dist/tools/code-functions-search.js +90 -0
- package/dist/tools/code-reconstruct-export.d.ts +1212 -0
- package/dist/tools/code-reconstruct-export.js +4002 -0
- package/dist/tools/code-reconstruct-plan.d.ts +274 -0
- package/dist/tools/code-reconstruct-plan.js +342 -0
- package/dist/tools/dotnet-metadata-extract.d.ts +541 -0
- package/dist/tools/dotnet-metadata-extract.js +355 -0
- package/dist/tools/dotnet-reconstruct-export.d.ts +567 -0
- package/dist/tools/dotnet-reconstruct-export.js +1151 -0
- package/dist/tools/dotnet-types-list.d.ts +325 -0
- package/dist/tools/dotnet-types-list.js +201 -0
- package/dist/tools/dynamic-dependencies.d.ts +115 -0
- package/dist/tools/dynamic-dependencies.js +213 -0
- package/dist/tools/dynamic-memory-import.d.ts +10 -0
- package/dist/tools/dynamic-memory-import.js +567 -0
- package/dist/tools/dynamic-trace-import.d.ts +10 -0
- package/dist/tools/dynamic-trace-import.js +235 -0
- package/dist/tools/entrypoint-fallback-disasm.d.ts +30 -0
- package/dist/tools/entrypoint-fallback-disasm.js +89 -0
- package/dist/tools/ghidra-analyze.d.ts +88 -0
- package/dist/tools/ghidra-analyze.js +208 -0
- package/dist/tools/ghidra-health.d.ts +37 -0
- package/dist/tools/ghidra-health.js +212 -0
- package/dist/tools/ioc-export.d.ts +209 -0
- package/dist/tools/ioc-export.js +542 -0
- package/dist/tools/packer-detect.d.ts +165 -0
- package/dist/tools/packer-detect.js +284 -0
- package/dist/tools/pe-exports-extract.d.ts +175 -0
- package/dist/tools/pe-exports-extract.js +253 -0
- package/dist/tools/pe-fingerprint.d.ts +234 -0
- package/dist/tools/pe-fingerprint.js +269 -0
- package/dist/tools/pe-imports-extract.d.ts +105 -0
- package/dist/tools/pe-imports-extract.js +245 -0
- package/dist/tools/report-generate.d.ts +157 -0
- package/dist/tools/report-generate.js +457 -0
- package/dist/tools/report-summarize.d.ts +2131 -0
- package/dist/tools/report-summarize.js +596 -0
- package/dist/tools/runtime-detect.d.ts +135 -0
- package/dist/tools/runtime-detect.js +247 -0
- package/dist/tools/sample-ingest.d.ts +94 -0
- package/dist/tools/sample-ingest.js +327 -0
- package/dist/tools/sample-profile-get.d.ts +183 -0
- package/dist/tools/sample-profile-get.js +121 -0
- package/dist/tools/sandbox-execute.d.ts +441 -0
- package/dist/tools/sandbox-execute.js +392 -0
- package/dist/tools/strings-extract.d.ts +375 -0
- package/dist/tools/strings-extract.js +314 -0
- package/dist/tools/strings-floss-decode.d.ts +143 -0
- package/dist/tools/strings-floss-decode.js +259 -0
- package/dist/tools/system-health.d.ts +434 -0
- package/dist/tools/system-health.js +446 -0
- package/dist/tools/task-cancel.d.ts +21 -0
- package/dist/tools/task-cancel.js +70 -0
- package/dist/tools/task-status.d.ts +27 -0
- package/dist/tools/task-status.js +106 -0
- package/dist/tools/task-sweep.d.ts +22 -0
- package/dist/tools/task-sweep.js +77 -0
- package/dist/tools/tool-help.d.ts +340 -0
- package/dist/tools/tool-help.js +261 -0
- package/dist/tools/yara-scan.d.ts +554 -0
- package/dist/tools/yara-scan.js +313 -0
- package/dist/types.d.ts +266 -0
- package/dist/types.js +41 -0
- package/dist/worker-pool.d.ts +204 -0
- package/dist/worker-pool.js +650 -0
- package/dist/workflows/deep-static.d.ts +104 -0
- package/dist/workflows/deep-static.js +276 -0
- package/dist/workflows/function-explanation-review.d.ts +655 -0
- package/dist/workflows/function-explanation-review.js +440 -0
- package/dist/workflows/reconstruct.d.ts +2053 -0
- package/dist/workflows/reconstruct.js +666 -0
- package/dist/workflows/semantic-name-review.d.ts +2418 -0
- package/dist/workflows/semantic-name-review.js +521 -0
- package/dist/workflows/triage.d.ts +659 -0
- package/dist/workflows/triage.js +1374 -0
- package/dist/workspace-manager.d.ts +150 -0
- package/dist/workspace-manager.js +411 -0
- package/ghidra_scripts/DecompileFunction.java +487 -0
- package/ghidra_scripts/DecompileFunction.py +150 -0
- package/ghidra_scripts/ExtractCFG.java +256 -0
- package/ghidra_scripts/ExtractCFG.py +233 -0
- package/ghidra_scripts/ExtractFunctions.java +442 -0
- package/ghidra_scripts/ExtractFunctions.py +101 -0
- package/ghidra_scripts/README.md +125 -0
- package/ghidra_scripts/SearchFunctionReferences.java +380 -0
- package/helpers/DotNetMetadataProbe/DotNetMetadataProbe.csproj +9 -0
- package/helpers/DotNetMetadataProbe/Program.cs +566 -0
- package/install-to-codex.ps1 +178 -0
- package/install-to-copilot.ps1 +303 -0
- package/package.json +101 -0
- package/requirements.txt +9 -0
- package/workers/requirements-dynamic.txt +11 -0
- package/workers/requirements.txt +8 -0
- package/workers/speakeasy_compat.py +175 -0
- package/workers/static_worker.py +5183 -0
- package/workers/yara_rules/default.yar +33 -0
- package/workers/yara_rules/malware_families.yar +93 -0
- package/workers/yara_rules/packers.yar +80 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[string]$ServerName = "windows-exe-decompiler",
|
|
3
|
+
[string]$ProjectRoot = (Get-Location).Path,
|
|
4
|
+
[string]$NodePath,
|
|
5
|
+
[string]$GhidraPath = "",
|
|
6
|
+
[string]$ConfigPath = "$env:USERPROFILE\.codex\config.toml",
|
|
7
|
+
[switch]$NoBackup
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
Set-StrictMode -Version Latest
|
|
11
|
+
$ErrorActionPreference = "Stop"
|
|
12
|
+
|
|
13
|
+
function Write-Step {
|
|
14
|
+
param([string]$Message)
|
|
15
|
+
Write-Host ""
|
|
16
|
+
Write-Host $Message -ForegroundColor Yellow
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function Convert-ToConfigPath {
|
|
20
|
+
param([Parameter(Mandatory = $true)][string]$PathValue)
|
|
21
|
+
return ([System.IO.Path]::GetFullPath($PathValue) -replace "\\", "/")
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function Get-NodeExecutable {
|
|
25
|
+
if ($NodePath) {
|
|
26
|
+
if (-not (Test-Path -Path $NodePath)) {
|
|
27
|
+
throw "NodePath does not exist: $NodePath"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return [System.IO.Path]::GetFullPath($NodePath)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
$nodeCommand = Get-Command node -ErrorAction SilentlyContinue
|
|
34
|
+
if ($null -eq $nodeCommand) {
|
|
35
|
+
throw "Node.js was not found in PATH. Install Node.js or pass -NodePath."
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return $nodeCommand.Source
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function Resolve-GhidraPath {
|
|
42
|
+
if ($GhidraPath) {
|
|
43
|
+
return $GhidraPath
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if ($env:GHIDRA_PATH) {
|
|
47
|
+
return $env:GHIDRA_PATH
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if ($env:GHIDRA_INSTALL_DIR) {
|
|
51
|
+
return $env:GHIDRA_INSTALL_DIR
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return ""
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function Backup-FileIfNeeded {
|
|
58
|
+
param([Parameter(Mandatory = $true)][string]$PathValue)
|
|
59
|
+
|
|
60
|
+
if ($NoBackup -or -not (Test-Path -Path $PathValue)) {
|
|
61
|
+
return $null
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
|
|
65
|
+
$backupPath = "$PathValue.$timestamp.bak"
|
|
66
|
+
Copy-Item -Path $PathValue -Destination $backupPath -Force
|
|
67
|
+
return $backupPath
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function Ensure-ParentDirectory {
|
|
71
|
+
param([Parameter(Mandatory = $true)][string]$PathValue)
|
|
72
|
+
|
|
73
|
+
$parent = Split-Path -Path $PathValue -Parent
|
|
74
|
+
if ($parent -and -not (Test-Path -Path $parent)) {
|
|
75
|
+
New-Item -Path $parent -ItemType Directory -Force | Out-Null
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function Build-ServerBlock {
|
|
80
|
+
param(
|
|
81
|
+
[Parameter(Mandatory = $true)][string]$NodeExecutableConfig,
|
|
82
|
+
[Parameter(Mandatory = $true)][string]$EntryPathConfig,
|
|
83
|
+
[Parameter(Mandatory = $true)][string]$ProjectRootConfig,
|
|
84
|
+
[string]$GhidraPathConfig
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
$lines = @(
|
|
88
|
+
"[mcp_servers.$ServerName]"
|
|
89
|
+
"command = `"$NodeExecutableConfig`""
|
|
90
|
+
"args = [`"$EntryPathConfig`"]"
|
|
91
|
+
"cwd = `"$ProjectRootConfig`""
|
|
92
|
+
"startup_timeout_sec = 30"
|
|
93
|
+
"tool_timeout_sec = 300"
|
|
94
|
+
"enabled = true"
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
if ($GhidraPathConfig) {
|
|
98
|
+
$lines += "env = { GHIDRA_PATH = `"$GhidraPathConfig`", GHIDRA_INSTALL_DIR = `"$GhidraPathConfig`" }"
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return ($lines -join [Environment]::NewLine)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function Upsert-ConfigBlock {
|
|
105
|
+
param(
|
|
106
|
+
[Parameter(Mandatory = $true)][string]$PathValue,
|
|
107
|
+
[Parameter(Mandatory = $true)][string]$BlockText
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
Ensure-ParentDirectory -PathValue $PathValue
|
|
111
|
+
|
|
112
|
+
$existing = ""
|
|
113
|
+
if (Test-Path -Path $PathValue) {
|
|
114
|
+
$existing = Get-Content -Path $PathValue -Raw
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
$pattern = "(?ms)^\[mcp_servers\.$([regex]::Escape($ServerName))\]\r?\n.*?(?=^\[|\z)"
|
|
118
|
+
if ($existing -match $pattern) {
|
|
119
|
+
$updated = [regex]::Replace($existing, $pattern, $BlockText + [Environment]::NewLine)
|
|
120
|
+
} else {
|
|
121
|
+
$separator = if ([string]::IsNullOrWhiteSpace($existing)) { "" } else { [Environment]::NewLine + [Environment]::NewLine }
|
|
122
|
+
$updated = $existing.TrimEnd() + $separator + $BlockText + [Environment]::NewLine
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
[System.IO.File]::WriteAllText($PathValue, $updated, [System.Text.UTF8Encoding]::new($false))
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
Write-Host "=== Windows EXE Decompiler MCP Server - Codex Install ===" -ForegroundColor Cyan
|
|
129
|
+
|
|
130
|
+
Write-Step "Step 1: Validate build output"
|
|
131
|
+
$projectRootFull = [System.IO.Path]::GetFullPath($ProjectRoot)
|
|
132
|
+
$entryPath = Join-Path -Path $projectRootFull -ChildPath "dist/index.js"
|
|
133
|
+
if (-not (Test-Path -Path $entryPath)) {
|
|
134
|
+
throw "dist/index.js was not found. Run 'npm run build' from the project root first."
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
$nodeExecutable = Get-NodeExecutable
|
|
138
|
+
$ghidraPathResolved = Resolve-GhidraPath
|
|
139
|
+
|
|
140
|
+
$nodeExecutableConfig = Convert-ToConfigPath -PathValue $nodeExecutable
|
|
141
|
+
$entryPathConfig = Convert-ToConfigPath -PathValue $entryPath
|
|
142
|
+
$projectRootConfig = Convert-ToConfigPath -PathValue $projectRootFull
|
|
143
|
+
$ghidraPathConfig = if ($ghidraPathResolved) { Convert-ToConfigPath -PathValue $ghidraPathResolved } else { "" }
|
|
144
|
+
|
|
145
|
+
Write-Host "Project root: $projectRootConfig" -ForegroundColor Gray
|
|
146
|
+
Write-Host "Node path: $nodeExecutableConfig" -ForegroundColor Gray
|
|
147
|
+
Write-Host "Server entry: $entryPathConfig" -ForegroundColor Gray
|
|
148
|
+
if ($ghidraPathConfig) {
|
|
149
|
+
Write-Host "Ghidra path: $ghidraPathConfig" -ForegroundColor Gray
|
|
150
|
+
} else {
|
|
151
|
+
Write-Host "No Ghidra path supplied. The config will be written without GHIDRA_PATH." -ForegroundColor Yellow
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
Write-Step "Step 2: Register MCP server with Codex"
|
|
155
|
+
& codex mcp add $ServerName -- $nodeExecutableConfig $entryPathConfig
|
|
156
|
+
if ($LASTEXITCODE -ne 0) {
|
|
157
|
+
throw "codex mcp add failed."
|
|
158
|
+
}
|
|
159
|
+
Write-Host "Codex registration completed." -ForegroundColor Green
|
|
160
|
+
|
|
161
|
+
Write-Step "Step 3: Update Codex config"
|
|
162
|
+
$backupPath = Backup-FileIfNeeded -PathValue $ConfigPath
|
|
163
|
+
$serverBlock = Build-ServerBlock -NodeExecutableConfig $nodeExecutableConfig -EntryPathConfig $entryPathConfig -ProjectRootConfig $projectRootConfig -GhidraPathConfig $ghidraPathConfig
|
|
164
|
+
Upsert-ConfigBlock -PathValue $ConfigPath -BlockText $serverBlock
|
|
165
|
+
Write-Host "Config written: $ConfigPath" -ForegroundColor Green
|
|
166
|
+
if ($backupPath) {
|
|
167
|
+
Write-Host "Backup file: $backupPath" -ForegroundColor Gray
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
Write-Step "Step 4: Verify installation"
|
|
171
|
+
& codex mcp list
|
|
172
|
+
|
|
173
|
+
Write-Step "Next steps"
|
|
174
|
+
Write-Host "1. Restart Codex if it was already running." -ForegroundColor White
|
|
175
|
+
Write-Host "2. Ask Codex to call 'tool.help' or 'workflow.triage'." -ForegroundColor White
|
|
176
|
+
Write-Host "3. If native analysis is needed, pass -GhidraPath or set GHIDRA_PATH." -ForegroundColor White
|
|
177
|
+
Write-Host ""
|
|
178
|
+
Write-Host "Installation complete." -ForegroundColor Green
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[string]$ServerName = "windows-exe-decompiler",
|
|
3
|
+
[string]$ProjectRoot = (Get-Location).Path,
|
|
4
|
+
[string]$NodePath,
|
|
5
|
+
[string]$GhidraPath = "",
|
|
6
|
+
[string]$WorkspaceConfigPath,
|
|
7
|
+
[string]$CopilotCliConfigPath,
|
|
8
|
+
[switch]$SkipWorkspaceConfig,
|
|
9
|
+
[switch]$SkipCopilotCliConfig,
|
|
10
|
+
[switch]$InstallVsCodeUserProfile,
|
|
11
|
+
[switch]$NoBackup
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
Set-StrictMode -Version Latest
|
|
15
|
+
$ErrorActionPreference = "Stop"
|
|
16
|
+
|
|
17
|
+
function Write-Step {
|
|
18
|
+
param(
|
|
19
|
+
[string]$Message
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
Write-Host ""
|
|
23
|
+
Write-Host $Message -ForegroundColor Yellow
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function Convert-ToConfigPath {
|
|
27
|
+
param(
|
|
28
|
+
[Parameter(Mandatory = $true)]
|
|
29
|
+
[string]$PathValue
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
$resolved = [System.IO.Path]::GetFullPath($PathValue)
|
|
33
|
+
return ($resolved -replace "\\", "/")
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function Ensure-Directory {
|
|
37
|
+
param(
|
|
38
|
+
[Parameter(Mandatory = $true)]
|
|
39
|
+
[string]$FilePath
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
$directory = Split-Path -Path $FilePath -Parent
|
|
43
|
+
if ($directory -and -not (Test-Path -Path $directory)) {
|
|
44
|
+
New-Item -Path $directory -ItemType Directory -Force | Out-Null
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function Backup-FileIfNeeded {
|
|
49
|
+
param(
|
|
50
|
+
[Parameter(Mandatory = $true)]
|
|
51
|
+
[string]$PathValue
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
if ($NoBackup -or -not (Test-Path -Path $PathValue)) {
|
|
55
|
+
return $null
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
|
|
59
|
+
$backupPath = "$PathValue.$timestamp.bak"
|
|
60
|
+
Copy-Item -Path $PathValue -Destination $backupPath -Force
|
|
61
|
+
return $backupPath
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function Load-JsonConfig {
|
|
65
|
+
param(
|
|
66
|
+
[Parameter(Mandatory = $true)]
|
|
67
|
+
[string]$PathValue,
|
|
68
|
+
|
|
69
|
+
[Parameter(Mandatory = $true)]
|
|
70
|
+
[string]$RootProperty
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
if (-not (Test-Path -Path $PathValue)) {
|
|
74
|
+
return [pscustomobject]@{
|
|
75
|
+
$RootProperty = [pscustomobject]@{}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
$raw = Get-Content -Path $PathValue -Raw
|
|
80
|
+
if ([string]::IsNullOrWhiteSpace($raw)) {
|
|
81
|
+
return [pscustomobject]@{
|
|
82
|
+
$RootProperty = [pscustomobject]@{}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
$config = $raw | ConvertFrom-Json
|
|
87
|
+
if ($null -eq $config) {
|
|
88
|
+
return [pscustomobject]@{
|
|
89
|
+
$RootProperty = [pscustomobject]@{}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (-not ($config.PSObject.Properties.Name -contains $RootProperty)) {
|
|
94
|
+
$config | Add-Member -NotePropertyName $RootProperty -NotePropertyValue ([pscustomobject]@{})
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return $config
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function Set-NamedProperty {
|
|
101
|
+
param(
|
|
102
|
+
[Parameter(Mandatory = $true)]
|
|
103
|
+
[object]$Object,
|
|
104
|
+
|
|
105
|
+
[Parameter(Mandatory = $true)]
|
|
106
|
+
[string]$Name,
|
|
107
|
+
|
|
108
|
+
[Parameter(Mandatory = $true)]
|
|
109
|
+
[object]$Value
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
$existingProperty = $Object.PSObject.Properties[$Name]
|
|
113
|
+
if ($null -ne $existingProperty) {
|
|
114
|
+
$Object.$Name = $Value
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
$Object | Add-Member -NotePropertyName $Name -NotePropertyValue $Value
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function Save-JsonConfig {
|
|
122
|
+
param(
|
|
123
|
+
[Parameter(Mandatory = $true)]
|
|
124
|
+
[string]$PathValue,
|
|
125
|
+
|
|
126
|
+
[Parameter(Mandatory = $true)]
|
|
127
|
+
[object]$Config
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
Ensure-Directory -FilePath $PathValue
|
|
131
|
+
$json = $Config | ConvertTo-Json -Depth 20
|
|
132
|
+
[System.IO.File]::WriteAllText($PathValue, $json + [Environment]::NewLine, [System.Text.UTF8Encoding]::new($false))
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function Get-NodeExecutable {
|
|
136
|
+
if ($NodePath) {
|
|
137
|
+
if (-not (Test-Path -Path $NodePath)) {
|
|
138
|
+
throw "NodePath does not exist: $NodePath"
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return [System.IO.Path]::GetFullPath($NodePath)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
$nodeCommand = Get-Command node -ErrorAction SilentlyContinue
|
|
145
|
+
if ($null -eq $nodeCommand) {
|
|
146
|
+
throw "Node.js is not available in PATH. Install Node.js or pass -NodePath explicitly."
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return $nodeCommand.Source
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function Resolve-GhidraPath {
|
|
153
|
+
if ($GhidraPath) {
|
|
154
|
+
return $GhidraPath
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if ($env:GHIDRA_PATH) {
|
|
158
|
+
return $env:GHIDRA_PATH
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if ($env:GHIDRA_INSTALL_DIR) {
|
|
162
|
+
return $env:GHIDRA_INSTALL_DIR
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return ""
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
Write-Host "=== Windows EXE Decompiler MCP Server - GitHub Copilot Install ===" -ForegroundColor Cyan
|
|
169
|
+
|
|
170
|
+
Write-Step "Step 1: Validate build output and runtime"
|
|
171
|
+
$projectRootFull = [System.IO.Path]::GetFullPath($ProjectRoot)
|
|
172
|
+
$distEntry = Join-Path -Path $projectRootFull -ChildPath "dist/index.js"
|
|
173
|
+
if (-not (Test-Path -Path $distEntry)) {
|
|
174
|
+
throw "dist/index.js was not found. Run 'npm run build' from the project root first."
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
$nodeExecutable = Get-NodeExecutable
|
|
178
|
+
$nodeExecutableConfig = Convert-ToConfigPath -PathValue $nodeExecutable
|
|
179
|
+
$distEntryConfig = Convert-ToConfigPath -PathValue $distEntry
|
|
180
|
+
$projectRootConfig = Convert-ToConfigPath -PathValue $projectRootFull
|
|
181
|
+
$ghidraPathResolved = Resolve-GhidraPath
|
|
182
|
+
$ghidraPathExists = $ghidraPathResolved -and (Test-Path -Path $ghidraPathResolved)
|
|
183
|
+
$ghidraPathConfig = if ($ghidraPathResolved) { Convert-ToConfigPath -PathValue $ghidraPathResolved } else { "" }
|
|
184
|
+
|
|
185
|
+
Write-Host "Project root: $projectRootConfig" -ForegroundColor Gray
|
|
186
|
+
Write-Host "Node path: $nodeExecutableConfig" -ForegroundColor Gray
|
|
187
|
+
Write-Host "Server entry: $distEntryConfig" -ForegroundColor Gray
|
|
188
|
+
if ($ghidraPathConfig -and $ghidraPathExists) {
|
|
189
|
+
Write-Host "Ghidra path: $ghidraPathConfig" -ForegroundColor Gray
|
|
190
|
+
} elseif ($ghidraPathConfig) {
|
|
191
|
+
Write-Host "Warning: the Ghidra path does not exist. The script will still write it into the config. Pass -GhidraPath to override it." -ForegroundColor Yellow
|
|
192
|
+
} else {
|
|
193
|
+
Write-Host "No Ghidra path supplied. The config will be written without GHIDRA_PATH." -ForegroundColor Yellow
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (-not $WorkspaceConfigPath) {
|
|
197
|
+
$WorkspaceConfigPath = Join-Path -Path $projectRootFull -ChildPath ".vscode/mcp.json"
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (-not $CopilotCliConfigPath) {
|
|
201
|
+
$copilotConfigRoot = if ($env:XDG_CONFIG_HOME) {
|
|
202
|
+
Join-Path -Path $env:XDG_CONFIG_HOME -ChildPath "copilot"
|
|
203
|
+
} else {
|
|
204
|
+
Join-Path -Path $HOME -ChildPath ".copilot"
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
$CopilotCliConfigPath = Join-Path -Path $copilotConfigRoot -ChildPath "mcp-config.json"
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
$workspaceServerConfig = [ordered]@{
|
|
211
|
+
type = "stdio"
|
|
212
|
+
command = $nodeExecutableConfig
|
|
213
|
+
args = @($distEntryConfig)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if ($ghidraPathConfig) {
|
|
217
|
+
$workspaceServerConfig.env = [ordered]@{
|
|
218
|
+
GHIDRA_PATH = $ghidraPathConfig
|
|
219
|
+
GHIDRA_INSTALL_DIR = $ghidraPathConfig
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
$copilotCliServerConfig = [ordered]@{
|
|
224
|
+
type = "local"
|
|
225
|
+
command = $nodeExecutableConfig
|
|
226
|
+
args = @($distEntryConfig)
|
|
227
|
+
cwd = $projectRootConfig
|
|
228
|
+
tools = @("*")
|
|
229
|
+
timeout = 300000
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if ($ghidraPathConfig) {
|
|
233
|
+
$copilotCliServerConfig.env = [ordered]@{
|
|
234
|
+
GHIDRA_PATH = $ghidraPathConfig
|
|
235
|
+
GHIDRA_INSTALL_DIR = $ghidraPathConfig
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (-not $SkipWorkspaceConfig) {
|
|
240
|
+
Write-Step "Step 2: Write workspace GitHub Copilot / VS Code MCP config"
|
|
241
|
+
$workspaceBackup = Backup-FileIfNeeded -PathValue $WorkspaceConfigPath
|
|
242
|
+
$workspaceConfig = Load-JsonConfig -PathValue $WorkspaceConfigPath -RootProperty "servers"
|
|
243
|
+
Set-NamedProperty -Object $workspaceConfig.servers -Name $ServerName -Value $workspaceServerConfig
|
|
244
|
+
Save-JsonConfig -PathValue $WorkspaceConfigPath -Config $workspaceConfig
|
|
245
|
+
|
|
246
|
+
Write-Host "Workspace config written: $WorkspaceConfigPath" -ForegroundColor Green
|
|
247
|
+
if ($workspaceBackup) {
|
|
248
|
+
Write-Host "Backup file: $workspaceBackup" -ForegroundColor Gray
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (-not $SkipCopilotCliConfig) {
|
|
253
|
+
Write-Step "Step 3: Write GitHub Copilot CLI MCP config"
|
|
254
|
+
$cliBackup = Backup-FileIfNeeded -PathValue $CopilotCliConfigPath
|
|
255
|
+
$cliConfig = Load-JsonConfig -PathValue $CopilotCliConfigPath -RootProperty "mcpServers"
|
|
256
|
+
Set-NamedProperty -Object $cliConfig.mcpServers -Name $ServerName -Value $copilotCliServerConfig
|
|
257
|
+
Save-JsonConfig -PathValue $CopilotCliConfigPath -Config $cliConfig
|
|
258
|
+
|
|
259
|
+
Write-Host "CLI config written: $CopilotCliConfigPath" -ForegroundColor Green
|
|
260
|
+
if ($cliBackup) {
|
|
261
|
+
Write-Host "Backup file: $cliBackup" -ForegroundColor Gray
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if ($InstallVsCodeUserProfile) {
|
|
266
|
+
Write-Step "Step 4: Try to install into the VS Code user-level MCP config"
|
|
267
|
+
$codeCommand = Get-Command code -ErrorAction SilentlyContinue
|
|
268
|
+
if ($null -eq $codeCommand) {
|
|
269
|
+
Write-Host "Warning: the 'code' command was not found. Skipping user-level VS Code installation." -ForegroundColor Yellow
|
|
270
|
+
} else {
|
|
271
|
+
$userProfilePayload = [pscustomobject]@{
|
|
272
|
+
name = $ServerName
|
|
273
|
+
type = "stdio"
|
|
274
|
+
command = $nodeExecutableConfig
|
|
275
|
+
args = @($distEntryConfig)
|
|
276
|
+
} | ConvertTo-Json -Depth 10 -Compress
|
|
277
|
+
|
|
278
|
+
if ($ghidraPathConfig) {
|
|
279
|
+
$userProfilePayload = [pscustomobject]@{
|
|
280
|
+
name = $ServerName
|
|
281
|
+
type = "stdio"
|
|
282
|
+
command = $nodeExecutableConfig
|
|
283
|
+
args = @($distEntryConfig)
|
|
284
|
+
env = [pscustomobject]@{
|
|
285
|
+
GHIDRA_PATH = $ghidraPathConfig
|
|
286
|
+
GHIDRA_INSTALL_DIR = $ghidraPathConfig
|
|
287
|
+
}
|
|
288
|
+
} | ConvertTo-Json -Depth 10 -Compress
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
& $codeCommand.Source --add-mcp $userProfilePayload
|
|
292
|
+
Write-Host "VS Code --add-mcp was invoked successfully." -ForegroundColor Green
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
Write-Step "Step 5: What to do next"
|
|
297
|
+
Write-Host "1. VS Code / GitHub Copilot Chat:" -ForegroundColor Cyan
|
|
298
|
+
Write-Host " Open this workspace. Copilot will read .vscode/mcp.json. Trust the MCP server when VS Code prompts you." -ForegroundColor White
|
|
299
|
+
Write-Host "2. GitHub Copilot CLI:" -ForegroundColor Cyan
|
|
300
|
+
Write-Host " Start 'copilot' and run '/mcp list' or '/mcp show $ServerName'." -ForegroundColor White
|
|
301
|
+
Write-Host "3. Use -SkipWorkspaceConfig or -SkipCopilotCliConfig if you only want to update one target." -ForegroundColor White
|
|
302
|
+
Write-Host ""
|
|
303
|
+
Write-Host "Installation complete." -ForegroundColor Green
|
package/package.json
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "windows-exe-decompiler-mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for Windows binary reverse engineering, PE triage, Ghidra-assisted analysis, and reconstruction workflows.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"windows-exe-decompiler-mcp-server": "./bin/windows-exe-decompiler-mcp-server.js"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"bin/",
|
|
16
|
+
"dist/**/*.js",
|
|
17
|
+
"dist/**/*.d.ts",
|
|
18
|
+
"workers/static_worker.py",
|
|
19
|
+
"workers/speakeasy_compat.py",
|
|
20
|
+
"workers/requirements.txt",
|
|
21
|
+
"workers/requirements-dynamic.txt",
|
|
22
|
+
"workers/yara_rules/*.yar",
|
|
23
|
+
"ghidra_scripts/*.java",
|
|
24
|
+
"ghidra_scripts/*.py",
|
|
25
|
+
"ghidra_scripts/README.md",
|
|
26
|
+
"helpers/DotNetMetadataProbe/DotNetMetadataProbe.csproj",
|
|
27
|
+
"helpers/DotNetMetadataProbe/Program.cs",
|
|
28
|
+
"requirements.txt",
|
|
29
|
+
"install-to-codex.ps1",
|
|
30
|
+
"install-to-copilot.ps1",
|
|
31
|
+
"CODEX_INSTALLATION.md",
|
|
32
|
+
"COPILOT_INSTALLATION.md"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc",
|
|
36
|
+
"clean": "node -e \"const fs=require('fs'); for (const p of ['dist']) { fs.rmSync(p,{recursive:true,force:true}); }\"",
|
|
37
|
+
"dev": "tsx watch src/index.ts",
|
|
38
|
+
"start": "node dist/index.js",
|
|
39
|
+
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest",
|
|
40
|
+
"test:watch": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --watch",
|
|
41
|
+
"lint": "eslint src --ext .ts",
|
|
42
|
+
"lint:fix": "eslint src --ext .ts --fix",
|
|
43
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
44
|
+
"format:check": "prettier --check \"src/**/*.ts\"",
|
|
45
|
+
"prepack": "npm run build",
|
|
46
|
+
"pack:dry-run": "npm pack --dry-run",
|
|
47
|
+
"release:check": "npm run build && npm pack --dry-run"
|
|
48
|
+
},
|
|
49
|
+
"keywords": [
|
|
50
|
+
"mcp",
|
|
51
|
+
"reverse-engineering",
|
|
52
|
+
"decompiler",
|
|
53
|
+
"pe-analysis",
|
|
54
|
+
"malware-analysis",
|
|
55
|
+
"ghidra",
|
|
56
|
+
"windows",
|
|
57
|
+
"copilot",
|
|
58
|
+
"codex"
|
|
59
|
+
],
|
|
60
|
+
"author": "",
|
|
61
|
+
"license": "MIT",
|
|
62
|
+
"repository": {
|
|
63
|
+
"type": "git",
|
|
64
|
+
"url": "git+https://github.com/Last-emo-boy/windows-exe-decompiler-mcp-server.git"
|
|
65
|
+
},
|
|
66
|
+
"homepage": "https://github.com/Last-emo-boy/windows-exe-decompiler-mcp-server",
|
|
67
|
+
"bugs": {
|
|
68
|
+
"url": "https://github.com/Last-emo-boy/windows-exe-decompiler-mcp-server/issues"
|
|
69
|
+
},
|
|
70
|
+
"publishConfig": {
|
|
71
|
+
"access": "public"
|
|
72
|
+
},
|
|
73
|
+
"dependencies": {
|
|
74
|
+
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
75
|
+
"better-sqlite3": "^12.6.2",
|
|
76
|
+
"pino": "^10.3.1",
|
|
77
|
+
"pino-pretty": "^13.1.3",
|
|
78
|
+
"uuid": "^13.0.0",
|
|
79
|
+
"zod": "^3.25.76"
|
|
80
|
+
},
|
|
81
|
+
"devDependencies": {
|
|
82
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
83
|
+
"@types/jest": "^30.0.0",
|
|
84
|
+
"@types/node": "^25.3.5",
|
|
85
|
+
"@typescript-eslint/eslint-plugin": "^8.56.1",
|
|
86
|
+
"@typescript-eslint/parser": "^8.56.1",
|
|
87
|
+
"cross-env": "^10.1.0",
|
|
88
|
+
"eslint": "^10.0.3",
|
|
89
|
+
"eslint-config-prettier": "^10.1.8",
|
|
90
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
91
|
+
"fast-check": "^4.6.0",
|
|
92
|
+
"jest": "^30.2.0",
|
|
93
|
+
"prettier": "^3.8.1",
|
|
94
|
+
"ts-jest": "^29.4.6",
|
|
95
|
+
"tsx": "^4.21.0",
|
|
96
|
+
"typescript": "^5.9.3"
|
|
97
|
+
},
|
|
98
|
+
"engines": {
|
|
99
|
+
"node": ">=18.0.0"
|
|
100
|
+
}
|
|
101
|
+
}
|
package/requirements.txt
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Root Python dependency baseline for the reverse-engineering workers.
|
|
2
|
+
# Latest versions verified on PyPI 2026-03-10.
|
|
3
|
+
# For optional dynamic-analysis tooling, install workers/requirements-dynamic.txt as an extra step.
|
|
4
|
+
|
|
5
|
+
pefile==2024.8.26
|
|
6
|
+
lief==0.17.5
|
|
7
|
+
yara-python==4.5.4
|
|
8
|
+
flare-floss==3.1.1
|
|
9
|
+
dnfile==0.18.0
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Optional dynamic-analysis dependencies (install only in isolated lab environments)
|
|
2
|
+
# These are intentionally separated from the static baseline requirements.
|
|
3
|
+
# Latest verified on PyPI 2026-03-10.
|
|
4
|
+
# Note: the PyPI package named `speakeasy` is an unrelated metrics server.
|
|
5
|
+
# Use `speakeasy-emulator`, which provides the `speakeasy` malware-emulation module.
|
|
6
|
+
# Unicorn still imports `pkg_resources`, so keep setuptools below 81 for now.
|
|
7
|
+
|
|
8
|
+
speakeasy-emulator==1.5.11
|
|
9
|
+
setuptools<81
|
|
10
|
+
frida==17.8.0
|
|
11
|
+
psutil==7.2.2
|