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.
Files changed (190) hide show
  1. package/CODEX_INSTALLATION.md +69 -0
  2. package/COPILOT_INSTALLATION.md +77 -0
  3. package/LICENSE +21 -0
  4. package/README.md +314 -0
  5. package/bin/windows-exe-decompiler-mcp-server.js +3 -0
  6. package/dist/analysis-provenance.d.ts +184 -0
  7. package/dist/analysis-provenance.js +74 -0
  8. package/dist/analysis-task-runner.d.ts +31 -0
  9. package/dist/analysis-task-runner.js +160 -0
  10. package/dist/artifact-inventory.d.ts +23 -0
  11. package/dist/artifact-inventory.js +175 -0
  12. package/dist/cache-manager.d.ts +128 -0
  13. package/dist/cache-manager.js +454 -0
  14. package/dist/confidence-semantics.d.ts +66 -0
  15. package/dist/confidence-semantics.js +122 -0
  16. package/dist/config.d.ts +335 -0
  17. package/dist/config.js +193 -0
  18. package/dist/database.d.ts +227 -0
  19. package/dist/database.js +601 -0
  20. package/dist/decompiler-worker.d.ts +441 -0
  21. package/dist/decompiler-worker.js +1962 -0
  22. package/dist/dynamic-trace.d.ts +95 -0
  23. package/dist/dynamic-trace.js +629 -0
  24. package/dist/env-validator.d.ts +15 -0
  25. package/dist/env-validator.js +249 -0
  26. package/dist/error-handler.d.ts +28 -0
  27. package/dist/error-handler.example.d.ts +22 -0
  28. package/dist/error-handler.example.js +141 -0
  29. package/dist/error-handler.js +139 -0
  30. package/dist/ghidra-analysis-status.d.ts +49 -0
  31. package/dist/ghidra-analysis-status.js +178 -0
  32. package/dist/ghidra-config.d.ts +134 -0
  33. package/dist/ghidra-config.js +464 -0
  34. package/dist/index.d.ts +9 -0
  35. package/dist/index.js +200 -0
  36. package/dist/job-queue.d.ts +169 -0
  37. package/dist/job-queue.js +407 -0
  38. package/dist/logger.d.ts +106 -0
  39. package/dist/logger.js +176 -0
  40. package/dist/policy-guard.d.ts +115 -0
  41. package/dist/policy-guard.js +243 -0
  42. package/dist/process-output.d.ts +15 -0
  43. package/dist/process-output.js +90 -0
  44. package/dist/prompts/function-explanation-review.d.ts +5 -0
  45. package/dist/prompts/function-explanation-review.js +64 -0
  46. package/dist/prompts/semantic-name-review.d.ts +5 -0
  47. package/dist/prompts/semantic-name-review.js +63 -0
  48. package/dist/runtime-correlation.d.ts +34 -0
  49. package/dist/runtime-correlation.js +279 -0
  50. package/dist/runtime-paths.d.ts +3 -0
  51. package/dist/runtime-paths.js +11 -0
  52. package/dist/selection-diff.d.ts +667 -0
  53. package/dist/selection-diff.js +53 -0
  54. package/dist/semantic-name-suggestion-artifacts.d.ts +116 -0
  55. package/dist/semantic-name-suggestion-artifacts.js +314 -0
  56. package/dist/server.d.ts +129 -0
  57. package/dist/server.js +578 -0
  58. package/dist/tools/artifact-read.d.ts +235 -0
  59. package/dist/tools/artifact-read.js +317 -0
  60. package/dist/tools/artifacts-diff.d.ts +728 -0
  61. package/dist/tools/artifacts-diff.js +304 -0
  62. package/dist/tools/artifacts-list.d.ts +515 -0
  63. package/dist/tools/artifacts-list.js +389 -0
  64. package/dist/tools/attack-map.d.ts +290 -0
  65. package/dist/tools/attack-map.js +519 -0
  66. package/dist/tools/cache-observability.d.ts +4 -0
  67. package/dist/tools/cache-observability.js +36 -0
  68. package/dist/tools/code-function-cfg.d.ts +50 -0
  69. package/dist/tools/code-function-cfg.js +102 -0
  70. package/dist/tools/code-function-decompile.d.ts +55 -0
  71. package/dist/tools/code-function-decompile.js +103 -0
  72. package/dist/tools/code-function-disassemble.d.ts +43 -0
  73. package/dist/tools/code-function-disassemble.js +185 -0
  74. package/dist/tools/code-function-explain-apply.d.ts +255 -0
  75. package/dist/tools/code-function-explain-apply.js +225 -0
  76. package/dist/tools/code-function-explain-prepare.d.ts +535 -0
  77. package/dist/tools/code-function-explain-prepare.js +276 -0
  78. package/dist/tools/code-function-explain-review.d.ts +397 -0
  79. package/dist/tools/code-function-explain-review.js +589 -0
  80. package/dist/tools/code-function-rename-apply.d.ts +248 -0
  81. package/dist/tools/code-function-rename-apply.js +220 -0
  82. package/dist/tools/code-function-rename-prepare.d.ts +506 -0
  83. package/dist/tools/code-function-rename-prepare.js +279 -0
  84. package/dist/tools/code-function-rename-review.d.ts +574 -0
  85. package/dist/tools/code-function-rename-review.js +761 -0
  86. package/dist/tools/code-functions-list.d.ts +37 -0
  87. package/dist/tools/code-functions-list.js +91 -0
  88. package/dist/tools/code-functions-rank.d.ts +34 -0
  89. package/dist/tools/code-functions-rank.js +90 -0
  90. package/dist/tools/code-functions-reconstruct.d.ts +2725 -0
  91. package/dist/tools/code-functions-reconstruct.js +2807 -0
  92. package/dist/tools/code-functions-search.d.ts +39 -0
  93. package/dist/tools/code-functions-search.js +90 -0
  94. package/dist/tools/code-reconstruct-export.d.ts +1212 -0
  95. package/dist/tools/code-reconstruct-export.js +4002 -0
  96. package/dist/tools/code-reconstruct-plan.d.ts +274 -0
  97. package/dist/tools/code-reconstruct-plan.js +342 -0
  98. package/dist/tools/dotnet-metadata-extract.d.ts +541 -0
  99. package/dist/tools/dotnet-metadata-extract.js +355 -0
  100. package/dist/tools/dotnet-reconstruct-export.d.ts +567 -0
  101. package/dist/tools/dotnet-reconstruct-export.js +1151 -0
  102. package/dist/tools/dotnet-types-list.d.ts +325 -0
  103. package/dist/tools/dotnet-types-list.js +201 -0
  104. package/dist/tools/dynamic-dependencies.d.ts +115 -0
  105. package/dist/tools/dynamic-dependencies.js +213 -0
  106. package/dist/tools/dynamic-memory-import.d.ts +10 -0
  107. package/dist/tools/dynamic-memory-import.js +567 -0
  108. package/dist/tools/dynamic-trace-import.d.ts +10 -0
  109. package/dist/tools/dynamic-trace-import.js +235 -0
  110. package/dist/tools/entrypoint-fallback-disasm.d.ts +30 -0
  111. package/dist/tools/entrypoint-fallback-disasm.js +89 -0
  112. package/dist/tools/ghidra-analyze.d.ts +88 -0
  113. package/dist/tools/ghidra-analyze.js +208 -0
  114. package/dist/tools/ghidra-health.d.ts +37 -0
  115. package/dist/tools/ghidra-health.js +212 -0
  116. package/dist/tools/ioc-export.d.ts +209 -0
  117. package/dist/tools/ioc-export.js +542 -0
  118. package/dist/tools/packer-detect.d.ts +165 -0
  119. package/dist/tools/packer-detect.js +284 -0
  120. package/dist/tools/pe-exports-extract.d.ts +175 -0
  121. package/dist/tools/pe-exports-extract.js +253 -0
  122. package/dist/tools/pe-fingerprint.d.ts +234 -0
  123. package/dist/tools/pe-fingerprint.js +269 -0
  124. package/dist/tools/pe-imports-extract.d.ts +105 -0
  125. package/dist/tools/pe-imports-extract.js +245 -0
  126. package/dist/tools/report-generate.d.ts +157 -0
  127. package/dist/tools/report-generate.js +457 -0
  128. package/dist/tools/report-summarize.d.ts +2131 -0
  129. package/dist/tools/report-summarize.js +596 -0
  130. package/dist/tools/runtime-detect.d.ts +135 -0
  131. package/dist/tools/runtime-detect.js +247 -0
  132. package/dist/tools/sample-ingest.d.ts +94 -0
  133. package/dist/tools/sample-ingest.js +327 -0
  134. package/dist/tools/sample-profile-get.d.ts +183 -0
  135. package/dist/tools/sample-profile-get.js +121 -0
  136. package/dist/tools/sandbox-execute.d.ts +441 -0
  137. package/dist/tools/sandbox-execute.js +392 -0
  138. package/dist/tools/strings-extract.d.ts +375 -0
  139. package/dist/tools/strings-extract.js +314 -0
  140. package/dist/tools/strings-floss-decode.d.ts +143 -0
  141. package/dist/tools/strings-floss-decode.js +259 -0
  142. package/dist/tools/system-health.d.ts +434 -0
  143. package/dist/tools/system-health.js +446 -0
  144. package/dist/tools/task-cancel.d.ts +21 -0
  145. package/dist/tools/task-cancel.js +70 -0
  146. package/dist/tools/task-status.d.ts +27 -0
  147. package/dist/tools/task-status.js +106 -0
  148. package/dist/tools/task-sweep.d.ts +22 -0
  149. package/dist/tools/task-sweep.js +77 -0
  150. package/dist/tools/tool-help.d.ts +340 -0
  151. package/dist/tools/tool-help.js +261 -0
  152. package/dist/tools/yara-scan.d.ts +554 -0
  153. package/dist/tools/yara-scan.js +313 -0
  154. package/dist/types.d.ts +266 -0
  155. package/dist/types.js +41 -0
  156. package/dist/worker-pool.d.ts +204 -0
  157. package/dist/worker-pool.js +650 -0
  158. package/dist/workflows/deep-static.d.ts +104 -0
  159. package/dist/workflows/deep-static.js +276 -0
  160. package/dist/workflows/function-explanation-review.d.ts +655 -0
  161. package/dist/workflows/function-explanation-review.js +440 -0
  162. package/dist/workflows/reconstruct.d.ts +2053 -0
  163. package/dist/workflows/reconstruct.js +666 -0
  164. package/dist/workflows/semantic-name-review.d.ts +2418 -0
  165. package/dist/workflows/semantic-name-review.js +521 -0
  166. package/dist/workflows/triage.d.ts +659 -0
  167. package/dist/workflows/triage.js +1374 -0
  168. package/dist/workspace-manager.d.ts +150 -0
  169. package/dist/workspace-manager.js +411 -0
  170. package/ghidra_scripts/DecompileFunction.java +487 -0
  171. package/ghidra_scripts/DecompileFunction.py +150 -0
  172. package/ghidra_scripts/ExtractCFG.java +256 -0
  173. package/ghidra_scripts/ExtractCFG.py +233 -0
  174. package/ghidra_scripts/ExtractFunctions.java +442 -0
  175. package/ghidra_scripts/ExtractFunctions.py +101 -0
  176. package/ghidra_scripts/README.md +125 -0
  177. package/ghidra_scripts/SearchFunctionReferences.java +380 -0
  178. package/helpers/DotNetMetadataProbe/DotNetMetadataProbe.csproj +9 -0
  179. package/helpers/DotNetMetadataProbe/Program.cs +566 -0
  180. package/install-to-codex.ps1 +178 -0
  181. package/install-to-copilot.ps1 +303 -0
  182. package/package.json +101 -0
  183. package/requirements.txt +9 -0
  184. package/workers/requirements-dynamic.txt +11 -0
  185. package/workers/requirements.txt +8 -0
  186. package/workers/speakeasy_compat.py +175 -0
  187. package/workers/static_worker.py +5183 -0
  188. package/workers/yara_rules/default.yar +33 -0
  189. package/workers/yara_rules/malware_families.yar +93 -0
  190. package/workers/yara_rules/packers.yar +80 -0
