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.
Files changed (134) hide show
  1. package/CLAUDE_INSTALLATION.md +129 -0
  2. package/CODEX_INSTALLATION.md +25 -1
  3. package/COPILOT_INSTALLATION.md +29 -1
  4. package/LICENSE +21 -21
  5. package/README.md +232 -110
  6. package/dist/analysis-provenance.d.ts +50 -2
  7. package/dist/analysis-provenance.js +1 -0
  8. package/dist/analysis-task-runner.js +92 -0
  9. package/dist/config.d.ts +35 -16
  10. package/dist/config.js +37 -3
  11. package/dist/database.js +115 -115
  12. package/dist/decompiler-worker.d.ts +10 -5
  13. package/dist/decompiler-worker.js +240 -58
  14. package/dist/dynamic-trace.d.ts +6 -0
  15. package/dist/dynamic-trace.js +52 -1
  16. package/dist/ghidra-config.js +17 -1
  17. package/dist/index.js +38 -8
  18. package/dist/pe-runtime-functions.d.ts +90 -0
  19. package/dist/pe-runtime-functions.js +452 -0
  20. package/dist/prompts/module-reconstruction-review.d.ts +5 -0
  21. package/dist/prompts/module-reconstruction-review.js +65 -0
  22. package/dist/runtime-correlation.d.ts +5 -0
  23. package/dist/runtime-correlation.js +179 -2
  24. package/dist/sample-workspace.d.ts +28 -0
  25. package/dist/sample-workspace.js +186 -0
  26. package/dist/semantic-name-suggestion-artifacts.d.ts +56 -0
  27. package/dist/semantic-name-suggestion-artifacts.js +87 -0
  28. package/dist/server.js +1 -1
  29. package/dist/setup-guidance.d.ts +73 -0
  30. package/dist/setup-guidance.js +211 -0
  31. package/dist/tools/artifact-read.d.ts +10 -10
  32. package/dist/tools/artifacts-diff.d.ts +8 -8
  33. package/dist/tools/artifacts-list.d.ts +16 -16
  34. package/dist/tools/attack-map.d.ts +8 -8
  35. package/dist/tools/binary-role-profile.d.ts +1197 -0
  36. package/dist/tools/binary-role-profile.js +575 -0
  37. package/dist/tools/code-function-explain-apply.d.ts +12 -12
  38. package/dist/tools/code-function-explain-prepare.d.ts +12 -12
  39. package/dist/tools/code-function-explain-review.d.ts +58 -58
  40. package/dist/tools/code-function-rename-apply.d.ts +12 -12
  41. package/dist/tools/code-function-rename-prepare.d.ts +14 -14
  42. package/dist/tools/code-function-rename-review.d.ts +66 -66
  43. package/dist/tools/code-functions-define.d.ts +337 -0
  44. package/dist/tools/code-functions-define.js +337 -0
  45. package/dist/tools/code-functions-list.js +1 -1
  46. package/dist/tools/code-functions-rank.js +1 -1
  47. package/dist/tools/code-functions-reconstruct.d.ts +368 -58
  48. package/dist/tools/code-functions-reconstruct.js +130 -10
  49. package/dist/tools/code-functions-smart-recover.d.ts +352 -0
  50. package/dist/tools/code-functions-smart-recover.js +190 -0
  51. package/dist/tools/code-module-review-apply.d.ts +233 -0
  52. package/dist/tools/code-module-review-apply.js +209 -0
  53. package/dist/tools/code-module-review-prepare.d.ts +756 -0
  54. package/dist/tools/code-module-review-prepare.js +343 -0
  55. package/dist/tools/code-module-review.d.ts +474 -0
  56. package/dist/tools/code-module-review.js +566 -0
  57. package/dist/tools/code-reconstruct-export.d.ts +193 -21
  58. package/dist/tools/code-reconstruct-export.js +578 -21
  59. package/dist/tools/code-reconstruct-plan.d.ts +20 -20
  60. package/dist/tools/com-role-profile.d.ts +353 -0
  61. package/dist/tools/com-role-profile.js +186 -0
  62. package/dist/tools/dll-export-profile.d.ts +625 -0
  63. package/dist/tools/dll-export-profile.js +230 -0
  64. package/dist/tools/dotnet-metadata-extract.d.ts +122 -122
  65. package/dist/tools/dotnet-reconstruct-export.d.ts +49 -49
  66. package/dist/tools/dotnet-types-list.d.ts +66 -66
  67. package/dist/tools/dynamic-dependencies.d.ts +144 -8
  68. package/dist/tools/dynamic-dependencies.js +20 -1
  69. package/dist/tools/dynamic-memory-import.js +105 -2
  70. package/dist/tools/ghidra-analyze.d.ts +20 -0
  71. package/dist/tools/ghidra-analyze.js +10 -2
  72. package/dist/tools/ghidra-health.d.ts +177 -0
  73. package/dist/tools/ghidra-health.js +28 -0
  74. package/dist/tools/ioc-export.d.ts +8 -8
  75. package/dist/tools/packer-detect.d.ts +14 -14
  76. package/dist/tools/packer-detect.js +6 -9
  77. package/dist/tools/pe-exports-extract.d.ts +8 -8
  78. package/dist/tools/pe-exports-extract.js +6 -9
  79. package/dist/tools/pe-fingerprint.d.ts +36 -36
  80. package/dist/tools/pe-imports-extract.d.ts +8 -8
  81. package/dist/tools/pe-imports-extract.js +6 -9
  82. package/dist/tools/pe-pdata-extract.d.ts +448 -0
  83. package/dist/tools/pe-pdata-extract.js +219 -0
  84. package/dist/tools/pe-symbols-recover.d.ts +227 -0
  85. package/dist/tools/pe-symbols-recover.js +316 -0
  86. package/dist/tools/report-generate.d.ts +15 -1
  87. package/dist/tools/report-generate.js +139 -16
  88. package/dist/tools/report-summarize.d.ts +2242 -8
  89. package/dist/tools/report-summarize.js +246 -10
  90. package/dist/tools/runtime-detect.d.ts +8 -8
  91. package/dist/tools/runtime-detect.js +2 -12
  92. package/dist/tools/rust-binary-analyze.d.ts +2047 -0
  93. package/dist/tools/rust-binary-analyze.js +443 -0
  94. package/dist/tools/sample-profile-get.d.ts +135 -16
  95. package/dist/tools/sample-profile-get.js +35 -32
  96. package/dist/tools/sandbox-execute.d.ts +10 -10
  97. package/dist/tools/strings-extract.d.ts +8 -8
  98. package/dist/tools/strings-extract.js +2 -12
  99. package/dist/tools/strings-floss-decode.d.ts +8 -8
  100. package/dist/tools/system-health.d.ts +172 -36
  101. package/dist/tools/system-health.js +14 -0
  102. package/dist/tools/system-setup-guide.d.ts +179 -0
  103. package/dist/tools/system-setup-guide.js +62 -0
  104. package/dist/tools/tool-help.d.ts +16 -16
  105. package/dist/tools/tool-help.js +172 -0
  106. package/dist/tools/yara-scan.d.ts +8 -8
  107. package/dist/types.d.ts +2 -0
  108. package/dist/workflows/function-explanation-review.d.ts +3034 -76
  109. package/dist/workflows/function-explanation-review.js +172 -42
  110. package/dist/workflows/function-index-recover.d.ts +333 -0
  111. package/dist/workflows/function-index-recover.js +291 -0
  112. package/dist/workflows/module-reconstruction-review.d.ts +3537 -0
  113. package/dist/workflows/module-reconstruction-review.js +354 -0
  114. package/dist/workflows/reconstruct.d.ts +2182 -223
  115. package/dist/workflows/reconstruct.js +575 -32
  116. package/dist/workflows/semantic-name-review.d.ts +1436 -85
  117. package/dist/workflows/semantic-name-review.js +150 -58
  118. package/dist/workflows/triage.d.ts +8 -8
  119. package/ghidra_scripts/DecompileFunction.java +487 -487
  120. package/ghidra_scripts/ExtractCFG.java +256 -256
  121. package/ghidra_scripts/ExtractFunctions.java +442 -442
  122. package/ghidra_scripts/README.md +112 -112
  123. package/ghidra_scripts/SearchFunctionReferences.java +380 -380
  124. package/helpers/DotNetMetadataProbe/DotNetMetadataProbe.csproj +9 -9
  125. package/helpers/DotNetMetadataProbe/Program.cs +566 -566
  126. package/install-to-claude.ps1 +432 -0
  127. package/install-to-codex.ps1 +256 -178
  128. package/install-to-copilot.ps1 +389 -303
  129. package/package.json +4 -2
  130. package/requirements.txt +9 -9
  131. package/workers/requirements-dynamic.txt +11 -11
  132. package/workers/requirements.txt +8 -8
  133. package/workers/speakeasy_compat.py +175 -175
  134. package/workers/static_worker.py +3474 -3474
