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
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* Generates quick triage report with summary, confidence, IOCs, evidence, and recommendations.
|
|
4
4
|
*/
|
|
5
5
|
import { z } from 'zod';
|
|
6
|
+
import { BinaryRoleProfileDataSchema, createBinaryRoleProfileHandler, } from './binary-role-profile.js';
|
|
7
|
+
import { RustBinaryAnalyzeDataSchema, createRustBinaryAnalyzeHandler, } from './rust-binary-analyze.js';
|
|
6
8
|
import { createTriageWorkflowHandler } from '../workflows/triage.js';
|
|
7
9
|
import { loadDynamicTraceEvidence } from '../dynamic-trace.js';
|
|
8
10
|
import { loadSemanticFunctionExplanationIndex, } from '../semantic-name-suggestion-artifacts.js';
|
|
@@ -144,6 +146,8 @@ export const ReportSummarizeOutputSchema = z.object({
|
|
|
144
146
|
evidence: z.array(z.string()).describe('Evidence supporting the assessment'),
|
|
145
147
|
evidence_lineage: EvidenceLineageSchema.optional().describe('Explicit evidence layers separating static-only, simulated, memory/hybrid, and executed runtime evidence.'),
|
|
146
148
|
confidence_semantics: ReportAssessmentConfidenceSchema.optional().describe('Explains how to interpret confidence scores. These are heuristic evidence scores, not calibrated probabilities.'),
|
|
149
|
+
binary_profile: BinaryRoleProfileDataSchema.optional().describe('Optional binary role profile summarizing EXE/DLL/COM/service/plugin/export characteristics.'),
|
|
150
|
+
rust_profile: RustBinaryAnalyzeDataSchema.optional().describe('Optional Rust-oriented binary analysis summary, including crate hints, recovered symbols, and recovery priorities.'),
|
|
147
151
|
provenance: AnalysisProvenanceSchema.optional().describe('Explicit runtime/semantic artifact selection used to produce this report, including scope, session selector, and selected artifact IDs.'),
|
|
148
152
|
selection_diffs: AnalysisSelectionDiffSchema.optional().describe('Optional comparison between the current artifact selection and a caller-provided baseline runtime/semantic selection.'),
|
|
149
153
|
function_explanations: z
|
|
@@ -208,6 +212,176 @@ export const reportSummarizeToolDefinition = {
|
|
|
208
212
|
inputSchema: ReportSummarizeInputSchema,
|
|
209
213
|
outputSchema: ReportSummarizeOutputSchema,
|
|
210
214
|
};
|
|
215
|
+
function buildBinaryProfileSummary(binaryProfile) {
|
|
216
|
+
const lifecycleSurface = binaryProfile.lifecycle_surface || [];
|
|
217
|
+
const classFactorySurface = binaryProfile.com_profile.class_factory_surface || [];
|
|
218
|
+
const callbackSurface = binaryProfile.host_interaction_profile.callback_surface || [];
|
|
219
|
+
const parts = [
|
|
220
|
+
`Binary role profile suggests ${binaryProfile.binary_role} (confidence=${binaryProfile.role_confidence.toFixed(2)})`,
|
|
221
|
+
];
|
|
222
|
+
if (binaryProfile.export_surface.total_exports > 0) {
|
|
223
|
+
parts.push(`exports=${binaryProfile.export_surface.total_exports}`);
|
|
224
|
+
}
|
|
225
|
+
if (binaryProfile.indicators.com_server.likely) {
|
|
226
|
+
parts.push('COM-like surface detected');
|
|
227
|
+
}
|
|
228
|
+
if (binaryProfile.indicators.service_binary.likely) {
|
|
229
|
+
parts.push('service indicators detected');
|
|
230
|
+
}
|
|
231
|
+
if (binaryProfile.export_dispatch_profile.likely_dispatch_model !== 'none') {
|
|
232
|
+
parts.push(`dispatch_model=${binaryProfile.export_dispatch_profile.likely_dispatch_model}`);
|
|
233
|
+
}
|
|
234
|
+
if (binaryProfile.export_dispatch_profile.registration_exports.length > 0) {
|
|
235
|
+
parts.push(`registration_exports=${binaryProfile.export_dispatch_profile.registration_exports.slice(0, 2).join(', ')}`);
|
|
236
|
+
}
|
|
237
|
+
if (lifecycleSurface.length > 0) {
|
|
238
|
+
parts.push(`dll_lifecycle=${lifecycleSurface.slice(0, 2).join(', ')}`);
|
|
239
|
+
}
|
|
240
|
+
if (binaryProfile.com_profile.class_factory_exports.length > 0) {
|
|
241
|
+
parts.push(`class_factory_exports=${binaryProfile.com_profile.class_factory_exports.slice(0, 2).join(', ')}`);
|
|
242
|
+
}
|
|
243
|
+
if (classFactorySurface.length > 0) {
|
|
244
|
+
parts.push(`class_factory_surface=${classFactorySurface.slice(0, 2).join(', ')}`);
|
|
245
|
+
}
|
|
246
|
+
if (binaryProfile.host_interaction_profile.callback_exports.length > 0) {
|
|
247
|
+
parts.push(`callback_exports=${binaryProfile.host_interaction_profile.callback_exports.slice(0, 2).join(', ')}`);
|
|
248
|
+
}
|
|
249
|
+
if (callbackSurface.length > 0) {
|
|
250
|
+
parts.push(`callback_surface=${callbackSurface.slice(0, 2).join(', ')}`);
|
|
251
|
+
}
|
|
252
|
+
if (binaryProfile.host_interaction_profile.likely_hosted) {
|
|
253
|
+
parts.push('host/plugin interaction surface detected');
|
|
254
|
+
}
|
|
255
|
+
if (binaryProfile.host_interaction_profile.host_hints.length > 0) {
|
|
256
|
+
parts.push(`host_hints=${binaryProfile.host_interaction_profile.host_hints.slice(0, 2).join(', ')}`);
|
|
257
|
+
}
|
|
258
|
+
if (binaryProfile.packed) {
|
|
259
|
+
parts.push('packing signals present');
|
|
260
|
+
}
|
|
261
|
+
return `${parts.join(', ')}.`;
|
|
262
|
+
}
|
|
263
|
+
function augmentWithBinaryProfile(triageData, binaryProfile) {
|
|
264
|
+
if (!binaryProfile) {
|
|
265
|
+
return triageData;
|
|
266
|
+
}
|
|
267
|
+
const summaryLine = buildBinaryProfileSummary(binaryProfile);
|
|
268
|
+
const lifecycleSurface = binaryProfile.lifecycle_surface || [];
|
|
269
|
+
const classFactorySurface = binaryProfile.com_profile.class_factory_surface || [];
|
|
270
|
+
const callbackSurface = binaryProfile.host_interaction_profile.callback_surface || [];
|
|
271
|
+
const evidenceLines = dedupe([
|
|
272
|
+
summaryLine,
|
|
273
|
+
...binaryProfile.analysis_priorities.map((item) => `binary_profile_priority: ${item}`),
|
|
274
|
+
...binaryProfile.export_dispatch_profile.registration_exports.map((item) => `binary_profile_surface: registration_export=${item}`),
|
|
275
|
+
...lifecycleSurface.map((item) => `binary_profile_surface: dll_lifecycle=${item}`),
|
|
276
|
+
...binaryProfile.com_profile.class_factory_exports.map((item) => `binary_profile_surface: class_factory_export=${item}`),
|
|
277
|
+
...classFactorySurface.map((item) => `binary_profile_surface: class_factory_surface=${item}`),
|
|
278
|
+
...binaryProfile.host_interaction_profile.callback_exports.map((item) => `binary_profile_surface: callback_export=${item}`),
|
|
279
|
+
...callbackSurface.map((item) => `binary_profile_surface: callback_surface=${item}`),
|
|
280
|
+
...binaryProfile.host_interaction_profile.host_hints.map((item) => `binary_profile_surface: host_hint=${item}`),
|
|
281
|
+
]);
|
|
282
|
+
const recommendationSuffix = binaryProfile.analysis_priorities.length > 0
|
|
283
|
+
? ` Binary role priorities: ${binaryProfile.analysis_priorities.join(', ')}.`
|
|
284
|
+
: '';
|
|
285
|
+
return {
|
|
286
|
+
...triageData,
|
|
287
|
+
summary: `${triageData.summary} ${summaryLine}`,
|
|
288
|
+
evidence: dedupe([...triageData.evidence, ...evidenceLines]),
|
|
289
|
+
binary_profile: binaryProfile,
|
|
290
|
+
recommendation: `${triageData.recommendation}${recommendationSuffix}`.trim(),
|
|
291
|
+
inference: triageData.inference
|
|
292
|
+
? {
|
|
293
|
+
...triageData.inference,
|
|
294
|
+
hypotheses: dedupe([
|
|
295
|
+
...triageData.inference.hypotheses,
|
|
296
|
+
`Binary role profile suggests ${binaryProfile.binary_role}.`,
|
|
297
|
+
]),
|
|
298
|
+
}
|
|
299
|
+
: triageData.inference,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
function buildRustProfileSummary(rustProfile) {
|
|
303
|
+
const parts = [
|
|
304
|
+
`Rust-focused analysis ${rustProfile.suspected_rust ? 'suggests a Rust-oriented binary' : 'did not strongly confirm Rust'} (confidence=${rustProfile.confidence.toFixed(2)})`,
|
|
305
|
+
];
|
|
306
|
+
if (rustProfile.primary_runtime) {
|
|
307
|
+
parts.push(`runtime=${rustProfile.primary_runtime}`);
|
|
308
|
+
}
|
|
309
|
+
if (rustProfile.crate_hints.length > 0) {
|
|
310
|
+
parts.push(`crate_hints=${rustProfile.crate_hints.slice(0, 4).join(', ')}`);
|
|
311
|
+
}
|
|
312
|
+
if (rustProfile.recovered_function_count > 0) {
|
|
313
|
+
parts.push(`recovered_functions=${rustProfile.recovered_function_count}`);
|
|
314
|
+
}
|
|
315
|
+
if (rustProfile.recovered_symbol_count > 0) {
|
|
316
|
+
parts.push(`recovered_symbols=${rustProfile.recovered_symbol_count}`);
|
|
317
|
+
}
|
|
318
|
+
return `${parts.join(', ')}.`;
|
|
319
|
+
}
|
|
320
|
+
function augmentWithRustProfile(triageData, rustProfile) {
|
|
321
|
+
if (!rustProfile) {
|
|
322
|
+
return triageData;
|
|
323
|
+
}
|
|
324
|
+
const summaryLine = buildRustProfileSummary(rustProfile);
|
|
325
|
+
const rustPriorityLines = rustProfile.analysis_priorities.map((item) => `rust_analysis_priority: ${item}`);
|
|
326
|
+
const compilerArtifacts = {
|
|
327
|
+
...(triageData.iocs.compiler_artifacts || {}),
|
|
328
|
+
cargo_paths: dedupe([
|
|
329
|
+
...(triageData.iocs.compiler_artifacts?.cargo_paths || []),
|
|
330
|
+
...rustProfile.cargo_paths,
|
|
331
|
+
]),
|
|
332
|
+
rust_markers: dedupe([
|
|
333
|
+
...(triageData.iocs.compiler_artifacts?.rust_markers || []),
|
|
334
|
+
...rustProfile.rust_markers,
|
|
335
|
+
]),
|
|
336
|
+
library_profile: rustProfile.library_profile || triageData.iocs.compiler_artifacts?.library_profile,
|
|
337
|
+
};
|
|
338
|
+
const recommendationSuffix = rustProfile.analysis_priorities.length > 0
|
|
339
|
+
? ` Rust recovery priorities: ${rustProfile.analysis_priorities.join(', ')}.`
|
|
340
|
+
: '';
|
|
341
|
+
return {
|
|
342
|
+
...triageData,
|
|
343
|
+
summary: `${triageData.summary} ${summaryLine}`.trim(),
|
|
344
|
+
iocs: {
|
|
345
|
+
...triageData.iocs,
|
|
346
|
+
compiler_artifacts: compilerArtifacts,
|
|
347
|
+
},
|
|
348
|
+
evidence: dedupe([summaryLine, ...triageData.evidence, ...rustProfile.evidence, ...rustPriorityLines]),
|
|
349
|
+
rust_profile: rustProfile,
|
|
350
|
+
recommendation: `${triageData.recommendation}${recommendationSuffix}`.trim(),
|
|
351
|
+
inference: triageData.inference
|
|
352
|
+
? {
|
|
353
|
+
...triageData.inference,
|
|
354
|
+
hypotheses: dedupe([
|
|
355
|
+
...triageData.inference.hypotheses,
|
|
356
|
+
rustProfile.suspected_rust
|
|
357
|
+
? 'Rust/toolchain evidence is strong enough to prioritize non-Ghidra function recovery paths.'
|
|
358
|
+
: 'Rust/toolchain evidence remains weak; keep recovery paths heuristic.',
|
|
359
|
+
]),
|
|
360
|
+
tooling_assessment: triageData.inference.tooling_assessment
|
|
361
|
+
? {
|
|
362
|
+
...triageData.inference.tooling_assessment,
|
|
363
|
+
framework_hints: dedupe([
|
|
364
|
+
...triageData.inference.tooling_assessment.framework_hints,
|
|
365
|
+
...rustProfile.crate_hints,
|
|
366
|
+
]),
|
|
367
|
+
toolchain_markers: dedupe([
|
|
368
|
+
...triageData.inference.tooling_assessment.toolchain_markers,
|
|
369
|
+
...rustProfile.runtime_hints,
|
|
370
|
+
]),
|
|
371
|
+
library_profile: triageData.inference.tooling_assessment.library_profile ||
|
|
372
|
+
rustProfile.library_profile,
|
|
373
|
+
}
|
|
374
|
+
: {
|
|
375
|
+
help_text_detected: false,
|
|
376
|
+
cli_surface_detected: false,
|
|
377
|
+
framework_hints: rustProfile.crate_hints,
|
|
378
|
+
toolchain_markers: rustProfile.runtime_hints,
|
|
379
|
+
library_profile: rustProfile.library_profile,
|
|
380
|
+
},
|
|
381
|
+
}
|
|
382
|
+
: triageData.inference,
|
|
383
|
+
};
|
|
384
|
+
}
|
|
211
385
|
function toolMetrics(startTime) {
|
|
212
386
|
return {
|
|
213
387
|
elapsed_ms: Date.now() - startTime,
|
|
@@ -334,6 +508,18 @@ function augmentWithDynamicEvidence(triageData, dynamicEvidence) {
|
|
|
334
508
|
buildEvidenceLayerHeadline(evidenceLineage),
|
|
335
509
|
...triageData.evidence,
|
|
336
510
|
...dynamicEvidence.evidence,
|
|
511
|
+
...(dynamicEvidence.protections || []).length > 0
|
|
512
|
+
? [`Runtime protections: ${(dynamicEvidence.protections || []).slice(0, 4).join(', ')}.`]
|
|
513
|
+
: [],
|
|
514
|
+
...(dynamicEvidence.region_owners || []).length > 0
|
|
515
|
+
? [`Runtime region owners: ${(dynamicEvidence.region_owners || []).slice(0, 4).join(', ')}.`]
|
|
516
|
+
: [],
|
|
517
|
+
...(dynamicEvidence.observed_modules || []).length > 0
|
|
518
|
+
? [`Runtime observed modules: ${(dynamicEvidence.observed_modules || []).slice(0, 4).join(', ')}.`]
|
|
519
|
+
: [],
|
|
520
|
+
...(dynamicEvidence.segment_names || []).length > 0
|
|
521
|
+
? [`Runtime segment names: ${(dynamicEvidence.segment_names || []).slice(0, 4).join(', ')}.`]
|
|
522
|
+
: [],
|
|
337
523
|
]),
|
|
338
524
|
evidence_lineage: evidenceLineage,
|
|
339
525
|
evidence_weights: {
|
|
@@ -348,6 +534,12 @@ function augmentWithDynamicEvidence(triageData, dynamicEvidence) {
|
|
|
348
534
|
hypotheses: dedupe([
|
|
349
535
|
...triageData.inference.hypotheses,
|
|
350
536
|
...dynamicEvidence.stages.map((item) => `Imported runtime evidence indicates stage: ${item}.`),
|
|
537
|
+
...(dynamicEvidence.observed_modules || [])
|
|
538
|
+
.slice(0, 3)
|
|
539
|
+
.map((item) => `Imported runtime evidence observed module: ${item}.`),
|
|
540
|
+
...(dynamicEvidence.segment_names || [])
|
|
541
|
+
.slice(0, 3)
|
|
542
|
+
.map((item) => `Imported runtime evidence observed segment: ${item}.`),
|
|
351
543
|
]),
|
|
352
544
|
false_positive_risks: dedupe([
|
|
353
545
|
...triageData.inference.false_positive_risks,
|
|
@@ -367,7 +559,7 @@ function augmentWithDynamicEvidence(triageData, dynamicEvidence) {
|
|
|
367
559
|
},
|
|
368
560
|
};
|
|
369
561
|
}
|
|
370
|
-
function createMinimalDotnetFallback(triageResult, startTime, functionExplanations = [], provenance, evidenceScope = 'all') {
|
|
562
|
+
function createMinimalDotnetFallback(triageResult, startTime, functionExplanations = [], provenance, evidenceScope = 'all', binaryProfile, rustProfile) {
|
|
371
563
|
const triageErrors = triageResult.errors || [];
|
|
372
564
|
const warnings = [
|
|
373
565
|
'report.summarize(mode=dotnet) is not fully implemented; returned degraded fallback output.',
|
|
@@ -390,8 +582,12 @@ function createMinimalDotnetFallback(triageResult, startTime, functionExplanatio
|
|
|
390
582
|
evidence: [
|
|
391
583
|
'Dotnet mode unavailable; triage fallback failed.',
|
|
392
584
|
...triageErrors.map((item) => `triage_error: ${item}`),
|
|
585
|
+
...(binaryProfile ? [buildBinaryProfileSummary(binaryProfile)] : []),
|
|
586
|
+
...(rustProfile ? [buildRustProfileSummary(rustProfile)] : []),
|
|
393
587
|
],
|
|
394
588
|
confidence_semantics: buildAssessmentConfidencePayload(0.2, evidenceScope),
|
|
589
|
+
binary_profile: binaryProfile,
|
|
590
|
+
rust_profile: rustProfile,
|
|
395
591
|
provenance,
|
|
396
592
|
function_explanations: functionExplanations.length > 0 ? functionExplanations : undefined,
|
|
397
593
|
inference: {
|
|
@@ -401,20 +597,20 @@ function createMinimalDotnetFallback(triageResult, startTime, functionExplanatio
|
|
|
401
597
|
],
|
|
402
598
|
false_positive_risks: ['No triage evidence is available in this degraded fallback result.'],
|
|
403
599
|
},
|
|
404
|
-
recommendation:
|
|
600
|
+
recommendation: `Re-run after ensuring workspace/original sample file exists, then use workflow.reconstruct or dotnet.reconstruct.export for .NET-specific structure.${binaryProfile?.analysis_priorities?.length ? ` Binary role priorities: ${binaryProfile.analysis_priorities.join(', ')}.` : ''}${rustProfile?.analysis_priorities?.length ? ` Rust recovery priorities: ${rustProfile.analysis_priorities.join(', ')}.` : ''}`,
|
|
405
601
|
},
|
|
406
602
|
warnings,
|
|
407
603
|
errors: triageErrors.length > 0 ? triageErrors : undefined,
|
|
408
604
|
metrics: toolMetrics(startTime),
|
|
409
605
|
};
|
|
410
606
|
}
|
|
411
|
-
function createDynamicEvidenceFallback(dynamicEvidence, triageResult, startTime, functionExplanations = [], provenance, evidenceScope = 'all') {
|
|
607
|
+
function createDynamicEvidenceFallback(dynamicEvidence, triageResult, startTime, functionExplanations = [], provenance, evidenceScope = 'all', binaryProfile, rustProfile) {
|
|
412
608
|
const evidenceLineage = buildEvidenceLineage(dynamicEvidence);
|
|
413
609
|
const threatLevel = dynamicEvidence.high_signal_apis.length > 0 ? 'suspicious' : dynamicEvidence.executed ? 'suspicious' : 'unknown';
|
|
414
610
|
return {
|
|
415
611
|
ok: true,
|
|
416
612
|
data: {
|
|
417
|
-
summary: `Triage pipeline failed, but imported runtime evidence is available. ${buildEvidenceLayerHeadline(evidenceLineage)} ${dynamicEvidence.summary}`,
|
|
613
|
+
summary: `Triage pipeline failed, but imported runtime evidence is available. ${buildEvidenceLayerHeadline(evidenceLineage)} ${dynamicEvidence.summary}${binaryProfile ? ` ${buildBinaryProfileSummary(binaryProfile)}` : ''}${rustProfile ? ` ${buildRustProfileSummary(rustProfile)}` : ''}`,
|
|
418
614
|
confidence: dynamicEvidence.executed ? 0.66 : 0.5,
|
|
419
615
|
threat_level: threatLevel,
|
|
420
616
|
iocs: {
|
|
@@ -425,9 +621,16 @@ function createDynamicEvidenceFallback(dynamicEvidence, triageResult, startTime,
|
|
|
425
621
|
suspicious_apis: dynamicEvidence.high_signal_apis,
|
|
426
622
|
},
|
|
427
623
|
},
|
|
428
|
-
evidence: dedupe([
|
|
624
|
+
evidence: dedupe([
|
|
625
|
+
buildEvidenceLayerHeadline(evidenceLineage),
|
|
626
|
+
...dynamicEvidence.evidence,
|
|
627
|
+
...(binaryProfile ? [buildBinaryProfileSummary(binaryProfile)] : []),
|
|
628
|
+
...(rustProfile ? [buildRustProfileSummary(rustProfile)] : []),
|
|
629
|
+
]),
|
|
429
630
|
evidence_lineage: evidenceLineage,
|
|
430
631
|
confidence_semantics: buildAssessmentConfidencePayload(dynamicEvidence.executed ? 0.66 : 0.5, evidenceScope, evidenceLineage),
|
|
632
|
+
binary_profile: binaryProfile,
|
|
633
|
+
rust_profile: rustProfile,
|
|
431
634
|
provenance,
|
|
432
635
|
function_explanations: functionExplanations.length > 0 ? functionExplanations : undefined,
|
|
433
636
|
evidence_weights: {
|
|
@@ -444,7 +647,7 @@ function createDynamicEvidenceFallback(dynamicEvidence, triageResult, startTime,
|
|
|
444
647
|
: 'Memory/hybrid evidence is suggestive but not equivalent to a fully executed trace.',
|
|
445
648
|
],
|
|
446
649
|
},
|
|
447
|
-
recommendation:
|
|
650
|
+
recommendation: `Correlate imported runtime evidence with code.functions.search, code.functions.reconstruct, and code.reconstruct.export to assign concrete function ownership.${binaryProfile?.analysis_priorities?.length ? ` Binary role priorities: ${binaryProfile.analysis_priorities.join(', ')}.` : ''}${rustProfile?.analysis_priorities?.length ? ` Rust recovery priorities: ${rustProfile.analysis_priorities.join(', ')}.` : ''}`,
|
|
448
651
|
},
|
|
449
652
|
warnings: [
|
|
450
653
|
'Triage pipeline failed; returned imported runtime-evidence fallback.',
|
|
@@ -456,6 +659,10 @@ function createDynamicEvidenceFallback(dynamicEvidence, triageResult, startTime,
|
|
|
456
659
|
}
|
|
457
660
|
export function createReportSummarizeHandler(workspaceManager, database, cacheManager, deps) {
|
|
458
661
|
const triageHandler = deps?.triageHandler || createTriageWorkflowHandler(workspaceManager, database, cacheManager);
|
|
662
|
+
const binaryRoleProfileHandler = deps?.binaryRoleProfileHandler ||
|
|
663
|
+
createBinaryRoleProfileHandler(workspaceManager, database, cacheManager);
|
|
664
|
+
const rustBinaryAnalyzeHandler = deps?.rustBinaryAnalyzeHandler ||
|
|
665
|
+
createRustBinaryAnalyzeHandler(workspaceManager, database, cacheManager);
|
|
459
666
|
return async (args) => {
|
|
460
667
|
const startTime = Date.now();
|
|
461
668
|
try {
|
|
@@ -467,10 +674,31 @@ export function createReportSummarizeHandler(workspaceManager, database, cacheMa
|
|
|
467
674
|
errors: [`Sample not found: ${input.sample_id}`],
|
|
468
675
|
};
|
|
469
676
|
}
|
|
677
|
+
const warnings = [];
|
|
470
678
|
const dynamicEvidence = await loadDynamicTraceEvidence(workspaceManager, database, input.sample_id, {
|
|
471
679
|
evidenceScope: input.evidence_scope,
|
|
472
680
|
sessionTag: input.evidence_session_tag,
|
|
473
681
|
});
|
|
682
|
+
const binaryRoleProfileResult = await binaryRoleProfileHandler({ sample_id: input.sample_id });
|
|
683
|
+
const binaryProfile = binaryRoleProfileResult.ok && binaryRoleProfileResult.data
|
|
684
|
+
? binaryRoleProfileResult.data
|
|
685
|
+
: undefined;
|
|
686
|
+
if (!binaryRoleProfileResult.ok) {
|
|
687
|
+
warnings.push(`binary.role.profile unavailable: ${(binaryRoleProfileResult.errors || ['unknown error']).join('; ')}`);
|
|
688
|
+
}
|
|
689
|
+
else if (binaryRoleProfileResult.warnings?.length) {
|
|
690
|
+
warnings.push(...binaryRoleProfileResult.warnings.map((item) => `binary.role.profile: ${item}`));
|
|
691
|
+
}
|
|
692
|
+
const rustBinaryAnalyzeResult = await rustBinaryAnalyzeHandler({ sample_id: input.sample_id });
|
|
693
|
+
const rustProfile = rustBinaryAnalyzeResult.ok && rustBinaryAnalyzeResult.data
|
|
694
|
+
? rustBinaryAnalyzeResult.data
|
|
695
|
+
: undefined;
|
|
696
|
+
if (!rustBinaryAnalyzeResult.ok) {
|
|
697
|
+
warnings.push(`rust_binary.analyze unavailable: ${(rustBinaryAnalyzeResult.errors || ['unknown error']).join('; ')}`);
|
|
698
|
+
}
|
|
699
|
+
else if (rustBinaryAnalyzeResult.warnings?.length) {
|
|
700
|
+
warnings.push(...rustBinaryAnalyzeResult.warnings.map((item) => `rust_binary.analyze: ${item}`));
|
|
701
|
+
}
|
|
474
702
|
const functionExplanationBundle = await loadFunctionExplanationSummaries(workspaceManager, database, input.sample_id, {
|
|
475
703
|
scope: input.semantic_scope,
|
|
476
704
|
sessionTag: input.semantic_session_tag,
|
|
@@ -502,7 +730,7 @@ export function createReportSummarizeHandler(workspaceManager, database, cacheMa
|
|
|
502
730
|
if (input.mode === 'triage') {
|
|
503
731
|
if (!triageResult.ok || !triageResult.data) {
|
|
504
732
|
if (dynamicEvidence) {
|
|
505
|
-
return createDynamicEvidenceFallback(dynamicEvidence, triageResult, startTime, functionExplanations, provenance, input.evidence_scope);
|
|
733
|
+
return createDynamicEvidenceFallback(dynamicEvidence, triageResult, startTime, functionExplanations, provenance, input.evidence_scope, binaryProfile, rustProfile);
|
|
506
734
|
}
|
|
507
735
|
return {
|
|
508
736
|
ok: false,
|
|
@@ -515,7 +743,9 @@ export function createReportSummarizeHandler(workspaceManager, database, cacheMa
|
|
|
515
743
|
const triageData = dynamicEvidence
|
|
516
744
|
? augmentWithDynamicEvidence(triageDataBase, dynamicEvidence)
|
|
517
745
|
: triageDataBase;
|
|
518
|
-
const
|
|
746
|
+
const binaryEnrichedTriageData = augmentWithBinaryProfile(triageData, binaryProfile);
|
|
747
|
+
const rustEnrichedTriageData = augmentWithRustProfile(binaryEnrichedTriageData, rustProfile);
|
|
748
|
+
const enrichedTriageData = augmentWithFunctionExplanations(rustEnrichedTriageData, functionExplanations);
|
|
519
749
|
return {
|
|
520
750
|
ok: true,
|
|
521
751
|
data: {
|
|
@@ -526,6 +756,8 @@ export function createReportSummarizeHandler(workspaceManager, database, cacheMa
|
|
|
526
756
|
evidence: enrichedTriageData.evidence,
|
|
527
757
|
evidence_lineage: enrichedTriageData.evidence_lineage || buildEvidenceLineage(dynamicEvidence),
|
|
528
758
|
confidence_semantics: buildAssessmentConfidencePayload(enrichedTriageData.confidence, input.evidence_scope, enrichedTriageData.evidence_lineage || buildEvidenceLineage(dynamicEvidence)),
|
|
759
|
+
binary_profile: enrichedTriageData.binary_profile,
|
|
760
|
+
rust_profile: enrichedTriageData.rust_profile,
|
|
529
761
|
provenance,
|
|
530
762
|
selection_diffs: Object.keys(selectionDiffs).length > 0 ? selectionDiffs : undefined,
|
|
531
763
|
function_explanations: enrichedTriageData.function_explanations,
|
|
@@ -535,18 +767,19 @@ export function createReportSummarizeHandler(workspaceManager, database, cacheMa
|
|
|
535
767
|
},
|
|
536
768
|
warnings: dynamicEvidence
|
|
537
769
|
? dedupe([
|
|
770
|
+
...warnings,
|
|
538
771
|
...(triageResult.warnings || []),
|
|
539
772
|
`Merged imported runtime evidence from ${dynamicEvidence.artifact_count} artifact(s) using scope=${input.evidence_scope}${input.evidence_session_tag ? ` selector=${input.evidence_session_tag}` : ''}.`,
|
|
540
773
|
dynamicEvidence.scope_note || '',
|
|
541
774
|
])
|
|
542
|
-
: triageResult.warnings,
|
|
775
|
+
: dedupe([...warnings, ...(triageResult.warnings || [])]),
|
|
543
776
|
errors: triageResult.errors,
|
|
544
777
|
metrics: toolMetrics(startTime),
|
|
545
778
|
};
|
|
546
779
|
}
|
|
547
780
|
if (input.mode === 'dotnet') {
|
|
548
781
|
if (!triageResult.ok || !triageResult.data) {
|
|
549
|
-
return createMinimalDotnetFallback(triageResult, startTime, functionExplanations, provenance, input.evidence_scope);
|
|
782
|
+
return createMinimalDotnetFallback(triageResult, startTime, functionExplanations, provenance, input.evidence_scope, binaryProfile, rustProfile);
|
|
550
783
|
}
|
|
551
784
|
const triageData = triageResult.data;
|
|
552
785
|
return {
|
|
@@ -563,6 +796,8 @@ export function createReportSummarizeHandler(workspaceManager, database, cacheMa
|
|
|
563
796
|
],
|
|
564
797
|
evidence_lineage: triageData.evidence_lineage || buildEvidenceLineage(dynamicEvidence),
|
|
565
798
|
confidence_semantics: buildAssessmentConfidencePayload(Math.max(0.05, Math.min(0.95, triageData.confidence * 0.92)), input.evidence_scope, triageData.evidence_lineage || buildEvidenceLineage(dynamicEvidence)),
|
|
799
|
+
binary_profile: binaryProfile,
|
|
800
|
+
rust_profile: rustProfile,
|
|
566
801
|
provenance,
|
|
567
802
|
selection_diffs: Object.keys(selectionDiffs).length > 0 ? selectionDiffs : undefined,
|
|
568
803
|
function_explanations: functionExplanations.length > 0 ? functionExplanations : undefined,
|
|
@@ -572,6 +807,7 @@ export function createReportSummarizeHandler(workspaceManager, database, cacheMa
|
|
|
572
807
|
'dotnet.reconstruct.export / workflow.reconstruct for .NET-specific structure.',
|
|
573
808
|
},
|
|
574
809
|
warnings: [
|
|
810
|
+
...warnings,
|
|
575
811
|
'report.summarize(mode=dotnet) not fully implemented; returned triage fallback.',
|
|
576
812
|
...(triageResult.warnings || []),
|
|
577
813
|
],
|
|
@@ -83,10 +83,6 @@ export declare const RuntimeDetectOutputSchema: z.ZodObject<{
|
|
|
83
83
|
}>>;
|
|
84
84
|
}, "strip", z.ZodTypeAny, {
|
|
85
85
|
ok: boolean;
|
|
86
|
-
metrics?: {
|
|
87
|
-
elapsed_ms: number;
|
|
88
|
-
tool: string;
|
|
89
|
-
} | undefined;
|
|
90
86
|
data?: {
|
|
91
87
|
is_dotnet: boolean;
|
|
92
88
|
dotnet_version: string | null;
|
|
@@ -98,15 +94,15 @@ export declare const RuntimeDetectOutputSchema: z.ZodObject<{
|
|
|
98
94
|
}[];
|
|
99
95
|
import_dlls: string[];
|
|
100
96
|
} | undefined;
|
|
97
|
+
metrics?: {
|
|
98
|
+
elapsed_ms: number;
|
|
99
|
+
tool: string;
|
|
100
|
+
} | undefined;
|
|
101
101
|
warnings?: string[] | undefined;
|
|
102
102
|
errors?: string[] | undefined;
|
|
103
103
|
artifacts?: any[] | undefined;
|
|
104
104
|
}, {
|
|
105
105
|
ok: boolean;
|
|
106
|
-
metrics?: {
|
|
107
|
-
elapsed_ms: number;
|
|
108
|
-
tool: string;
|
|
109
|
-
} | undefined;
|
|
110
106
|
data?: {
|
|
111
107
|
is_dotnet: boolean;
|
|
112
108
|
dotnet_version: string | null;
|
|
@@ -118,6 +114,10 @@ export declare const RuntimeDetectOutputSchema: z.ZodObject<{
|
|
|
118
114
|
}[];
|
|
119
115
|
import_dlls: string[];
|
|
120
116
|
} | undefined;
|
|
117
|
+
metrics?: {
|
|
118
|
+
elapsed_ms: number;
|
|
119
|
+
tool: string;
|
|
120
|
+
} | undefined;
|
|
121
121
|
warnings?: string[] | undefined;
|
|
122
122
|
errors?: string[] | undefined;
|
|
123
123
|
artifacts?: any[] | undefined;
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { z } from 'zod';
|
|
7
7
|
import { spawn } from 'child_process';
|
|
8
|
-
import path from 'path';
|
|
9
8
|
import { v4 as uuidv4 } from 'uuid';
|
|
10
9
|
import { generateCacheKey } from '../cache-manager.js';
|
|
11
10
|
import { resolvePackagePath } from '../runtime-paths.js';
|
|
12
11
|
import { lookupCachedResult, formatCacheWarning } from './cache-observability.js';
|
|
12
|
+
import { resolvePrimarySamplePath } from '../sample-workspace.js';
|
|
13
13
|
// ============================================================================
|
|
14
14
|
// Constants
|
|
15
15
|
// ============================================================================
|
|
@@ -174,17 +174,7 @@ export function createRuntimeDetectHandler(workspaceManager, database, cacheMana
|
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
176
|
// 3. Get sample path from workspace
|
|
177
|
-
const
|
|
178
|
-
// Find the sample file in the original directory
|
|
179
|
-
const fs = await import('fs/promises');
|
|
180
|
-
const files = await fs.readdir(workspace.original);
|
|
181
|
-
if (files.length === 0) {
|
|
182
|
-
return {
|
|
183
|
-
ok: false,
|
|
184
|
-
errors: ['Sample file not found in workspace'],
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
const samplePath = path.join(workspace.original, files[0]);
|
|
177
|
+
const { samplePath } = await resolvePrimarySamplePath(workspaceManager, input.sample_id);
|
|
188
178
|
// 4. Prepare worker request
|
|
189
179
|
const workerRequest = {
|
|
190
180
|
job_id: uuidv4(),
|