@@ -0,0 +1,157 @@
1
+ /**
2
+ * report.generate MCP Tool
3
+ *
4
+ * Requirements: 24.1, 24.3, 24.5, 24.6
5
+ *
6
+ * Generates comprehensive Markdown analysis report
7
+ */
8
+ import { z } from 'zod';
9
+ import type { ToolDefinition, ToolHandler } from '../types.js';
10
+ import type { DatabaseManager } from '../database.js';
11
+ import type { WorkspaceManager } from '../workspace-manager.js';
12
+ /**
13
+ * Input schema for report.generate tool
14
+ */
15
+ export declare const reportGenerateInputSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.ZodEffects<z.ZodObject<{
16
+ sample_id: z.ZodString;
17
+ format: z.ZodOptional<z.ZodEnum<["markdown", "json", "html"]>>;
18
+ include_sections: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
19
+ evidence_scope: z.ZodDefault<z.ZodOptional<z.ZodEnum<["all", "latest", "session"]>>>;
20
+ evidence_session_tag: z.ZodOptional<z.ZodString>;
21
+ semantic_scope: z.ZodDefault<z.ZodOptional<z.ZodEnum<["all", "latest", "session"]>>>;
22
+ semantic_session_tag: z.ZodOptional<z.ZodString>;
23
+ compare_evidence_scope: z.ZodOptional<z.ZodEnum<["all", "latest", "session"]>>;
24
+ compare_evidence_session_tag: z.ZodOptional<z.ZodString>;
25
+ compare_semantic_scope: z.ZodOptional<z.ZodEnum<["all", "latest", "session"]>>;
26
+ compare_semantic_session_tag: z.ZodOptional<z.ZodString>;
27
+ }, "strip", z.ZodTypeAny, {
28
+ sample_id: string;
29
+ evidence_scope: "all" | "latest" | "session";
30
+ semantic_scope: "all" | "latest" | "session";
31
+ evidence_session_tag?: string | undefined;
32
+ semantic_session_tag?: string | undefined;
33
+ compare_evidence_scope?: "all" | "latest" | "session" | undefined;
34
+ compare_evidence_session_tag?: string | undefined;
35
+ compare_semantic_scope?: "all" | "latest" | "session" | undefined;
36
+ compare_semantic_session_tag?: string | undefined;
37
+ format?: "markdown" | "json" | "html" | undefined;
38
+ include_sections?: string[] | undefined;
39
+ }, {
40
+ sample_id: string;
41
+ evidence_scope?: "all" | "latest" | "session" | undefined;
42
+ evidence_session_tag?: string | undefined;
43
+ semantic_scope?: "all" | "latest" | "session" | undefined;
44
+ semantic_session_tag?: string | undefined;
45
+ compare_evidence_scope?: "all" | "latest" | "session" | undefined;
46
+ compare_evidence_session_tag?: string | undefined;
47
+ compare_semantic_scope?: "all" | "latest" | "session" | undefined;
48
+ compare_semantic_session_tag?: string | undefined;
49
+ format?: "markdown" | "json" | "html" | undefined;
50
+ include_sections?: string[] | undefined;
51
+ }>, {
52
+ sample_id: string;
53
+ evidence_scope: "all" | "latest" | "session";
54
+ semantic_scope: "all" | "latest" | "session";
55
+ evidence_session_tag?: string | undefined;
56
+ semantic_session_tag?: string | undefined;
57
+ compare_evidence_scope?: "all" | "latest" | "session" | undefined;
58
+ compare_evidence_session_tag?: string | undefined;
59
+ compare_semantic_scope?: "all" | "latest" | "session" | undefined;
60
+ compare_semantic_session_tag?: string | undefined;
61
+ format?: "markdown" | "json" | "html" | undefined;
62
+ include_sections?: string[] | undefined;
63
+ }, {
64
+ sample_id: string;
65
+ evidence_scope?: "all" | "latest" | "session" | undefined;
66
+ evidence_session_tag?: string | undefined;
67
+ semantic_scope?: "all" | "latest" | "session" | undefined;
68
+ semantic_session_tag?: string | undefined;
69
+ compare_evidence_scope?: "all" | "latest" | "session" | undefined;
70
+ compare_evidence_session_tag?: string | undefined;
71
+ compare_semantic_scope?: "all" | "latest" | "session" | undefined;
72
+ compare_semantic_session_tag?: string | undefined;
73
+ format?: "markdown" | "json" | "html" | undefined;
74
+ include_sections?: string[] | undefined;
75
+ }>, {
76
+ sample_id: string;
77
+ evidence_scope: "all" | "latest" | "session";
78
+ semantic_scope: "all" | "latest" | "session";
79
+ evidence_session_tag?: string | undefined;
80
+ semantic_session_tag?: string | undefined;
81
+ compare_evidence_scope?: "all" | "latest" | "session" | undefined;
82
+ compare_evidence_session_tag?: string | undefined;
83
+ compare_semantic_scope?: "all" | "latest" | "session" | undefined;
84
+ compare_semantic_session_tag?: string | undefined;
85
+ format?: "markdown" | "json" | "html" | undefined;
86
+ include_sections?: string[] | undefined;
87
+ }, {
88
+ sample_id: string;
89
+ evidence_scope?: "all" | "latest" | "session" | undefined;
90
+ evidence_session_tag?: string | undefined;
91
+ semantic_scope?: "all" | "latest" | "session" | undefined;
92
+ semantic_session_tag?: string | undefined;
93
+ compare_evidence_scope?: "all" | "latest" | "session" | undefined;
94
+ compare_evidence_session_tag?: string | undefined;
95
+ compare_semantic_scope?: "all" | "latest" | "session" | undefined;
96
+ compare_semantic_session_tag?: string | undefined;
97
+ format?: "markdown" | "json" | "html" | undefined;
98
+ include_sections?: string[] | undefined;
99
+ }>, {
100
+ sample_id: string;
101
+ evidence_scope: "all" | "latest" | "session";
102
+ semantic_scope: "all" | "latest" | "session";
103
+ evidence_session_tag?: string | undefined;
104
+ semantic_session_tag?: string | undefined;
105
+ compare_evidence_scope?: "all" | "latest" | "session" | undefined;
106
+ compare_evidence_session_tag?: string | undefined;
107
+ compare_semantic_scope?: "all" | "latest" | "session" | undefined;
108
+ compare_semantic_session_tag?: string | undefined;
109
+ format?: "markdown" | "json" | "html" | undefined;
110
+ include_sections?: string[] | undefined;
111
+ }, {
112
+ sample_id: string;
113
+ evidence_scope?: "all" | "latest" | "session" | undefined;
114
+ evidence_session_tag?: string | undefined;
115
+ semantic_scope?: "all" | "latest" | "session" | undefined;
116
+ semantic_session_tag?: string | undefined;
117
+ compare_evidence_scope?: "all" | "latest" | "session" | undefined;
118
+ compare_evidence_session_tag?: string | undefined;
119
+ compare_semantic_scope?: "all" | "latest" | "session" | undefined;
120
+ compare_semantic_session_tag?: string | undefined;
121
+ format?: "markdown" | "json" | "html" | undefined;
122
+ include_sections?: string[] | undefined;
123
+ }>, {
124
+ sample_id: string;
125
+ evidence_scope: "all" | "latest" | "session";
126
+ semantic_scope: "all" | "latest" | "session";
127
+ evidence_session_tag?: string | undefined;
128
+ semantic_session_tag?: string | undefined;
129
+ compare_evidence_scope?: "all" | "latest" | "session" | undefined;
130
+ compare_evidence_session_tag?: string | undefined;
131
+ compare_semantic_scope?: "all" | "latest" | "session" | undefined;
132
+ compare_semantic_session_tag?: string | undefined;
133
+ format?: "markdown" | "json" | "html" | undefined;
134
+ include_sections?: string[] | undefined;
135
+ }, {
136
+ sample_id: string;
137
+ evidence_scope?: "all" | "latest" | "session" | undefined;
138
+ evidence_session_tag?: string | undefined;
139
+ semantic_scope?: "all" | "latest" | "session" | undefined;
140
+ semantic_session_tag?: string | undefined;
141
+ compare_evidence_scope?: "all" | "latest" | "session" | undefined;
142
+ compare_evidence_session_tag?: string | undefined;
143
+ compare_semantic_scope?: "all" | "latest" | "session" | undefined;
144
+ compare_semantic_session_tag?: string | undefined;
145
+ format?: "markdown" | "json" | "html" | undefined;
146
+ include_sections?: string[] | undefined;
147
+ }>;
148
+ export type ReportGenerateInput = z.infer<typeof reportGenerateInputSchema>;
149
+ /**
150
+ * Tool definition for report.generate
151
+ */
152
+ export declare const reportGenerateToolDefinition: ToolDefinition;
153
+ /**
154
+ * Create handler for report.generate tool
155
+ */
156
+ export declare function createReportGenerateHandler(workspaceManager: WorkspaceManager, database: DatabaseManager): ToolHandler;
157
+ //# sourceMappingURL=report-generate.d.ts.map
@@ -0,0 +1,457 @@
1
+ /**
2
+ * report.generate MCP Tool
3
+ *
4
+ * Requirements: 24.1, 24.3, 24.5, 24.6
5
+ *
6
+ * Generates comprehensive Markdown analysis report
7
+ */
8
+ import { z } from 'zod';
9
+ import fs from 'fs';
10
+ import path from 'path';
11
+ import { createHash, randomUUID } from 'crypto';
12
+ import { logger } from '../logger.js';
13
+ import { isGhidraReadyStatus } from '../ghidra-analysis-status.js';
14
+ import { loadDynamicTraceEvidence } from '../dynamic-trace.js';
15
+ import { loadSemanticFunctionExplanationIndex } from '../semantic-name-suggestion-artifacts.js';
16
+ import { buildReportConfidenceSemantics } from '../confidence-semantics.js';
17
+ import { buildRuntimeArtifactProvenance, buildSemanticArtifactProvenance, } from '../analysis-provenance.js';
18
+ import { buildArtifactSelectionDiff, } from '../selection-diff.js';
19
+ /**
20
+ * Input schema for report.generate tool
21
+ */
22
+ export const reportGenerateInputSchema = z.object({
23
+ sample_id: z.string().describe('Sample identifier (sha256:<hex>)'),
24
+ format: z.enum(['markdown', 'json', 'html']).optional().describe('Report format (default: markdown)'),
25
+ include_sections: z.array(z.string()).optional().describe('Sections to include (default: all)'),
26
+ evidence_scope: z
27
+ .enum(['all', 'latest', 'session'])
28
+ .optional()
29
+ .default('all')
30
+ .describe('Runtime evidence scope: all artifacts, latest artifact window, or a specific session selector'),
31
+ evidence_session_tag: z
32
+ .string()
33
+ .optional()
34
+ .describe('Optional runtime evidence session selector used when evidence_scope=session or to narrow all/latest results'),
35
+ semantic_scope: z
36
+ .enum(['all', 'latest', 'session'])
37
+ .optional()
38
+ .default('all')
39
+ .describe('Semantic explanation artifact scope: all artifacts, latest explanation window, or a specific semantic review session'),
40
+ semantic_session_tag: z
41
+ .string()
42
+ .optional()
43
+ .describe('Optional semantic review session selector used when semantic_scope=session or to narrow all/latest results'),
44
+ compare_evidence_scope: z
45
+ .enum(['all', 'latest', 'session'])
46
+ .optional()
47
+ .describe('Optional baseline runtime evidence scope used to compare this report against another runtime artifact selection'),
48
+ compare_evidence_session_tag: z
49
+ .string()
50
+ .optional()
51
+ .describe('Optional baseline runtime evidence session selector used when compare_evidence_scope=session'),
52
+ compare_semantic_scope: z
53
+ .enum(['all', 'latest', 'session'])
54
+ .optional()
55
+ .describe('Optional baseline semantic explanation scope used to compare this report against another semantic artifact selection'),
56
+ compare_semantic_session_tag: z
57
+ .string()
58
+ .optional()
59
+ .describe('Optional baseline semantic explanation session selector used when compare_semantic_scope=session'),
60
+ }).refine((value) => value.evidence_scope !== 'session' || Boolean(value.evidence_session_tag?.trim()), {
61
+ message: 'evidence_session_tag is required when evidence_scope=session',
62
+ path: ['evidence_session_tag'],
63
+ }).refine((value) => value.semantic_scope !== 'session' || Boolean(value.semantic_session_tag?.trim()), {
64
+ message: 'semantic_session_tag is required when semantic_scope=session',
65
+ path: ['semantic_session_tag'],
66
+ }).refine((value) => value.compare_evidence_scope !== 'session' || Boolean(value.compare_evidence_session_tag?.trim()), {
67
+ message: 'compare_evidence_session_tag is required when compare_evidence_scope=session',
68
+ path: ['compare_evidence_session_tag'],
69
+ }).refine((value) => value.compare_semantic_scope !== 'session' || Boolean(value.compare_semantic_session_tag?.trim()), {
70
+ message: 'compare_semantic_session_tag is required when compare_semantic_scope=session',
71
+ path: ['compare_semantic_session_tag'],
72
+ });
73
+ /**
74
+ * Tool definition for report.generate
75
+ */
76
+ export const reportGenerateToolDefinition = {
77
+ name: 'report.generate',
78
+ description: 'Generate comprehensive analysis report aggregating all analysis results. Supports Markdown, JSON, and HTML formats.',
79
+ inputSchema: reportGenerateInputSchema
80
+ };
81
+ /**
82
+ * Generate Markdown report
83
+ */
84
+ function generateMarkdownReport(sample, analyses, functions, dynamicEvidence, functionExplanations, evidenceScope, evidenceSessionTag, semanticScope = 'all', semanticSessionTag, provenance, selectionDiffs) {
85
+ const lines = [];
86
+ // Header
87
+ lines.push(`# Analysis Report: ${sample.sha256}`);
88
+ lines.push('');
89
+ lines.push(`**Generated:** ${new Date().toISOString()}`);
90
+ lines.push('');
91
+ // Sample Information
92
+ lines.push('## Sample Information');
93
+ lines.push('');
94
+ lines.push(`- **SHA256:** ${sample.sha256}`);
95
+ lines.push(`- **MD5:** ${sample.md5}`);
96
+ lines.push(`- **Size:** ${sample.size} bytes`);
97
+ lines.push(`- **File Type:** ${sample.file_type || 'Unknown'}`);
98
+ lines.push(`- **Ingested:** ${sample.created_at}`);
99
+ lines.push('');
100
+ // Analysis Summary
101
+ lines.push('## Analysis Summary');
102
+ lines.push('');
103
+ lines.push(`- **Total Analyses:** ${analyses.length}`);
104
+ lines.push(`- **Completed:** ${analyses.filter(a => isGhidraReadyStatus(a.status)).length}`);
105
+ lines.push(`- **Failed:** ${analyses.filter(a => a.status === 'failed').length}`);
106
+ lines.push('');
107
+ // Analyses Details
108
+ for (const analysis of analyses) {
109
+ lines.push(`### ${analysis.stage} (${analysis.backend})`);
110
+ lines.push('');
111
+ lines.push(`- **Status:** ${analysis.status}`);
112
+ lines.push(`- **Started:** ${analysis.started_at || 'N/A'}`);
113
+ lines.push(`- **Finished:** ${analysis.finished_at || 'N/A'}`);
114
+ if (analysis.metrics_json) {
115
+ try {
116
+ const metrics = JSON.parse(analysis.metrics_json);
117
+ lines.push(`- **Duration:** ${metrics.elapsed_ms}ms`);
118
+ }
119
+ catch (e) {
120
+ // Ignore parse errors
121
+ }
122
+ }
123
+ if (analysis.output_json) {
124
+ try {
125
+ const output = JSON.parse(analysis.output_json);
126
+ if (output.function_count !== undefined) {
127
+ lines.push(`- **Functions Extracted:** ${output.function_count}`);
128
+ }
129
+ }
130
+ catch (e) {
131
+ // Ignore parse errors
132
+ }
133
+ }
134
+ lines.push('');
135
+ }
136
+ // Function Statistics
137
+ if (functions.length > 0) {
138
+ lines.push('## Function Statistics');
139
+ lines.push('');
140
+ lines.push(`- **Total Functions:** ${functions.length}`);
141
+ const avgSize = functions.reduce((sum, f) => sum + (f.size || 0), 0) / functions.length;
142
+ lines.push(`- **Average Size:** ${Math.round(avgSize)} bytes`);
143
+ const entryPoints = functions.filter(f => f.is_entry_point === 1).length;
144
+ lines.push(`- **Entry Points:** ${entryPoints}`);
145
+ const exported = functions.filter(f => f.is_exported === 1).length;
146
+ lines.push(`- **Exported Functions:** ${exported}`);
147
+ lines.push('');
148
+ // Top Functions
149
+ const topFunctions = functions
150
+ .filter(f => f.score > 0)
151
+ .sort((a, b) => b.score - a.score)
152
+ .slice(0, 10);
153
+ if (topFunctions.length > 0) {
154
+ lines.push('### Top 10 Functions by Interest Score');
155
+ lines.push('');
156
+ lines.push('| Rank | Address | Name | Score | Tags |');
157
+ lines.push('|------|---------|------|-------|------|');
158
+ topFunctions.forEach((func, index) => {
159
+ const tags = func.tags ? JSON.parse(func.tags).join(', ') : '';
160
+ lines.push(`| ${index + 1} | ${func.address} | ${func.name || 'unknown'} | ${func.score.toFixed(2)} | ${tags} |`);
161
+ });
162
+ lines.push('');
163
+ }
164
+ }
165
+ lines.push('## Runtime Evidence');
166
+ lines.push('');
167
+ lines.push(`- **Evidence Scope:** ${evidenceScope}`);
168
+ lines.push(`- **Session Selector:** ${evidenceSessionTag || 'N/A'}`);
169
+ if (dynamicEvidence) {
170
+ lines.push(`- **Artifacts Considered:** ${dynamicEvidence.artifact_count}`);
171
+ lines.push(`- **Executed Trace Present:** ${dynamicEvidence.executed ? 'Yes' : 'No'}`);
172
+ lines.push(`- **Latest Imported At:** ${dynamicEvidence.latest_imported_at || 'N/A'}`);
173
+ lines.push(`- **Scope Note:** ${dynamicEvidence.scope_note || 'N/A'}`);
174
+ lines.push(`- **High Signal APIs:** ${dynamicEvidence.high_signal_apis.join(', ') || 'none'}`);
175
+ lines.push(`- **Stages:** ${dynamicEvidence.stages.join(', ') || 'none'}`);
176
+ lines.push(`- **Source Formats:** ${(dynamicEvidence.source_formats || []).join(', ') || 'none'}`);
177
+ lines.push(`- **Source Names:** ${(dynamicEvidence.source_names || []).join(', ') || 'none'}`);
178
+ if ((dynamicEvidence.confidence_layers || []).length > 0) {
179
+ lines.push('');
180
+ lines.push('### Runtime Evidence Lineage');
181
+ lines.push('');
182
+ for (const layer of dynamicEvidence.confidence_layers || []) {
183
+ lines.push(`- **${layer.layer}:** artifacts=${layer.artifact_count}, band=${layer.confidence_band}, latest=${layer.latest_imported_at || 'N/A'}, sources=${layer.source_names.join(', ') || 'none'}`);
184
+ }
185
+ lines.push('');
186
+ }
187
+ else {
188
+ lines.push('');
189
+ }
190
+ }
191
+ else {
192
+ lines.push('- **Artifacts Considered:** 0');
193
+ lines.push('- **Scope Note:** No runtime evidence matched the selected scope.');
194
+ lines.push('');
195
+ }
196
+ if (provenance) {
197
+ lines.push('## Analysis Provenance');
198
+ lines.push('');
199
+ lines.push(`- **Runtime Artifact IDs:** ${provenance.runtime.artifact_ids.join(', ') || 'none'}`);
200
+ lines.push(`- **Runtime Session Tags:** ${provenance.runtime.session_tags.join(', ') || 'none'}`);
201
+ lines.push(`- **Runtime Latest Artifact At:** ${provenance.runtime.latest_artifact_at || 'N/A'}`);
202
+ lines.push(`- **Semantic Artifact IDs:** ${provenance.semantic_explanations.artifact_ids.join(', ') || 'none'}`);
203
+ lines.push(`- **Semantic Session Tags:** ${provenance.semantic_explanations.session_tags.join(', ') || 'none'}`);
204
+ lines.push(`- **Semantic Latest Artifact At:** ${provenance.semantic_explanations.latest_artifact_at || 'N/A'}`);
205
+ lines.push('');
206
+ }
207
+ if (selectionDiffs && (selectionDiffs.runtime || selectionDiffs.semantic_explanations)) {
208
+ lines.push('## Selection Diffs');
209
+ lines.push('');
210
+ if (selectionDiffs.runtime) {
211
+ lines.push(`- **Runtime Diff:** ${selectionDiffs.runtime.summary}`);
212
+ }
213
+ if (selectionDiffs.semantic_explanations) {
214
+ lines.push(`- **Semantic Diff:** ${selectionDiffs.semantic_explanations.summary}`);
215
+ }
216
+ lines.push('');
217
+ }
218
+ if (functionExplanations.length > 0) {
219
+ lines.push('## Function Explanations');
220
+ lines.push('');
221
+ lines.push(`- **Semantic Scope:** ${semanticScope}`);
222
+ lines.push(`- **Semantic Session Selector:** ${semanticSessionTag || 'N/A'}`);
223
+ lines.push('');
224
+ for (const explanation of functionExplanations) {
225
+ lines.push(`- **${explanation.behavior}:** ${explanation.summary} (confidence=${explanation.confidence.toFixed(2)}, target=${explanation.function || explanation.address || 'unknown'}, source=${explanation.source || 'unknown'})`);
226
+ if (explanation.rewrite_guidance.length > 0) {
227
+ lines.push(` rewrite_guidance: ${explanation.rewrite_guidance.join(' | ')}`);
228
+ }
229
+ }
230
+ lines.push('');
231
+ }
232
+ const confidenceSemantics = buildReportConfidenceSemantics({
233
+ score: dynamicEvidence?.executed ? 0.72 : dynamicEvidence ? 0.58 : 0.42,
234
+ evidenceScope,
235
+ runtimeLayers: dynamicEvidence?.confidence_layers?.map((item) => item.layer) || ['static_only'],
236
+ executedTracePresent: dynamicEvidence?.executed || false,
237
+ });
238
+ lines.push('## Confidence Semantics');
239
+ lines.push('');
240
+ lines.push(`- **Score Kind:** ${confidenceSemantics.score_kind}`);
241
+ lines.push(`- **Band:** ${confidenceSemantics.band}`);
242
+ lines.push(`- **Calibrated Probability:** ${confidenceSemantics.calibrated ? 'Yes' : 'No'}`);
243
+ lines.push(`- **Meaning:** ${confidenceSemantics.meaning}`);
244
+ lines.push(`- **Compare Within:** ${confidenceSemantics.compare_within}`);
245
+ lines.push(`- **Caution:** ${confidenceSemantics.caution}`);
246
+ lines.push(`- **Drivers:** ${confidenceSemantics.drivers.join(', ') || 'none'}`);
247
+ lines.push('');
248
+ // Footer
249
+ lines.push('---');
250
+ lines.push('');
251
+ lines.push('*Report generated by Windows EXE Decompiler MCP Server*');
252
+ lines.push('');
253
+ return lines.join('\n');
254
+ }
255
+ /**
256
+ * Create handler for report.generate tool
257
+ */
258
+ export function createReportGenerateHandler(workspaceManager, database) {
259
+ return async (args) => {
260
+ try {
261
+ const input = reportGenerateInputSchema.parse(args);
262
+ logger.info({
263
+ sample_id: input.sample_id,
264
+ format: input.format,
265
+ evidence_scope: input.evidence_scope,
266
+ evidence_session_tag: input.evidence_session_tag || null,
267
+ }, 'report.generate tool called');
268
+ // Check if sample exists
269
+ const sample = database.findSample(input.sample_id);
270
+ if (!sample) {
271
+ return {
272
+ content: [{
273
+ type: 'text',
274
+ text: JSON.stringify({
275
+ ok: false,
276
+ errors: [`Sample not found: ${input.sample_id}`]
277
+ }, null, 2)
278
+ }],
279
+ isError: true
280
+ };
281
+ }
282
+ // Get all analyses for this sample
283
+ const analyses = database.findAnalysesBySample(input.sample_id);
284
+ // Get all functions for this sample
285
+ const functions = database.findFunctions(input.sample_id);
286
+ const dynamicEvidence = await loadDynamicTraceEvidence(workspaceManager, database, input.sample_id, {
287
+ evidenceScope: input.evidence_scope,
288
+ sessionTag: input.evidence_session_tag,
289
+ });
290
+ const functionExplanationIndex = await loadSemanticFunctionExplanationIndex(workspaceManager, database, input.sample_id, {
291
+ scope: input.semantic_scope,
292
+ sessionTag: input.semantic_session_tag,
293
+ });
294
+ const functionExplanations = Array.from(functionExplanationIndex.byAddress.values())
295
+ .sort((a, b) => {
296
+ if (b.confidence !== a.confidence) {
297
+ return b.confidence - a.confidence;
298
+ }
299
+ return (b.created_at || '').localeCompare(a.created_at || '');
300
+ })
301
+ .slice(0, 6)
302
+ .map((item) => ({
303
+ address: item.address,
304
+ function: item.function,
305
+ behavior: item.behavior,
306
+ summary: item.summary,
307
+ confidence: item.confidence,
308
+ rewrite_guidance: item.rewrite_guidance.slice(0, 4),
309
+ source: item.model_name || item.client_name || null,
310
+ }));
311
+ const provenance = {
312
+ runtime: buildRuntimeArtifactProvenance(dynamicEvidence, input.evidence_scope, input.evidence_session_tag),
313
+ semantic_explanations: buildSemanticArtifactProvenance('semantic explanation artifacts', functionExplanationIndex, input.semantic_scope, input.semantic_session_tag),
314
+ };
315
+ const selectionDiffs = {};
316
+ if (input.compare_evidence_scope) {
317
+ const baselineDynamicEvidence = await loadDynamicTraceEvidence(workspaceManager, database, input.sample_id, {
318
+ evidenceScope: input.compare_evidence_scope,
319
+ sessionTag: input.compare_evidence_session_tag,
320
+ });
321
+ selectionDiffs.runtime = buildArtifactSelectionDiff('runtime', provenance.runtime, buildRuntimeArtifactProvenance(baselineDynamicEvidence, input.compare_evidence_scope, input.compare_evidence_session_tag));
322
+ }
323
+ if (input.compare_semantic_scope) {
324
+ const baselineSemanticIndex = await loadSemanticFunctionExplanationIndex(workspaceManager, database, input.sample_id, {
325
+ scope: input.compare_semantic_scope,
326
+ sessionTag: input.compare_semantic_session_tag,
327
+ });
328
+ selectionDiffs.semantic_explanations = buildArtifactSelectionDiff('semantic_explanations', provenance.semantic_explanations, buildSemanticArtifactProvenance('semantic explanation artifacts', baselineSemanticIndex, input.compare_semantic_scope, input.compare_semantic_session_tag));
329
+ }
330
+ // Generate report based on format
331
+ const format = input.format || 'markdown';
332
+ let reportContent;
333
+ let reportExtension;
334
+ let mimeType;
335
+ switch (format) {
336
+ case 'markdown':
337
+ reportContent = generateMarkdownReport(sample, analyses, functions, dynamicEvidence, functionExplanations, input.evidence_scope, input.evidence_session_tag, input.semantic_scope, input.semantic_session_tag, provenance, selectionDiffs);
338
+ reportExtension = 'md';
339
+ mimeType = 'text/markdown';
340
+ break;
341
+ case 'json':
342
+ const confidenceSemantics = buildReportConfidenceSemantics({
343
+ score: dynamicEvidence?.executed ? 0.72 : dynamicEvidence ? 0.58 : 0.42,
344
+ evidenceScope: input.evidence_scope,
345
+ runtimeLayers: dynamicEvidence?.confidence_layers?.map((item) => item.layer) || ['static_only'],
346
+ executedTracePresent: dynamicEvidence?.executed || false,
347
+ });
348
+ reportContent = JSON.stringify({
349
+ sample,
350
+ analyses,
351
+ functions,
352
+ dynamic_evidence: dynamicEvidence,
353
+ function_explanations: functionExplanations,
354
+ evidence_scope: input.evidence_scope,
355
+ evidence_session_tag: input.evidence_session_tag || null,
356
+ semantic_scope: input.semantic_scope,
357
+ semantic_session_tag: input.semantic_session_tag || null,
358
+ provenance,
359
+ selection_diffs: Object.keys(selectionDiffs).length > 0 ? selectionDiffs : undefined,
360
+ confidence_semantics: confidenceSemantics,
361
+ generated_at: new Date().toISOString()
362
+ }, null, 2);
363
+ reportExtension = 'json';
364
+ mimeType = 'application/json';
365
+ break;
366
+ case 'html':
367
+ // Simple HTML wrapper around markdown
368
+ reportContent = `<!DOCTYPE html>
369
+ <html>
370
+ <head>
371
+ <meta charset="UTF-8">
372
+ <title>Analysis Report: ${sample.sha256}</title>
373
+ <style>
374
+ body { font-family: Arial, sans-serif; max-width: 1200px; margin: 0 auto; padding: 20px; }
375
+ table { border-collapse: collapse; width: 100%; }
376
+ th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
377
+ th { background-color: #f2f2f2; }
378
+ </style>
379
+ </head>
380
+ <body>
381
+ <pre>${generateMarkdownReport(sample, analyses, functions, dynamicEvidence, functionExplanations, input.evidence_scope, input.evidence_session_tag, input.semantic_scope, input.semantic_session_tag, provenance, selectionDiffs)}</pre>
382
+ </body>
383
+ </html>`;
384
+ reportExtension = 'html';
385
+ mimeType = 'text/html';
386
+ break;
387
+ default:
388
+ throw new Error(`Unsupported format: ${format}`);
389
+ }
390
+ // Store report to workspace
391
+ const workspace = await workspaceManager.getWorkspace(input.sample_id);
392
+ const reportFilename = `report_${Date.now()}.${reportExtension}`;
393
+ const reportPath = path.join(workspace.reports, reportFilename);
394
+ // Ensure reports directory exists
395
+ if (!fs.existsSync(workspace.reports)) {
396
+ fs.mkdirSync(workspace.reports, { recursive: true });
397
+ }
398
+ // Write report file
399
+ fs.writeFileSync(reportPath, reportContent, 'utf-8');
400
+ // Compute SHA256 of report
401
+ const reportSha256 = createHash('sha256')
402
+ .update(reportContent)
403
+ .digest('hex');
404
+ // Insert artifact record
405
+ const artifactId = randomUUID();
406
+ database.insertArtifact({
407
+ id: artifactId,
408
+ sample_id: input.sample_id,
409
+ type: `report_${format}`,
410
+ path: `reports/${reportFilename}`,
411
+ sha256: reportSha256,
412
+ mime: mimeType,
413
+ created_at: new Date().toISOString()
414
+ });
415
+ logger.info({
416
+ sample_id: input.sample_id,
417
+ format,
418
+ artifact_id: artifactId,
419
+ path: reportPath
420
+ }, 'Report generated successfully');
421
+ return {
422
+ content: [{
423
+ type: 'text',
424
+ text: JSON.stringify({
425
+ ok: true,
426
+ data: {
427
+ artifact_id: artifactId,
428
+ path: reportPath,
429
+ format,
430
+ size: reportContent.length,
431
+ sha256: reportSha256,
432
+ provenance,
433
+ selection_diffs: Object.keys(selectionDiffs).length > 0 ? selectionDiffs : undefined
434
+ }
435
+ }, null, 2)
436
+ }]
437
+ };
438
+ }
439
+ catch (error) {
440
+ const errorMessage = error instanceof Error ? error.message : String(error);
441
+ logger.error({
442
+ error: errorMessage
443
+ }, 'report.generate tool failed');
444
+ return {
445
+ content: [{
446
+ type: 'text',
447
+ text: JSON.stringify({
448
+ ok: false,
449
+ errors: [errorMessage]
450
+ }, null, 2)
451
+ }],
452
+ isError: true
453
+ };
454
+ }
455
+ };
456
+ }
457
+ //# sourceMappingURL=report-generate.js.map