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,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* yara.scan tool implementation
|
|
3
|
+
* Scans PE files using YARA rules to identify malware families and packers
|
|
4
|
+
* Requirements: 5.1, 5.2, 5.3
|
|
5
|
+
*/
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { spawn } from 'child_process';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
10
|
+
import { generateCacheKey } from '../cache-manager.js';
|
|
11
|
+
import { resolvePackagePath } from '../runtime-paths.js';
|
|
12
|
+
import { lookupCachedResult, formatCacheWarning } from './cache-observability.js';
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Constants
|
|
15
|
+
// ============================================================================
|
|
16
|
+
const TOOL_NAME = 'yara.scan';
|
|
17
|
+
const TOOL_VERSION = '1.0.0';
|
|
18
|
+
const CACHE_TTL_MS = 30 * 24 * 60 * 60 * 1000; // 30 days
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// Input/Output Schemas
|
|
21
|
+
// ============================================================================
|
|
22
|
+
/**
|
|
23
|
+
* Input schema for yara.scan tool
|
|
24
|
+
* Requirements: 5.1, 5.2
|
|
25
|
+
*/
|
|
26
|
+
export const YaraScanInputSchema = z.object({
|
|
27
|
+
sample_id: z.string().describe('Sample ID (format: sha256:<hex>)'),
|
|
28
|
+
rule_set: z.string().describe('Rule set name (e.g., malware_families, packers)'),
|
|
29
|
+
timeout_ms: z.number().int().min(1000).optional().default(30000).describe('Timeout in milliseconds'),
|
|
30
|
+
rule_tier: z
|
|
31
|
+
.enum(['production', 'experimental', 'test', 'all'])
|
|
32
|
+
.optional()
|
|
33
|
+
.default('production')
|
|
34
|
+
.describe('Rule quality tier. Default production excludes weak test rules.'),
|
|
35
|
+
force_refresh: z
|
|
36
|
+
.boolean()
|
|
37
|
+
.optional()
|
|
38
|
+
.default(false)
|
|
39
|
+
.describe('Bypass cache lookup and recompute from source sample'),
|
|
40
|
+
});
|
|
41
|
+
/**
|
|
42
|
+
* Output schema for yara.scan tool
|
|
43
|
+
* Requirements: 5.2, 5.3
|
|
44
|
+
*/
|
|
45
|
+
export const YaraScanOutputSchema = z.object({
|
|
46
|
+
ok: z.boolean(),
|
|
47
|
+
data: z.object({
|
|
48
|
+
matches: z.array(z.object({
|
|
49
|
+
rule: z.string(),
|
|
50
|
+
tags: z.array(z.string()),
|
|
51
|
+
meta: z.record(z.any()),
|
|
52
|
+
strings: z.array(z.object({
|
|
53
|
+
identifier: z.string(),
|
|
54
|
+
offset: z.number(),
|
|
55
|
+
matched_data: z.string(),
|
|
56
|
+
location: z.object({
|
|
57
|
+
section: z.string().nullable().optional(),
|
|
58
|
+
offset_in_section: z.number().nullable().optional(),
|
|
59
|
+
rva: z.number().nullable().optional(),
|
|
60
|
+
distance_to_entrypoint: z.number().nullable().optional(),
|
|
61
|
+
function_hint: z.object({
|
|
62
|
+
name: z.string(),
|
|
63
|
+
address: z.string(),
|
|
64
|
+
proximity: z.string(),
|
|
65
|
+
}).nullable().optional(),
|
|
66
|
+
}).optional(),
|
|
67
|
+
})),
|
|
68
|
+
confidence: z.object({
|
|
69
|
+
level: z.enum(['low', 'medium', 'high']),
|
|
70
|
+
score: z.number(),
|
|
71
|
+
reason: z.string(),
|
|
72
|
+
}).optional(),
|
|
73
|
+
evidence: z.object({
|
|
74
|
+
import_dll_hits: z.array(z.string()),
|
|
75
|
+
import_api_hits: z.array(z.string()),
|
|
76
|
+
section_hits: z.array(z.string()).optional(),
|
|
77
|
+
near_entrypoint_hits: z.number().optional(),
|
|
78
|
+
string_only: z.boolean(),
|
|
79
|
+
}).optional(),
|
|
80
|
+
inference: z.object({
|
|
81
|
+
classification: z.string(),
|
|
82
|
+
summary: z.string(),
|
|
83
|
+
}).optional(),
|
|
84
|
+
})),
|
|
85
|
+
ruleset_version: z.string(),
|
|
86
|
+
timed_out: z.boolean(),
|
|
87
|
+
rule_set: z.string(),
|
|
88
|
+
rule_tier: z.string().optional(),
|
|
89
|
+
rule_files: z.array(z.string()).optional(),
|
|
90
|
+
confidence_summary: z.object({
|
|
91
|
+
high: z.number(),
|
|
92
|
+
medium: z.number(),
|
|
93
|
+
low: z.number(),
|
|
94
|
+
}).optional(),
|
|
95
|
+
import_evidence: z.object({
|
|
96
|
+
dll_count: z.number(),
|
|
97
|
+
api_count: z.number(),
|
|
98
|
+
}).optional(),
|
|
99
|
+
offset_mapping: z.object({
|
|
100
|
+
parser: z.string().nullable().optional(),
|
|
101
|
+
sections_count: z.number().optional(),
|
|
102
|
+
entry_point: z.record(z.any()).optional(),
|
|
103
|
+
}).optional(),
|
|
104
|
+
quality_notes: z.array(z.string()).optional(),
|
|
105
|
+
}).optional(),
|
|
106
|
+
warnings: z.array(z.string()).optional(),
|
|
107
|
+
errors: z.array(z.string()).optional(),
|
|
108
|
+
artifacts: z.array(z.any()).optional(),
|
|
109
|
+
metrics: z.object({
|
|
110
|
+
elapsed_ms: z.number(),
|
|
111
|
+
tool: z.string(),
|
|
112
|
+
}).optional(),
|
|
113
|
+
});
|
|
114
|
+
// ============================================================================
|
|
115
|
+
// Tool Definition
|
|
116
|
+
// ============================================================================
|
|
117
|
+
/**
|
|
118
|
+
* Tool definition for yara.scan
|
|
119
|
+
*/
|
|
120
|
+
export const yaraScanToolDefinition = {
|
|
121
|
+
name: TOOL_NAME,
|
|
122
|
+
description: '使用 YARA 规则扫描样本,识别已知的恶意软件家族和加壳器',
|
|
123
|
+
inputSchema: YaraScanInputSchema,
|
|
124
|
+
outputSchema: YaraScanOutputSchema,
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Spawn Python Static Worker and communicate via stdin/stdout JSON protocol
|
|
128
|
+
*
|
|
129
|
+
* Requirements: Worker communication
|
|
130
|
+
*
|
|
131
|
+
* @param request - Worker request object
|
|
132
|
+
* @returns Worker response object
|
|
133
|
+
*/
|
|
134
|
+
async function callStaticWorker(request) {
|
|
135
|
+
return new Promise((resolve, reject) => {
|
|
136
|
+
// Get Python worker path
|
|
137
|
+
const workerPath = resolvePackagePath('workers', 'static_worker.py');
|
|
138
|
+
// Spawn Python process
|
|
139
|
+
const pythonCommand = process.platform === 'win32' ? 'python' : 'python3';
|
|
140
|
+
const pythonProcess = spawn(pythonCommand, [workerPath], {
|
|
141
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
142
|
+
});
|
|
143
|
+
let stdout = '';
|
|
144
|
+
let stderr = '';
|
|
145
|
+
// Collect stdout
|
|
146
|
+
pythonProcess.stdout.on('data', (data) => {
|
|
147
|
+
stdout += data.toString();
|
|
148
|
+
});
|
|
149
|
+
// Collect stderr
|
|
150
|
+
pythonProcess.stderr.on('data', (data) => {
|
|
151
|
+
stderr += data.toString();
|
|
152
|
+
});
|
|
153
|
+
// Handle process exit
|
|
154
|
+
pythonProcess.on('close', (code) => {
|
|
155
|
+
if (code !== 0) {
|
|
156
|
+
reject(new Error(`Python worker exited with code ${code}. stderr: ${stderr}`));
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
// Parse response from stdout
|
|
160
|
+
try {
|
|
161
|
+
const lines = stdout.trim().split('\n');
|
|
162
|
+
const lastLine = lines[lines.length - 1];
|
|
163
|
+
const response = JSON.parse(lastLine);
|
|
164
|
+
resolve(response);
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
reject(new Error(`Failed to parse worker response: ${error.message}. stdout: ${stdout}`));
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
// Handle process error
|
|
171
|
+
pythonProcess.on('error', (error) => {
|
|
172
|
+
reject(new Error(`Failed to spawn Python worker: ${error.message}`));
|
|
173
|
+
});
|
|
174
|
+
// Send request to worker via stdin
|
|
175
|
+
try {
|
|
176
|
+
pythonProcess.stdin.write(JSON.stringify(request) + '\n');
|
|
177
|
+
pythonProcess.stdin.end();
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
reject(new Error(`Failed to write to worker stdin: ${error.message}`));
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
// ============================================================================
|
|
185
|
+
// Tool Handler
|
|
186
|
+
// ============================================================================
|
|
187
|
+
/**
|
|
188
|
+
* Create yara.scan tool handler
|
|
189
|
+
* Requirements: 5.1, 5.2, 5.3, 5.5
|
|
190
|
+
*/
|
|
191
|
+
export function createYaraScanHandler(workspaceManager, database, cacheManager) {
|
|
192
|
+
return async (args) => {
|
|
193
|
+
const input = args;
|
|
194
|
+
const startTime = Date.now();
|
|
195
|
+
try {
|
|
196
|
+
// 1. Validate sample exists
|
|
197
|
+
const sample = database.findSample(input.sample_id);
|
|
198
|
+
if (!sample) {
|
|
199
|
+
return {
|
|
200
|
+
ok: false,
|
|
201
|
+
errors: [`Sample not found: ${input.sample_id}`],
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
// 2. Generate cache key
|
|
205
|
+
// Requirement: 5.5 - Cache key includes ruleset version
|
|
206
|
+
const cacheKey = generateCacheKey({
|
|
207
|
+
sampleSha256: sample.sha256,
|
|
208
|
+
toolName: TOOL_NAME,
|
|
209
|
+
toolVersion: TOOL_VERSION,
|
|
210
|
+
args: {
|
|
211
|
+
rule_set: input.rule_set,
|
|
212
|
+
timeout_ms: input.timeout_ms,
|
|
213
|
+
rule_tier: input.rule_tier,
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
// 3. Check cache
|
|
217
|
+
if (!input.force_refresh) {
|
|
218
|
+
const cachedLookup = await lookupCachedResult(cacheManager, cacheKey);
|
|
219
|
+
if (cachedLookup) {
|
|
220
|
+
return {
|
|
221
|
+
ok: true,
|
|
222
|
+
data: cachedLookup.data,
|
|
223
|
+
warnings: ['Result from cache', formatCacheWarning(cachedLookup.metadata)],
|
|
224
|
+
metrics: {
|
|
225
|
+
elapsed_ms: Date.now() - startTime,
|
|
226
|
+
tool: TOOL_NAME,
|
|
227
|
+
cached: true,
|
|
228
|
+
cache_key: cachedLookup.metadata.key,
|
|
229
|
+
cache_tier: cachedLookup.metadata.tier,
|
|
230
|
+
cache_created_at: cachedLookup.metadata.createdAt,
|
|
231
|
+
cache_expires_at: cachedLookup.metadata.expiresAt,
|
|
232
|
+
cache_hit_at: cachedLookup.metadata.fetchedAt,
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// 4. Get sample path from workspace
|
|
238
|
+
const workspace = await workspaceManager.getWorkspace(input.sample_id);
|
|
239
|
+
// Find the sample file in the original directory
|
|
240
|
+
const fs = await import('fs/promises');
|
|
241
|
+
const files = await fs.readdir(workspace.original);
|
|
242
|
+
if (files.length === 0) {
|
|
243
|
+
return {
|
|
244
|
+
ok: false,
|
|
245
|
+
errors: ['Sample file not found in workspace'],
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
const samplePath = path.join(workspace.original, files[0]);
|
|
249
|
+
// 5. Prepare worker request
|
|
250
|
+
const workerRequest = {
|
|
251
|
+
job_id: uuidv4(),
|
|
252
|
+
tool: TOOL_NAME,
|
|
253
|
+
sample: {
|
|
254
|
+
sample_id: input.sample_id,
|
|
255
|
+
path: samplePath,
|
|
256
|
+
},
|
|
257
|
+
args: {
|
|
258
|
+
rule_set: input.rule_set,
|
|
259
|
+
timeout_ms: input.timeout_ms,
|
|
260
|
+
rule_tier: input.rule_tier,
|
|
261
|
+
},
|
|
262
|
+
context: {
|
|
263
|
+
request_time_utc: new Date().toISOString(),
|
|
264
|
+
policy: {
|
|
265
|
+
allow_dynamic: false,
|
|
266
|
+
allow_network: false,
|
|
267
|
+
},
|
|
268
|
+
versions: {
|
|
269
|
+
tool_version: TOOL_VERSION,
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
};
|
|
273
|
+
// 6. Call Static Worker
|
|
274
|
+
// Requirements: 5.1, 5.2, 5.3
|
|
275
|
+
const workerResponse = await callStaticWorker(workerRequest);
|
|
276
|
+
if (!workerResponse.ok) {
|
|
277
|
+
return {
|
|
278
|
+
ok: false,
|
|
279
|
+
errors: workerResponse.errors,
|
|
280
|
+
warnings: workerResponse.warnings,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
// 7. Cache result
|
|
284
|
+
// Requirement: 5.5 - Cache with ruleset version for invalidation
|
|
285
|
+
await cacheManager.setCachedResult(cacheKey, workerResponse.data, CACHE_TTL_MS);
|
|
286
|
+
// 8. Return result
|
|
287
|
+
return {
|
|
288
|
+
ok: true,
|
|
289
|
+
data: workerResponse.data,
|
|
290
|
+
warnings: input.force_refresh
|
|
291
|
+
? ['force_refresh=true; bypassed cache lookup', ...(workerResponse.warnings || [])]
|
|
292
|
+
: workerResponse.warnings,
|
|
293
|
+
errors: workerResponse.errors,
|
|
294
|
+
artifacts: workerResponse.artifacts,
|
|
295
|
+
metrics: {
|
|
296
|
+
...workerResponse.metrics,
|
|
297
|
+
elapsed_ms: Date.now() - startTime,
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
return {
|
|
303
|
+
ok: false,
|
|
304
|
+
errors: [error.message],
|
|
305
|
+
metrics: {
|
|
306
|
+
elapsed_ms: Date.now() - startTime,
|
|
307
|
+
tool: TOOL_NAME,
|
|
308
|
+
},
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
//# sourceMappingURL=yara-scan.js.map
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the MCP Server
|
|
3
|
+
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
/**
|
|
6
|
+
* JSON Schema type for tool input/output validation
|
|
7
|
+
*/
|
|
8
|
+
export type JSONSchema = z.ZodTypeAny;
|
|
9
|
+
/**
|
|
10
|
+
* Tool definition following MCP protocol
|
|
11
|
+
*/
|
|
12
|
+
export interface ToolDefinition {
|
|
13
|
+
name: string;
|
|
14
|
+
description: string;
|
|
15
|
+
inputSchema: JSONSchema;
|
|
16
|
+
outputSchema?: JSONSchema;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Prompt argument definition following MCP protocol
|
|
20
|
+
*/
|
|
21
|
+
export interface PromptArgumentDefinition {
|
|
22
|
+
name: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
required?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Prompt definition following MCP protocol
|
|
28
|
+
*/
|
|
29
|
+
export interface PromptDefinition {
|
|
30
|
+
name: string;
|
|
31
|
+
title?: string;
|
|
32
|
+
description?: string;
|
|
33
|
+
arguments?: PromptArgumentDefinition[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Prompt arguments (generic string map)
|
|
37
|
+
*/
|
|
38
|
+
export type PromptArgs = Record<string, string>;
|
|
39
|
+
/**
|
|
40
|
+
* Prompt message content
|
|
41
|
+
*/
|
|
42
|
+
export interface PromptMessageContent {
|
|
43
|
+
type: 'text';
|
|
44
|
+
text: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Prompt message item
|
|
48
|
+
*/
|
|
49
|
+
export interface PromptMessage {
|
|
50
|
+
role: 'user' | 'assistant';
|
|
51
|
+
content: PromptMessageContent;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Prompt handler result
|
|
55
|
+
*/
|
|
56
|
+
export interface PromptResult {
|
|
57
|
+
description?: string;
|
|
58
|
+
messages: PromptMessage[];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Content types for MCP responses
|
|
62
|
+
*/
|
|
63
|
+
export type ContentType = 'text' | 'resource' | 'structuredContent';
|
|
64
|
+
/**
|
|
65
|
+
* Resource content structure
|
|
66
|
+
*/
|
|
67
|
+
export interface ResourceContent {
|
|
68
|
+
uri: string;
|
|
69
|
+
mimeType?: string;
|
|
70
|
+
text?: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Structured content with schema
|
|
74
|
+
*/
|
|
75
|
+
export interface StructuredContent {
|
|
76
|
+
type: string;
|
|
77
|
+
data: unknown;
|
|
78
|
+
schema?: JSONSchema;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Content item in tool result
|
|
82
|
+
*/
|
|
83
|
+
export interface Content {
|
|
84
|
+
type: ContentType;
|
|
85
|
+
text?: string;
|
|
86
|
+
resource?: ResourceContent;
|
|
87
|
+
structuredContent?: StructuredContent;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Tool execution result
|
|
91
|
+
*/
|
|
92
|
+
export interface ToolResult {
|
|
93
|
+
content: Content[];
|
|
94
|
+
isError?: boolean;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Tool arguments (generic)
|
|
98
|
+
*/
|
|
99
|
+
export type ToolArgs = Record<string, unknown>;
|
|
100
|
+
/**
|
|
101
|
+
* Tool handler function type
|
|
102
|
+
*/
|
|
103
|
+
export type ToolHandler = (args: unknown) => Promise<ToolResult>;
|
|
104
|
+
/**
|
|
105
|
+
* Worker result from analysis workers
|
|
106
|
+
*/
|
|
107
|
+
export interface WorkerResult {
|
|
108
|
+
ok: boolean;
|
|
109
|
+
data?: unknown;
|
|
110
|
+
errors?: string[];
|
|
111
|
+
warnings?: string[];
|
|
112
|
+
artifacts?: ArtifactRef[];
|
|
113
|
+
metrics?: Record<string, unknown>;
|
|
114
|
+
}
|
|
115
|
+
export interface SampleInfo {
|
|
116
|
+
sampleId: string;
|
|
117
|
+
sha256: string;
|
|
118
|
+
md5: string;
|
|
119
|
+
size: number;
|
|
120
|
+
path: string;
|
|
121
|
+
}
|
|
122
|
+
export interface WorkspacePath {
|
|
123
|
+
root: string;
|
|
124
|
+
original: string;
|
|
125
|
+
cache: string;
|
|
126
|
+
ghidra: string;
|
|
127
|
+
reports: string;
|
|
128
|
+
}
|
|
129
|
+
export interface ArtifactRef {
|
|
130
|
+
id: string;
|
|
131
|
+
type: string;
|
|
132
|
+
path: string;
|
|
133
|
+
sha256: string;
|
|
134
|
+
mime?: string;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Parameters for cache key generation
|
|
138
|
+
* Requirements: 20.1, 20.2
|
|
139
|
+
*/
|
|
140
|
+
export interface CacheKeyParams {
|
|
141
|
+
sampleSha256: string;
|
|
142
|
+
toolName: string;
|
|
143
|
+
toolVersion: string;
|
|
144
|
+
args: Record<string, unknown>;
|
|
145
|
+
rulesetVersion?: string;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Cached result structure
|
|
149
|
+
* Requirements: 20.3, 20.4, 20.5
|
|
150
|
+
*/
|
|
151
|
+
export interface CachedResult {
|
|
152
|
+
key: string;
|
|
153
|
+
data: unknown;
|
|
154
|
+
createdAt: string;
|
|
155
|
+
expiresAt?: string;
|
|
156
|
+
sampleSha256?: string;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Error categories for classification
|
|
160
|
+
* Requirements: 22.1, 22.2, 22.3
|
|
161
|
+
*/
|
|
162
|
+
export declare enum ErrorCategory {
|
|
163
|
+
TIMEOUT = "E_TIMEOUT",
|
|
164
|
+
RESOURCE_EXHAUSTED = "E_RESOURCE_EXHAUSTED",
|
|
165
|
+
WORKER_UNAVAILABLE = "E_WORKER_UNAVAILABLE",
|
|
166
|
+
INVALID_INPUT = "E_INVALID_INPUT",
|
|
167
|
+
PARSE_ERROR = "E_PARSE_PE",
|
|
168
|
+
POLICY_DENIED = "E_POLICY_DENY",
|
|
169
|
+
NOT_FOUND = "E_NOT_FOUND",
|
|
170
|
+
PARTIAL_SUCCESS = "E_PARTIAL_SUCCESS",
|
|
171
|
+
UNKNOWN = "E_UNKNOWN"
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Context for error handling
|
|
175
|
+
* Requirements: 22.4
|
|
176
|
+
*/
|
|
177
|
+
export interface ErrorContext {
|
|
178
|
+
tool: string;
|
|
179
|
+
sampleId: string;
|
|
180
|
+
attempt: number;
|
|
181
|
+
maxRetries: number;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Result of error handling
|
|
185
|
+
* Requirements: 22.4, 22.5, 22.6
|
|
186
|
+
*/
|
|
187
|
+
export interface ErrorResult {
|
|
188
|
+
shouldRetry: boolean;
|
|
189
|
+
backoffMs?: number;
|
|
190
|
+
fallbackAction?: string;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Job priority levels (higher number = higher priority)
|
|
194
|
+
* Requirements: 21.2
|
|
195
|
+
*/
|
|
196
|
+
export declare enum JobPriority {
|
|
197
|
+
LOW = 1,
|
|
198
|
+
NORMAL = 5,
|
|
199
|
+
HIGH = 10,
|
|
200
|
+
CRITICAL = 20
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Job execution status
|
|
204
|
+
* Requirements: 21.1, 21.2
|
|
205
|
+
*/
|
|
206
|
+
export type JobStatusType = 'queued' | 'running' | 'completed' | 'failed' | 'cancelled';
|
|
207
|
+
/**
|
|
208
|
+
* Retry policy for failed jobs
|
|
209
|
+
* Requirements: 21.5
|
|
210
|
+
*/
|
|
211
|
+
export interface RetryPolicy {
|
|
212
|
+
maxRetries: number;
|
|
213
|
+
backoffMs: number;
|
|
214
|
+
retryableErrors: string[];
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Job definition
|
|
218
|
+
* Requirements: 21.1
|
|
219
|
+
*/
|
|
220
|
+
export interface Job {
|
|
221
|
+
id: string;
|
|
222
|
+
type: 'static' | 'decompile' | 'dotnet' | 'sandbox';
|
|
223
|
+
tool: string;
|
|
224
|
+
sampleId: string;
|
|
225
|
+
args: Record<string, unknown>;
|
|
226
|
+
priority: number;
|
|
227
|
+
timeout: number;
|
|
228
|
+
retryPolicy: RetryPolicy;
|
|
229
|
+
createdAt: string;
|
|
230
|
+
attempts: number;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Job status information
|
|
234
|
+
* Requirements: 21.1, 21.2
|
|
235
|
+
*/
|
|
236
|
+
export interface JobStatus {
|
|
237
|
+
id: string;
|
|
238
|
+
status: JobStatusType;
|
|
239
|
+
progress?: number;
|
|
240
|
+
startedAt?: string;
|
|
241
|
+
finishedAt?: string;
|
|
242
|
+
error?: string;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Job execution metrics
|
|
246
|
+
* Requirements: 30.1, 30.2
|
|
247
|
+
*/
|
|
248
|
+
export interface JobMetrics {
|
|
249
|
+
elapsedMs: number;
|
|
250
|
+
peakRssMb: number;
|
|
251
|
+
cpuPercent?: number;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Job execution result
|
|
255
|
+
* Requirements: 21.4
|
|
256
|
+
*/
|
|
257
|
+
export interface JobResult {
|
|
258
|
+
jobId: string;
|
|
259
|
+
ok: boolean;
|
|
260
|
+
data?: unknown;
|
|
261
|
+
errors: string[];
|
|
262
|
+
warnings: string[];
|
|
263
|
+
artifacts: ArtifactRef[];
|
|
264
|
+
metrics: JobMetrics;
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the MCP Server
|
|
3
|
+
*/
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// Error Handling Types
|
|
6
|
+
// ============================================================================
|
|
7
|
+
/**
|
|
8
|
+
* Error categories for classification
|
|
9
|
+
* Requirements: 22.1, 22.2, 22.3
|
|
10
|
+
*/
|
|
11
|
+
export var ErrorCategory;
|
|
12
|
+
(function (ErrorCategory) {
|
|
13
|
+
// Retryable errors
|
|
14
|
+
ErrorCategory["TIMEOUT"] = "E_TIMEOUT";
|
|
15
|
+
ErrorCategory["RESOURCE_EXHAUSTED"] = "E_RESOURCE_EXHAUSTED";
|
|
16
|
+
ErrorCategory["WORKER_UNAVAILABLE"] = "E_WORKER_UNAVAILABLE";
|
|
17
|
+
// Non-retryable errors
|
|
18
|
+
ErrorCategory["INVALID_INPUT"] = "E_INVALID_INPUT";
|
|
19
|
+
ErrorCategory["PARSE_ERROR"] = "E_PARSE_PE";
|
|
20
|
+
ErrorCategory["POLICY_DENIED"] = "E_POLICY_DENY";
|
|
21
|
+
ErrorCategory["NOT_FOUND"] = "E_NOT_FOUND";
|
|
22
|
+
// Partial failures
|
|
23
|
+
ErrorCategory["PARTIAL_SUCCESS"] = "E_PARTIAL_SUCCESS";
|
|
24
|
+
// Unknown errors
|
|
25
|
+
ErrorCategory["UNKNOWN"] = "E_UNKNOWN";
|
|
26
|
+
})(ErrorCategory || (ErrorCategory = {}));
|
|
27
|
+
// ============================================================================
|
|
28
|
+
// Job Queue Types
|
|
29
|
+
// ============================================================================
|
|
30
|
+
/**
|
|
31
|
+
* Job priority levels (higher number = higher priority)
|
|
32
|
+
* Requirements: 21.2
|
|
33
|
+
*/
|
|
34
|
+
export var JobPriority;
|
|
35
|
+
(function (JobPriority) {
|
|
36
|
+
JobPriority[JobPriority["LOW"] = 1] = "LOW";
|
|
37
|
+
JobPriority[JobPriority["NORMAL"] = 5] = "NORMAL";
|
|
38
|
+
JobPriority[JobPriority["HIGH"] = 10] = "HIGH";
|
|
39
|
+
JobPriority[JobPriority["CRITICAL"] = 20] = "CRITICAL";
|
|
40
|
+
})(JobPriority || (JobPriority = {}));
|
|
41
|
+
//# sourceMappingURL=types.js.map
|