@@ -0,0 +1,443 @@
1
+ import { z } from 'zod';
2
+ import { generateCacheKey } from '../cache-manager.js';
3
+ import { lookupCachedResult, formatCacheWarning } from './cache-observability.js';
4
+ import { BinaryRoleProfileDataSchema, createBinaryRoleProfileHandler, } from './binary-role-profile.js';
5
+ import { createRuntimeDetectHandler } from './runtime-detect.js';
6
+ import { createStringsExtractHandler } from './strings-extract.js';
7
+ import { createCodeFunctionsSmartRecoverHandler } from './code-functions-smart-recover.js';
8
+ import { createPESymbolsRecoverHandler } from './pe-symbols-recover.js';
9
+ import { buildLibraryProfile } from '../workflows/triage.js';
10
+ const TOOL_NAME = 'rust_binary.analyze';
11
+ const TOOL_VERSION = '0.1.0';
12
+ const CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
13
+ const LIBRARY_HINT_PATTERNS = [
14
+ { name: 'tokio', patterns: [/\btokio\b/i] },
15
+ { name: 'goblin', patterns: [/\bgoblin\b/i] },
16
+ { name: 'iced-x86', patterns: [/\biced[-_]?x86\b/i] },
17
+ { name: 'clap', patterns: [/\bclap\b/i] },
18
+ { name: 'sysinfo', patterns: [/\bsysinfo\b/i] },
19
+ { name: 'reqwest', patterns: [/\breqwest\b/i] },
20
+ { name: 'serde', patterns: [/\bserde\b/i] },
21
+ { name: 'mio', patterns: [/\bmio\b/i] },
22
+ { name: 'pelite', patterns: [/\bpelite\b/i] },
23
+ { name: 'object', patterns: [/\bobject\b/i] },
24
+ { name: 'winapi', patterns: [/\bwinapi\b/i] },
25
+ { name: 'ntapi', patterns: [/\bntapi\b/i] },
26
+ { name: 'windows-sys', patterns: [/\bwindows[-_]?sys\b/i] },
27
+ ];
28
+ const RustLibraryProfileSchema = z.object({
29
+ ecosystems: z.array(z.string()),
30
+ top_crates: z.array(z.string()),
31
+ notable_libraries: z.array(z.string()),
32
+ evidence: z.array(z.string()),
33
+ });
34
+ export const rustBinaryAnalyzeInputSchema = z.object({
35
+ sample_id: z.string().describe('Sample ID (format: sha256:<hex>)'),
36
+ max_strings: z
37
+ .number()
38
+ .int()
39
+ .min(40)
40
+ .max(400)
41
+ .optional()
42
+ .default(160)
43
+ .describe('Maximum strings inspected for Rust crate, panic, and async/runtime markers'),
44
+ max_symbol_preview: z
45
+ .number()
46
+ .int()
47
+ .min(1)
48
+ .max(24)
49
+ .optional()
50
+ .default(8)
51
+ .describe('Maximum recovered symbols returned in the preview'),
52
+ force_refresh: z
53
+ .boolean()
54
+ .optional()
55
+ .default(false)
56
+ .describe('Bypass cache lookup and recompute from source sample'),
57
+ });
58
+ export const RustBinaryAnalyzeDataSchema = z.object({
59
+ sample_id: z.string(),
60
+ suspected_rust: z.boolean(),
61
+ confidence: z.number().min(0).max(1),
62
+ primary_runtime: z.string().nullable(),
63
+ runtime_hints: z.array(z.string()),
64
+ cargo_paths: z.array(z.string()),
65
+ rust_markers: z.array(z.string()),
66
+ async_runtime_markers: z.array(z.string()),
67
+ panic_markers: z.array(z.string()),
68
+ crate_hints: z.array(z.string()),
69
+ library_profile: RustLibraryProfileSchema.optional(),
70
+ binary_profile: BinaryRoleProfileDataSchema.optional(),
71
+ recovered_function_count: z.number().int().nonnegative(),
72
+ recovered_function_strategy: z.array(z.string()),
73
+ recovered_symbol_count: z.number().int().nonnegative(),
74
+ recovered_symbol_preview: z.array(z.object({
75
+ address: z.string(),
76
+ recovered_name: z.string(),
77
+ name_strategy: z.string(),
78
+ confidence: z.number(),
79
+ })),
80
+ components: z.object({
81
+ runtime_detect: z.object({
82
+ ok: z.boolean(),
83
+ warning_count: z.number().int().nonnegative(),
84
+ error_count: z.number().int().nonnegative(),
85
+ }),
86
+ strings_extract: z.object({
87
+ ok: z.boolean(),
88
+ warning_count: z.number().int().nonnegative(),
89
+ error_count: z.number().int().nonnegative(),
90
+ }),
91
+ smart_recover: z.object({
92
+ ok: z.boolean(),
93
+ warning_count: z.number().int().nonnegative(),
94
+ error_count: z.number().int().nonnegative(),
95
+ }),
96
+ symbols_recover: z.object({
97
+ ok: z.boolean(),
98
+ warning_count: z.number().int().nonnegative(),
99
+ error_count: z.number().int().nonnegative(),
100
+ }),
101
+ binary_role_profile: z.object({
102
+ ok: z.boolean(),
103
+ warning_count: z.number().int().nonnegative(),
104
+ error_count: z.number().int().nonnegative(),
105
+ }),
106
+ }),
107
+ importable_with_code_functions_define: z.boolean(),
108
+ evidence: z.array(z.string()),
109
+ analysis_priorities: z.array(z.string()),
110
+ next_steps: z.array(z.string()),
111
+ });
112
+ export const rustBinaryAnalyzeOutputSchema = z.object({
113
+ ok: z.boolean(),
114
+ data: RustBinaryAnalyzeDataSchema.optional(),
115
+ warnings: z.array(z.string()).optional(),
116
+ errors: z.array(z.string()).optional(),
117
+ metrics: z
118
+ .object({
119
+ elapsed_ms: z.number(),
120
+ tool: z.string(),
121
+ })
122
+ .optional(),
123
+ });
124
+ export const rustBinaryAnalyzeToolDefinition = {
125
+ name: TOOL_NAME,
126
+ description: 'Analyze Rust-oriented PE binaries by correlating runtime hints, crate/toolchain strings, smart function recovery, and recovered symbol names.',
127
+ inputSchema: rustBinaryAnalyzeInputSchema,
128
+ outputSchema: rustBinaryAnalyzeOutputSchema,
129
+ };
130
+ function uniqueStrings(values) {
131
+ const seen = new Set();
132
+ const output = [];
133
+ for (const value of values) {
134
+ const normalized = (value || '').trim();
135
+ if (!normalized || seen.has(normalized)) {
136
+ continue;
137
+ }
138
+ seen.add(normalized);
139
+ output.push(normalized);
140
+ }
141
+ return output;
142
+ }
143
+ function clamp(value, min = 0, max = 1) {
144
+ if (!Number.isFinite(value)) {
145
+ return min;
146
+ }
147
+ return Math.min(max, Math.max(min, value));
148
+ }
149
+ function extractCrateNameFromCargoPath(input) {
150
+ const normalized = input.replace(/\//g, '\\');
151
+ const match = normalized.match(/cargo\\(?:registry\\src|git\\checkouts)\\[^\\]+\\([^\\]+)(?:\\|$)/i);
152
+ if (!match?.[1]) {
153
+ return null;
154
+ }
155
+ return match[1].replace(/-\d[\w.+-]*$/, '').toLowerCase();
156
+ }
157
+ function detectLibraryHints(str) {
158
+ return LIBRARY_HINT_PATTERNS.filter((hint) => hint.patterns.some((pattern) => pattern.test(str))).map((hint) => hint.name);
159
+ }
160
+ function analyzeRustStrings(strings) {
161
+ const cargoPaths = [];
162
+ const rustMarkers = [];
163
+ const asyncRuntimeMarkers = [];
164
+ const panicMarkers = [];
165
+ const crateNames = [];
166
+ const libraryHints = [];
167
+ for (const rawEntry of strings) {
168
+ const str = typeof rawEntry === 'string'
169
+ ? rawEntry
170
+ : rawEntry && typeof rawEntry === 'object' && 'string' in rawEntry
171
+ ? String(rawEntry.string || '')
172
+ : '';
173
+ if (!str) {
174
+ continue;
175
+ }
176
+ const cargoMatch = str.match(/cargo[\\/](?:registry[\\/]src|git[\\/]checkouts)[^\r\n]*/i);
177
+ if (cargoMatch?.[0]) {
178
+ cargoPaths.push(cargoMatch[0]);
179
+ const crateName = extractCrateNameFromCargoPath(cargoMatch[0]);
180
+ if (crateName) {
181
+ crateNames.push(crateName);
182
+ }
183
+ }
184
+ if (/rust_panic|core::panicking|panic_unwind|alloc::|std::rt|rustc|\\src\\main\.rs|\\src\\lib\.rs/i.test(str)) {
185
+ rustMarkers.push(str);
186
+ }
187
+ if (/tokio|async|futures|mio|spawn_blocking|joinhandle|reactor/i.test(str)) {
188
+ asyncRuntimeMarkers.push(str);
189
+ }
190
+ if (/panic|panicking|assertion failed|unwrap failed|expect failed/i.test(str)) {
191
+ panicMarkers.push(str);
192
+ }
193
+ libraryHints.push(...detectLibraryHints(str));
194
+ }
195
+ return {
196
+ cargoPaths: uniqueStrings(cargoPaths),
197
+ rustMarkers: uniqueStrings(rustMarkers),
198
+ asyncRuntimeMarkers: uniqueStrings(asyncRuntimeMarkers),
199
+ panicMarkers: uniqueStrings(panicMarkers),
200
+ crateNames: uniqueStrings(crateNames),
201
+ libraryHints: uniqueStrings(libraryHints),
202
+ };
203
+ }
204
+ function buildRustConfidence(options) {
205
+ let score = 0.08;
206
+ if (options.runtimeHints.some((item) => item.toLowerCase().includes('rust')))
207
+ score += 0.28;
208
+ if (options.cargoPaths.length > 0)
209
+ score += 0.2;
210
+ if (options.rustMarkers.length > 0)
211
+ score += 0.17;
212
+ if (options.crateHints.length > 0)
213
+ score += 0.15;
214
+ if (options.recoveredFunctionCount > 0)
215
+ score += 0.06;
216
+ if (options.recoveredSymbolCount > 0)
217
+ score += 0.06;
218
+ return clamp(score);
219
+ }
220
+ export function createRustBinaryAnalyzeHandler(workspaceManager, database, cacheManager, dependencies = {}) {
221
+ const runtimeHandler = dependencies.runtimeHandler || createRuntimeDetectHandler(workspaceManager, database, cacheManager);
222
+ const stringsHandler = dependencies.stringsHandler || createStringsExtractHandler(workspaceManager, database, cacheManager);
223
+ const smartRecoverHandler = dependencies.smartRecoverHandler ||
224
+ createCodeFunctionsSmartRecoverHandler(workspaceManager, database, cacheManager);
225
+ const symbolsRecoverHandler = dependencies.symbolsRecoverHandler ||
226
+ createPESymbolsRecoverHandler(workspaceManager, database, cacheManager);
227
+ const binaryRoleHandler = dependencies.binaryRoleHandler ||
228
+ createBinaryRoleProfileHandler(workspaceManager, database, cacheManager);
229
+ return async (args) => {
230
+ const input = rustBinaryAnalyzeInputSchema.parse(args);
231
+ const startTime = Date.now();
232
+ try {
233
+ const sample = database.findSample(input.sample_id);
234
+ if (!sample) {
235
+ return {
236
+ ok: false,
237
+ errors: [`Sample not found: ${input.sample_id}`],
238
+ metrics: {
239
+ elapsed_ms: Date.now() - startTime,
240
+ tool: TOOL_NAME,
241
+ },
242
+ };
243
+ }
244
+ const cacheKey = generateCacheKey({
245
+ sampleSha256: sample.sha256,
246
+ toolName: TOOL_NAME,
247
+ toolVersion: TOOL_VERSION,
248
+ args: {
249
+ max_strings: input.max_strings,
250
+ max_symbol_preview: input.max_symbol_preview,
251
+ },
252
+ });
253
+ if (!input.force_refresh) {
254
+ const cachedLookup = await lookupCachedResult(cacheManager, cacheKey);
255
+ if (cachedLookup) {
256
+ return {
257
+ ok: true,
258
+ data: cachedLookup.data,
259
+ warnings: ['Result from cache', formatCacheWarning(cachedLookup.metadata)],
260
+ metrics: {
261
+ elapsed_ms: Date.now() - startTime,
262
+ tool: TOOL_NAME,
263
+ },
264
+ };
265
+ }
266
+ }
267
+ const [runtimeResult, stringsResult, smartRecoverResult, symbolsRecoverResult, binaryRoleResult] = await Promise.all([
268
+ runtimeHandler({ sample_id: input.sample_id, force_refresh: input.force_refresh }),
269
+ stringsHandler({
270
+ sample_id: input.sample_id,
271
+ category_filter: 'all',
272
+ max_strings: input.max_strings,
273
+ force_refresh: input.force_refresh,
274
+ }),
275
+ smartRecoverHandler({ sample_id: input.sample_id, force_refresh: input.force_refresh }),
276
+ symbolsRecoverHandler({
277
+ sample_id: input.sample_id,
278
+ max_string_hints: input.max_strings,
279
+ force_refresh: input.force_refresh,
280
+ }),
281
+ binaryRoleHandler({ sample_id: input.sample_id, max_strings: input.max_strings, force_refresh: input.force_refresh }),
282
+ ]);
283
+ const componentStatus = {
284
+ runtime_detect: {
285
+ ok: runtimeResult.ok,
286
+ warning_count: runtimeResult.warnings?.length || 0,
287
+ error_count: runtimeResult.errors?.length || 0,
288
+ },
289
+ strings_extract: {
290
+ ok: stringsResult.ok,
291
+ warning_count: stringsResult.warnings?.length || 0,
292
+ error_count: stringsResult.errors?.length || 0,
293
+ },
294
+ smart_recover: {
295
+ ok: smartRecoverResult.ok,
296
+ warning_count: smartRecoverResult.warnings?.length || 0,
297
+ error_count: smartRecoverResult.errors?.length || 0,
298
+ },
299
+ symbols_recover: {
300
+ ok: symbolsRecoverResult.ok,
301
+ warning_count: symbolsRecoverResult.warnings?.length || 0,
302
+ error_count: symbolsRecoverResult.errors?.length || 0,
303
+ },
304
+ binary_role_profile: {
305
+ ok: binaryRoleResult.ok,
306
+ warning_count: binaryRoleResult.warnings?.length || 0,
307
+ error_count: binaryRoleResult.errors?.length || 0,
308
+ },
309
+ };
310
+ const warnings = [
311
+ ...(runtimeResult.warnings || []).map((item) => `runtime: ${item}`),
312
+ ...(runtimeResult.ok ? [] : (runtimeResult.errors || []).map((item) => `runtime error: ${item}`)),
313
+ ...(stringsResult.warnings || []).map((item) => `strings: ${item}`),
314
+ ...(stringsResult.ok ? [] : (stringsResult.errors || []).map((item) => `strings error: ${item}`)),
315
+ ...(smartRecoverResult.warnings || []).map((item) => `smart_recover: ${item}`),
316
+ ...(smartRecoverResult.ok
317
+ ? []
318
+ : (smartRecoverResult.errors || []).map((item) => `smart_recover error: ${item}`)),
319
+ ...(symbolsRecoverResult.warnings || []).map((item) => `symbols_recover: ${item}`),
320
+ ...(symbolsRecoverResult.ok
321
+ ? []
322
+ : (symbolsRecoverResult.errors || []).map((item) => `symbols_recover error: ${item}`)),
323
+ ...(binaryRoleResult.warnings || []).map((item) => `binary_role: ${item}`),
324
+ ...(binaryRoleResult.ok
325
+ ? []
326
+ : (binaryRoleResult.errors || []).map((item) => `binary_role error: ${item}`)),
327
+ ];
328
+ const runtimeData = (runtimeResult.ok ? runtimeResult.data : undefined);
329
+ const stringsData = (stringsResult.ok ? stringsResult.data : undefined);
330
+ const smartRecoverData = (smartRecoverResult.ok ? smartRecoverResult.data : undefined);
331
+ const symbolsData = (symbolsRecoverResult.ok ? symbolsRecoverResult.data : undefined);
332
+ const binaryProfile = binaryRoleResult.ok ? binaryRoleResult.data : undefined;
333
+ const rawStrings = stringsData?.strings || [];
334
+ const stringAnalysis = analyzeRustStrings(rawStrings);
335
+ const libraryProfile = buildLibraryProfile({
336
+ cargoPaths: stringAnalysis.cargoPaths,
337
+ crateNames: stringAnalysis.crateNames,
338
+ libraryHints: stringAnalysis.libraryHints,
339
+ rustMarkers: stringAnalysis.rustMarkers,
340
+ }, runtimeData || {});
341
+ const runtimeHints = uniqueStrings([
342
+ ...(runtimeData?.suspected || []).map((item) => item.runtime),
343
+ ...(symbolsData?.runtime_hints || []),
344
+ ...(libraryProfile?.ecosystems || []),
345
+ ]);
346
+ const crateHints = uniqueStrings([
347
+ ...(symbolsData?.crate_hints || []),
348
+ ...stringAnalysis.crateNames,
349
+ ...(libraryProfile?.top_crates || []),
350
+ ]);
351
+ const recoveredFunctionCount = smartRecoverData?.count || 0;
352
+ const recoveredFunctionStrategy = smartRecoverData?.strategy || [];
353
+ const recoveredSymbolCount = symbolsData?.count || 0;
354
+ const recoveredSymbolPreview = (symbolsData?.symbols || []).slice(0, input.max_symbol_preview);
355
+ const confidence = buildRustConfidence({
356
+ runtimeHints,
357
+ cargoPaths: stringAnalysis.cargoPaths,
358
+ rustMarkers: stringAnalysis.rustMarkers,
359
+ crateHints,
360
+ recoveredFunctionCount,
361
+ recoveredSymbolCount,
362
+ });
363
+ const suspectedRust = confidence >= 0.42;
364
+ const evidence = uniqueStrings([
365
+ ...(runtimeData?.suspected || [])
366
+ .filter((item) => item.runtime.toLowerCase().includes('rust'))
367
+ .flatMap((item) => item.evidence || []),
368
+ ...stringAnalysis.cargoPaths.slice(0, 3).map((item) => `Cargo path: ${item}`),
369
+ ...stringAnalysis.rustMarkers.slice(0, 3).map((item) => `Rust marker: ${item}`),
370
+ ...stringAnalysis.asyncRuntimeMarkers.slice(0, 2).map((item) => `Async/runtime marker: ${item}`),
371
+ ...stringAnalysis.panicMarkers.slice(0, 2).map((item) => `Panic marker: ${item}`),
372
+ ...((libraryProfile?.evidence || []).slice(0, 3)),
373
+ ...(recoveredSymbolPreview.slice(0, 3).map((item) => `Recovered symbol: ${item.recovered_name}`)),
374
+ ]);
375
+ const analysisPriorities = uniqueStrings([
376
+ ...(binaryProfile?.analysis_priorities || []),
377
+ recoveredFunctionCount > 0 ? 'feed_recovered_boundaries_into_code.functions.define' : '',
378
+ recoveredSymbolCount > 0 ? 'review_recovered_symbol_names_before_manual_validation' : '',
379
+ stringAnalysis.asyncRuntimeMarkers.length > 0 ? 'trace_async_runtime_and_scheduler_paths' : '',
380
+ stringAnalysis.panicMarkers.length > 0 ? 'separate_panic_paths_from_primary_business_logic' : '',
381
+ crateHints.includes('tokio') || crateHints.includes('mio')
382
+ ? 'trace_runtime_bootstrap_and_async_task_dispatch'
383
+ : '',
384
+ crateHints.includes('goblin') || crateHints.includes('iced-x86')
385
+ ? 'review_binary_parsing_and_disassembly_modules_first'
386
+ : '',
387
+ ]).filter(Boolean);
388
+ const nextSteps = uniqueStrings([
389
+ recoveredFunctionCount > 0
390
+ ? 'Use code.functions.define with source=smart_recover or symbols_recover to materialize the recovered function index.'
391
+ : 'Use pe.pdata.extract to inspect the PE exception directory directly if function recovery remains empty.',
392
+ 'Run ghidra.analyze with options.language_id / options.cspec / options.script_paths when Rust auto-detection under-identifies functions.',
393
+ recoveredSymbolCount > 0
394
+ ? 'Use code.functions.define with recovered_name values to preserve recovered symbol names before reconstruct/export.'
395
+ : 'Run pe.symbols.recover after strings extraction to derive more descriptive recovered names.',
396
+ ]);
397
+ const payload = {
398
+ sample_id: input.sample_id,
399
+ suspected_rust: suspectedRust,
400
+ confidence,
401
+ primary_runtime: symbolsData?.primary_runtime || runtimeHints[0] || null,
402
+ runtime_hints: runtimeHints,
403
+ cargo_paths: stringAnalysis.cargoPaths,
404
+ rust_markers: stringAnalysis.rustMarkers,
405
+ async_runtime_markers: stringAnalysis.asyncRuntimeMarkers,
406
+ panic_markers: stringAnalysis.panicMarkers,
407
+ crate_hints: crateHints,
408
+ library_profile: libraryProfile,
409
+ binary_profile: binaryProfile,
410
+ recovered_function_count: recoveredFunctionCount,
411
+ recovered_function_strategy: recoveredFunctionStrategy,
412
+ recovered_symbol_count: recoveredSymbolCount,
413
+ recovered_symbol_preview: recoveredSymbolPreview,
414
+ components: componentStatus,
415
+ importable_with_code_functions_define: recoveredFunctionCount > 0 || recoveredSymbolCount > 0,
416
+ evidence,
417
+ analysis_priorities: analysisPriorities,
418
+ next_steps: nextSteps,
419
+ };
420
+ await cacheManager.setCachedResult(cacheKey, payload, CACHE_TTL_MS, sample.sha256);
421
+ return {
422
+ ok: true,
423
+ data: payload,
424
+ warnings: warnings.length > 0 ? warnings : undefined,
425
+ metrics: {
426
+ elapsed_ms: Date.now() - startTime,
427
+ tool: TOOL_NAME,
428
+ },
429
+ };
430
+ }
431
+ catch (error) {
432
+ return {
433
+ ok: false,
434
+ errors: [error instanceof Error ? error.message : String(error)],
435
+ metrics: {
436
+ elapsed_ms: Date.now() - startTime,
437
+ tool: TOOL_NAME,
438
+ },
439
+ };
440
+ }
441
+ };
442
+ }
443
+ //# sourceMappingURL=rust-binary-analyze.js.map
@@ -1,14 +1,12 @@
1
1
  /**
2
2
  * sample.profile.get tool implementation
3
- * Retrieves sample profile including basic information and completed analyses
4
- * Requirements: Data Model
3
+ * Retrieves sample profile including basic information, completed analyses,
4
+ * and workspace/original integrity status.
5
5
  */
6
6
  import { z } from 'zod';
7
7
  import type { ToolDefinition, ToolArgs, WorkerResult } from '../types.js';
8
8
  import type { DatabaseManager } from '../database.js';
9
- /**
10
- * Input schema for sample.profile.get tool
11
- */
9
+ import type { WorkspaceManager } from '../workspace-manager.js';
12
10
  export declare const SampleProfileGetInputSchema: z.ZodObject<{
13
11
  sample_id: z.ZodString;
14
12
  stale_running_ms: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
@@ -20,9 +18,6 @@ export declare const SampleProfileGetInputSchema: z.ZodObject<{
20
18
  stale_running_ms?: number | null | undefined;
21
19
  }>;
22
20
  export type SampleProfileGetInput = z.infer<typeof SampleProfileGetInputSchema>;
23
- /**
24
- * Output schema for sample.profile.get tool
25
- */
26
21
  export declare const SampleProfileGetOutputSchema: z.ZodObject<{
27
22
  ok: z.ZodBoolean;
28
23
  data: z.ZodOptional<z.ZodObject<{
@@ -79,6 +74,61 @@ export declare const SampleProfileGetOutputSchema: z.ZodObject<{
79
74
  output_json?: string | undefined;
80
75
  metrics_json?: string | undefined;
81
76
  }>, "many">;
77
+ workspace: z.ZodOptional<z.ZodObject<{
78
+ status: z.ZodEnum<["ready", "workspace_missing", "original_dir_missing", "original_file_missing"]>;
79
+ workspace_root: z.ZodNullable<z.ZodString>;
80
+ original_dir: z.ZodNullable<z.ZodString>;
81
+ reports_dir: z.ZodNullable<z.ZodString>;
82
+ ghidra_dir: z.ZodNullable<z.ZodString>;
83
+ workspace_exists: z.ZodBoolean;
84
+ original_dir_exists: z.ZodBoolean;
85
+ reports_dir_exists: z.ZodBoolean;
86
+ ghidra_dir_exists: z.ZodBoolean;
87
+ original_present: z.ZodBoolean;
88
+ original_file_count: z.ZodNumber;
89
+ original_files: z.ZodArray<z.ZodString, "many">;
90
+ alternate_workspace_root: z.ZodNullable<z.ZodString>;
91
+ alternate_original_dir: z.ZodNullable<z.ZodString>;
92
+ alternate_original_present: z.ZodBoolean;
93
+ alternate_original_files: z.ZodArray<z.ZodString, "many">;
94
+ remediation: z.ZodArray<z.ZodString, "many">;
95
+ }, "strip", z.ZodTypeAny, {
96
+ status: "ready" | "workspace_missing" | "original_dir_missing" | "original_file_missing";
97
+ workspace_root: string | null;
98
+ original_dir: string | null;
99
+ reports_dir: string | null;
100
+ ghidra_dir: string | null;
101
+ workspace_exists: boolean;
102
+ original_dir_exists: boolean;
103
+ reports_dir_exists: boolean;
104
+ ghidra_dir_exists: boolean;
105
+ original_file_count: number;
106
+ original_files: string[];
107
+ alternate_workspace_root: string | null;
108
+ alternate_original_dir: string | null;
109
+ alternate_original_files: string[];
110
+ original_present: boolean;
111
+ alternate_original_present: boolean;
112
+ remediation: string[];
113
+ }, {
114
+ status: "ready" | "workspace_missing" | "original_dir_missing" | "original_file_missing";
115
+ workspace_root: string | null;
116
+ original_dir: string | null;
117
+ reports_dir: string | null;
118
+ ghidra_dir: string | null;
119
+ workspace_exists: boolean;
120
+ original_dir_exists: boolean;
121
+ reports_dir_exists: boolean;
122
+ ghidra_dir_exists: boolean;
123
+ original_file_count: number;
124
+ original_files: string[];
125
+ alternate_workspace_root: string | null;
126
+ alternate_original_dir: string | null;
127
+ alternate_original_files: string[];
128
+ original_present: boolean;
129
+ alternate_original_present: boolean;
130
+ remediation: string[];
131
+ }>>;
82
132
  }, "strip", z.ZodTypeAny, {
83
133
  sample: {
84
134
  id: string;
@@ -99,6 +149,25 @@ export declare const SampleProfileGetOutputSchema: z.ZodObject<{
99
149
  output_json?: string | undefined;
100
150
  metrics_json?: string | undefined;
101
151
  }[];
152
+ workspace?: {
153
+ status: "ready" | "workspace_missing" | "original_dir_missing" | "original_file_missing";
154
+ workspace_root: string | null;
155
+ original_dir: string | null;
156
+ reports_dir: string | null;
157
+ ghidra_dir: string | null;
158
+ workspace_exists: boolean;
159
+ original_dir_exists: boolean;
160
+ reports_dir_exists: boolean;
161
+ ghidra_dir_exists: boolean;
162
+ original_file_count: number;
163
+ original_files: string[];
164
+ alternate_workspace_root: string | null;
165
+ alternate_original_dir: string | null;
166
+ alternate_original_files: string[];
167
+ original_present: boolean;
168
+ alternate_original_present: boolean;
169
+ remediation: string[];
170
+ } | undefined;
102
171
  }, {
103
172
  sample: {
104
173
  id: string;
@@ -119,6 +188,25 @@ export declare const SampleProfileGetOutputSchema: z.ZodObject<{
119
188
  output_json?: string | undefined;
120
189
  metrics_json?: string | undefined;
121
190
  }[];
191
+ workspace?: {
192
+ status: "ready" | "workspace_missing" | "original_dir_missing" | "original_file_missing";
193
+ workspace_root: string | null;
194
+ original_dir: string | null;
195
+ reports_dir: string | null;
196
+ ghidra_dir: string | null;
197
+ workspace_exists: boolean;
198
+ original_dir_exists: boolean;
199
+ reports_dir_exists: boolean;
200
+ ghidra_dir_exists: boolean;
201
+ original_file_count: number;
202
+ original_files: string[];
203
+ alternate_workspace_root: string | null;
204
+ alternate_original_dir: string | null;
205
+ alternate_original_files: string[];
206
+ original_present: boolean;
207
+ alternate_original_present: boolean;
208
+ remediation: string[];
209
+ } | undefined;
122
210
  }>>;
123
211
  errors: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
124
212
  }, "strip", z.ZodTypeAny, {
@@ -143,6 +231,25 @@ export declare const SampleProfileGetOutputSchema: z.ZodObject<{
143
231
  output_json?: string | undefined;
144
232
  metrics_json?: string | undefined;
145
233
  }[];
234
+ workspace?: {
235
+ status: "ready" | "workspace_missing" | "original_dir_missing" | "original_file_missing";
236
+ workspace_root: string | null;
237
+ original_dir: string | null;
238
+ reports_dir: string | null;
239
+ ghidra_dir: string | null;
240
+ workspace_exists: boolean;
241
+ original_dir_exists: boolean;
242
+ reports_dir_exists: boolean;
243
+ ghidra_dir_exists: boolean;
244
+ original_file_count: number;
245
+ original_files: string[];
246
+ alternate_workspace_root: string | null;
247
+ alternate_original_dir: string | null;
248
+ alternate_original_files: string[];
249
+ original_present: boolean;
250
+ alternate_original_present: boolean;
251
+ remediation: string[];
252
+ } | undefined;
146
253
  } | undefined;
147
254
  errors?: string[] | undefined;
148
255
  }, {
@@ -167,17 +274,29 @@ export declare const SampleProfileGetOutputSchema: z.ZodObject<{
167
274
  output_json?: string | undefined;
168
275
  metrics_json?: string | undefined;
169
276
  }[];
277
+ workspace?: {
278
+ status: "ready" | "workspace_missing" | "original_dir_missing" | "original_file_missing";
279
+ workspace_root: string | null;
280
+ original_dir: string | null;
281
+ reports_dir: string | null;
282
+ ghidra_dir: string | null;
283
+ workspace_exists: boolean;
284
+ original_dir_exists: boolean;
285
+ reports_dir_exists: boolean;
286
+ ghidra_dir_exists: boolean;
287
+ original_file_count: number;
288
+ original_files: string[];
289
+ alternate_workspace_root: string | null;
290
+ alternate_original_dir: string | null;
291
+ alternate_original_files: string[];
292
+ original_present: boolean;
293
+ alternate_original_present: boolean;
294
+ remediation: string[];
295
+ } | undefined;
170
296
  } | undefined;
171
297
  errors?: string[] | undefined;
172
298
  }>;
173
299
  export type SampleProfileGetOutput = z.infer<typeof SampleProfileGetOutputSchema>;
174
- /**
175
- * Tool definition for sample.profile.get
176
- */
177
300
  export declare const sampleProfileGetToolDefinition: ToolDefinition;
178
- /**
179
- * Create sample.profile.get tool handler
180
- * Requirements: Data Model
181
- */
182
- export declare function createSampleProfileGetHandler(database: DatabaseManager): (args: ToolArgs) => Promise<WorkerResult>;
301
+ export declare function createSampleProfileGetHandler(database: DatabaseManager, workspaceManager?: WorkspaceManager): (args: ToolArgs) => Promise<WorkerResult>;
183
302
  //# sourceMappingURL=sample-profile-get.d.ts.map