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
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { ToolDefinition, ToolArgs, WorkerResult } from '../types.js';
|
|
3
|
+
import type { WorkspaceManager } from '../workspace-manager.js';
|
|
4
|
+
import type { DatabaseManager } from '../database.js';
|
|
5
|
+
export declare const codeFunctionsDefineInputSchema: z.ZodObject<{
|
|
6
|
+
sample_id: z.ZodString;
|
|
7
|
+
definitions: z.ZodArray<z.ZodEffects<z.ZodObject<{
|
|
8
|
+
address: z.ZodOptional<z.ZodString>;
|
|
9
|
+
va: z.ZodOptional<z.ZodNumber>;
|
|
10
|
+
rva: z.ZodOptional<z.ZodNumber>;
|
|
11
|
+
size: z.ZodOptional<z.ZodNumber>;
|
|
12
|
+
name: z.ZodOptional<z.ZodString>;
|
|
13
|
+
recovered_name: z.ZodOptional<z.ZodString>;
|
|
14
|
+
summary: z.ZodOptional<z.ZodString>;
|
|
15
|
+
tags: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
|
|
16
|
+
caller_count: z.ZodOptional<z.ZodNumber>;
|
|
17
|
+
callee_count: z.ZodOptional<z.ZodNumber>;
|
|
18
|
+
is_entry_point: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
19
|
+
is_exported: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
20
|
+
callees: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
|
|
21
|
+
score: z.ZodOptional<z.ZodNumber>;
|
|
22
|
+
evidence: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
|
|
23
|
+
}, "strip", z.ZodTypeAny, {
|
|
24
|
+
tags: string[];
|
|
25
|
+
is_entry_point: boolean;
|
|
26
|
+
is_exported: boolean;
|
|
27
|
+
callees: string[];
|
|
28
|
+
evidence: string[];
|
|
29
|
+
address?: string | undefined;
|
|
30
|
+
name?: string | undefined;
|
|
31
|
+
size?: number | undefined;
|
|
32
|
+
score?: number | undefined;
|
|
33
|
+
summary?: string | undefined;
|
|
34
|
+
caller_count?: number | undefined;
|
|
35
|
+
callee_count?: number | undefined;
|
|
36
|
+
rva?: number | undefined;
|
|
37
|
+
va?: number | undefined;
|
|
38
|
+
recovered_name?: string | undefined;
|
|
39
|
+
}, {
|
|
40
|
+
address?: string | undefined;
|
|
41
|
+
name?: string | undefined;
|
|
42
|
+
size?: number | undefined;
|
|
43
|
+
score?: number | undefined;
|
|
44
|
+
tags?: string[] | undefined;
|
|
45
|
+
summary?: string | undefined;
|
|
46
|
+
caller_count?: number | undefined;
|
|
47
|
+
callee_count?: number | undefined;
|
|
48
|
+
is_entry_point?: boolean | undefined;
|
|
49
|
+
is_exported?: boolean | undefined;
|
|
50
|
+
callees?: string[] | undefined;
|
|
51
|
+
evidence?: string[] | undefined;
|
|
52
|
+
rva?: number | undefined;
|
|
53
|
+
va?: number | undefined;
|
|
54
|
+
recovered_name?: string | undefined;
|
|
55
|
+
}>, {
|
|
56
|
+
tags: string[];
|
|
57
|
+
is_entry_point: boolean;
|
|
58
|
+
is_exported: boolean;
|
|
59
|
+
callees: string[];
|
|
60
|
+
evidence: string[];
|
|
61
|
+
address?: string | undefined;
|
|
62
|
+
name?: string | undefined;
|
|
63
|
+
size?: number | undefined;
|
|
64
|
+
score?: number | undefined;
|
|
65
|
+
summary?: string | undefined;
|
|
66
|
+
caller_count?: number | undefined;
|
|
67
|
+
callee_count?: number | undefined;
|
|
68
|
+
rva?: number | undefined;
|
|
69
|
+
va?: number | undefined;
|
|
70
|
+
recovered_name?: string | undefined;
|
|
71
|
+
}, {
|
|
72
|
+
address?: string | undefined;
|
|
73
|
+
name?: string | undefined;
|
|
74
|
+
size?: number | undefined;
|
|
75
|
+
score?: number | undefined;
|
|
76
|
+
tags?: string[] | undefined;
|
|
77
|
+
summary?: string | undefined;
|
|
78
|
+
caller_count?: number | undefined;
|
|
79
|
+
callee_count?: number | undefined;
|
|
80
|
+
is_entry_point?: boolean | undefined;
|
|
81
|
+
is_exported?: boolean | undefined;
|
|
82
|
+
callees?: string[] | undefined;
|
|
83
|
+
evidence?: string[] | undefined;
|
|
84
|
+
rva?: number | undefined;
|
|
85
|
+
va?: number | undefined;
|
|
86
|
+
recovered_name?: string | undefined;
|
|
87
|
+
}>, "many">;
|
|
88
|
+
source: z.ZodDefault<z.ZodOptional<z.ZodEnum<["manual", "pdata", "symbols_recover", "smart_recover", "external"]>>>;
|
|
89
|
+
replace_all: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
90
|
+
persist_artifact: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
91
|
+
register_analysis: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
92
|
+
session_tag: z.ZodOptional<z.ZodString>;
|
|
93
|
+
}, "strip", z.ZodTypeAny, {
|
|
94
|
+
sample_id: string;
|
|
95
|
+
source: "smart_recover" | "symbols_recover" | "manual" | "pdata" | "external";
|
|
96
|
+
definitions: {
|
|
97
|
+
tags: string[];
|
|
98
|
+
is_entry_point: boolean;
|
|
99
|
+
is_exported: boolean;
|
|
100
|
+
callees: string[];
|
|
101
|
+
evidence: string[];
|
|
102
|
+
address?: string | undefined;
|
|
103
|
+
name?: string | undefined;
|
|
104
|
+
size?: number | undefined;
|
|
105
|
+
score?: number | undefined;
|
|
106
|
+
summary?: string | undefined;
|
|
107
|
+
caller_count?: number | undefined;
|
|
108
|
+
callee_count?: number | undefined;
|
|
109
|
+
rva?: number | undefined;
|
|
110
|
+
va?: number | undefined;
|
|
111
|
+
recovered_name?: string | undefined;
|
|
112
|
+
}[];
|
|
113
|
+
replace_all: boolean;
|
|
114
|
+
persist_artifact: boolean;
|
|
115
|
+
register_analysis: boolean;
|
|
116
|
+
session_tag?: string | undefined;
|
|
117
|
+
}, {
|
|
118
|
+
sample_id: string;
|
|
119
|
+
definitions: {
|
|
120
|
+
address?: string | undefined;
|
|
121
|
+
name?: string | undefined;
|
|
122
|
+
size?: number | undefined;
|
|
123
|
+
score?: number | undefined;
|
|
124
|
+
tags?: string[] | undefined;
|
|
125
|
+
summary?: string | undefined;
|
|
126
|
+
caller_count?: number | undefined;
|
|
127
|
+
callee_count?: number | undefined;
|
|
128
|
+
is_entry_point?: boolean | undefined;
|
|
129
|
+
is_exported?: boolean | undefined;
|
|
130
|
+
callees?: string[] | undefined;
|
|
131
|
+
evidence?: string[] | undefined;
|
|
132
|
+
rva?: number | undefined;
|
|
133
|
+
va?: number | undefined;
|
|
134
|
+
recovered_name?: string | undefined;
|
|
135
|
+
}[];
|
|
136
|
+
session_tag?: string | undefined;
|
|
137
|
+
source?: "smart_recover" | "symbols_recover" | "manual" | "pdata" | "external" | undefined;
|
|
138
|
+
replace_all?: boolean | undefined;
|
|
139
|
+
persist_artifact?: boolean | undefined;
|
|
140
|
+
register_analysis?: boolean | undefined;
|
|
141
|
+
}>;
|
|
142
|
+
export declare const codeFunctionsDefineOutputSchema: z.ZodObject<{
|
|
143
|
+
ok: z.ZodBoolean;
|
|
144
|
+
data: z.ZodOptional<z.ZodObject<{
|
|
145
|
+
sample_id: z.ZodString;
|
|
146
|
+
source: z.ZodString;
|
|
147
|
+
replace_all: z.ZodBoolean;
|
|
148
|
+
imported_count: z.ZodNumber;
|
|
149
|
+
function_index_status: z.ZodEnum<["ready"]>;
|
|
150
|
+
decompile_status: z.ZodEnum<["missing"]>;
|
|
151
|
+
cfg_status: z.ZodEnum<["missing"]>;
|
|
152
|
+
image_base: z.ZodNullable<z.ZodNumber>;
|
|
153
|
+
imported_functions: z.ZodArray<z.ZodObject<{
|
|
154
|
+
address: z.ZodString;
|
|
155
|
+
rva: z.ZodNullable<z.ZodNumber>;
|
|
156
|
+
size: z.ZodNullable<z.ZodNumber>;
|
|
157
|
+
name: z.ZodString;
|
|
158
|
+
is_entry_point: z.ZodBoolean;
|
|
159
|
+
is_exported: z.ZodBoolean;
|
|
160
|
+
}, "strip", z.ZodTypeAny, {
|
|
161
|
+
address: string;
|
|
162
|
+
name: string;
|
|
163
|
+
size: number | null;
|
|
164
|
+
is_entry_point: boolean;
|
|
165
|
+
is_exported: boolean;
|
|
166
|
+
rva: number | null;
|
|
167
|
+
}, {
|
|
168
|
+
address: string;
|
|
169
|
+
name: string;
|
|
170
|
+
size: number | null;
|
|
171
|
+
is_entry_point: boolean;
|
|
172
|
+
is_exported: boolean;
|
|
173
|
+
rva: number | null;
|
|
174
|
+
}>, "many">;
|
|
175
|
+
analysis_id: z.ZodOptional<z.ZodString>;
|
|
176
|
+
artifact: z.ZodOptional<z.ZodObject<{
|
|
177
|
+
id: z.ZodString;
|
|
178
|
+
type: z.ZodString;
|
|
179
|
+
path: z.ZodString;
|
|
180
|
+
sha256: z.ZodString;
|
|
181
|
+
mime: z.ZodOptional<z.ZodString>;
|
|
182
|
+
}, "strip", z.ZodTypeAny, {
|
|
183
|
+
path: string;
|
|
184
|
+
type: string;
|
|
185
|
+
id: string;
|
|
186
|
+
sha256: string;
|
|
187
|
+
mime?: string | undefined;
|
|
188
|
+
}, {
|
|
189
|
+
path: string;
|
|
190
|
+
type: string;
|
|
191
|
+
id: string;
|
|
192
|
+
sha256: string;
|
|
193
|
+
mime?: string | undefined;
|
|
194
|
+
}>>;
|
|
195
|
+
next_steps: z.ZodArray<z.ZodString, "many">;
|
|
196
|
+
}, "strip", z.ZodTypeAny, {
|
|
197
|
+
sample_id: string;
|
|
198
|
+
source: string;
|
|
199
|
+
image_base: number | null;
|
|
200
|
+
next_steps: string[];
|
|
201
|
+
replace_all: boolean;
|
|
202
|
+
imported_count: number;
|
|
203
|
+
function_index_status: "ready";
|
|
204
|
+
decompile_status: "missing";
|
|
205
|
+
cfg_status: "missing";
|
|
206
|
+
imported_functions: {
|
|
207
|
+
address: string;
|
|
208
|
+
name: string;
|
|
209
|
+
size: number | null;
|
|
210
|
+
is_entry_point: boolean;
|
|
211
|
+
is_exported: boolean;
|
|
212
|
+
rva: number | null;
|
|
213
|
+
}[];
|
|
214
|
+
artifact?: {
|
|
215
|
+
path: string;
|
|
216
|
+
type: string;
|
|
217
|
+
id: string;
|
|
218
|
+
sha256: string;
|
|
219
|
+
mime?: string | undefined;
|
|
220
|
+
} | undefined;
|
|
221
|
+
analysis_id?: string | undefined;
|
|
222
|
+
}, {
|
|
223
|
+
sample_id: string;
|
|
224
|
+
source: string;
|
|
225
|
+
image_base: number | null;
|
|
226
|
+
next_steps: string[];
|
|
227
|
+
replace_all: boolean;
|
|
228
|
+
imported_count: number;
|
|
229
|
+
function_index_status: "ready";
|
|
230
|
+
decompile_status: "missing";
|
|
231
|
+
cfg_status: "missing";
|
|
232
|
+
imported_functions: {
|
|
233
|
+
address: string;
|
|
234
|
+
name: string;
|
|
235
|
+
size: number | null;
|
|
236
|
+
is_entry_point: boolean;
|
|
237
|
+
is_exported: boolean;
|
|
238
|
+
rva: number | null;
|
|
239
|
+
}[];
|
|
240
|
+
artifact?: {
|
|
241
|
+
path: string;
|
|
242
|
+
type: string;
|
|
243
|
+
id: string;
|
|
244
|
+
sha256: string;
|
|
245
|
+
mime?: string | undefined;
|
|
246
|
+
} | undefined;
|
|
247
|
+
analysis_id?: string | undefined;
|
|
248
|
+
}>>;
|
|
249
|
+
warnings: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
250
|
+
errors: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
251
|
+
artifacts: z.ZodOptional<z.ZodArray<z.ZodAny, "many">>;
|
|
252
|
+
metrics: z.ZodOptional<z.ZodObject<{
|
|
253
|
+
elapsed_ms: z.ZodNumber;
|
|
254
|
+
tool: z.ZodString;
|
|
255
|
+
}, "strip", z.ZodTypeAny, {
|
|
256
|
+
elapsed_ms: number;
|
|
257
|
+
tool: string;
|
|
258
|
+
}, {
|
|
259
|
+
elapsed_ms: number;
|
|
260
|
+
tool: string;
|
|
261
|
+
}>>;
|
|
262
|
+
}, "strip", z.ZodTypeAny, {
|
|
263
|
+
ok: boolean;
|
|
264
|
+
data?: {
|
|
265
|
+
sample_id: string;
|
|
266
|
+
source: string;
|
|
267
|
+
image_base: number | null;
|
|
268
|
+
next_steps: string[];
|
|
269
|
+
replace_all: boolean;
|
|
270
|
+
imported_count: number;
|
|
271
|
+
function_index_status: "ready";
|
|
272
|
+
decompile_status: "missing";
|
|
273
|
+
cfg_status: "missing";
|
|
274
|
+
imported_functions: {
|
|
275
|
+
address: string;
|
|
276
|
+
name: string;
|
|
277
|
+
size: number | null;
|
|
278
|
+
is_entry_point: boolean;
|
|
279
|
+
is_exported: boolean;
|
|
280
|
+
rva: number | null;
|
|
281
|
+
}[];
|
|
282
|
+
artifact?: {
|
|
283
|
+
path: string;
|
|
284
|
+
type: string;
|
|
285
|
+
id: string;
|
|
286
|
+
sha256: string;
|
|
287
|
+
mime?: string | undefined;
|
|
288
|
+
} | undefined;
|
|
289
|
+
analysis_id?: string | undefined;
|
|
290
|
+
} | undefined;
|
|
291
|
+
metrics?: {
|
|
292
|
+
elapsed_ms: number;
|
|
293
|
+
tool: string;
|
|
294
|
+
} | undefined;
|
|
295
|
+
warnings?: string[] | undefined;
|
|
296
|
+
errors?: string[] | undefined;
|
|
297
|
+
artifacts?: any[] | undefined;
|
|
298
|
+
}, {
|
|
299
|
+
ok: boolean;
|
|
300
|
+
data?: {
|
|
301
|
+
sample_id: string;
|
|
302
|
+
source: string;
|
|
303
|
+
image_base: number | null;
|
|
304
|
+
next_steps: string[];
|
|
305
|
+
replace_all: boolean;
|
|
306
|
+
imported_count: number;
|
|
307
|
+
function_index_status: "ready";
|
|
308
|
+
decompile_status: "missing";
|
|
309
|
+
cfg_status: "missing";
|
|
310
|
+
imported_functions: {
|
|
311
|
+
address: string;
|
|
312
|
+
name: string;
|
|
313
|
+
size: number | null;
|
|
314
|
+
is_entry_point: boolean;
|
|
315
|
+
is_exported: boolean;
|
|
316
|
+
rva: number | null;
|
|
317
|
+
}[];
|
|
318
|
+
artifact?: {
|
|
319
|
+
path: string;
|
|
320
|
+
type: string;
|
|
321
|
+
id: string;
|
|
322
|
+
sha256: string;
|
|
323
|
+
mime?: string | undefined;
|
|
324
|
+
} | undefined;
|
|
325
|
+
analysis_id?: string | undefined;
|
|
326
|
+
} | undefined;
|
|
327
|
+
metrics?: {
|
|
328
|
+
elapsed_ms: number;
|
|
329
|
+
tool: string;
|
|
330
|
+
} | undefined;
|
|
331
|
+
warnings?: string[] | undefined;
|
|
332
|
+
errors?: string[] | undefined;
|
|
333
|
+
artifacts?: any[] | undefined;
|
|
334
|
+
}>;
|
|
335
|
+
export declare const codeFunctionsDefineToolDefinition: ToolDefinition;
|
|
336
|
+
export declare function createCodeFunctionsDefineHandler(workspaceManager: WorkspaceManager, database: DatabaseManager): (args: ToolArgs) => Promise<WorkerResult>;
|
|
337
|
+
//# sourceMappingURL=code-functions-define.d.ts.map
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { createHash, randomUUID } from 'crypto';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { extractPdataFromPE } from '../pe-runtime-functions.js';
|
|
6
|
+
import { resolvePrimarySamplePath } from '../sample-workspace.js';
|
|
7
|
+
const TOOL_NAME = 'code.functions.define';
|
|
8
|
+
const FunctionDefinitionSchema = z
|
|
9
|
+
.object({
|
|
10
|
+
address: z.string().optional().describe('Absolute virtual address such as 0x140001000'),
|
|
11
|
+
va: z.number().int().nonnegative().optional().describe('Absolute virtual address as a numeric value'),
|
|
12
|
+
rva: z.number().int().nonnegative().optional().describe('Relative virtual address. Converted using the PE image base.'),
|
|
13
|
+
size: z.number().int().positive().optional().describe('Function size in bytes when known'),
|
|
14
|
+
name: z.string().min(1).max(256).optional().describe('Preferred function name'),
|
|
15
|
+
recovered_name: z.string().min(1).max(256).optional().describe('Recovered name from pe.symbols.recover when name is not present'),
|
|
16
|
+
summary: z.string().max(2000).optional().describe('Optional analyst summary for this function'),
|
|
17
|
+
tags: z.array(z.string()).optional().default([]).describe('Optional semantic or provenance tags'),
|
|
18
|
+
caller_count: z.number().int().nonnegative().optional().describe('Optional caller count estimate'),
|
|
19
|
+
callee_count: z.number().int().nonnegative().optional().describe('Optional callee count estimate'),
|
|
20
|
+
is_entry_point: z.boolean().optional().default(false).describe('Mark the function as an entry point'),
|
|
21
|
+
is_exported: z.boolean().optional().default(false).describe('Mark the function as exported'),
|
|
22
|
+
callees: z.array(z.string()).optional().default([]).describe('Optional list of known callees'),
|
|
23
|
+
score: z.number().min(0).max(1).optional().describe('Optional precomputed ranking score'),
|
|
24
|
+
evidence: z.array(z.string()).optional().default([]).describe('Optional evidence strings that explain why this boundary was defined'),
|
|
25
|
+
})
|
|
26
|
+
.refine((value) => Boolean(value.address?.trim()) || value.va !== undefined || value.rva !== undefined, {
|
|
27
|
+
message: 'Each function definition must provide at least one of address, va, or rva.',
|
|
28
|
+
});
|
|
29
|
+
export const codeFunctionsDefineInputSchema = z.object({
|
|
30
|
+
sample_id: z.string().describe('Sample ID (format: sha256:<hex>)'),
|
|
31
|
+
definitions: z
|
|
32
|
+
.array(FunctionDefinitionSchema)
|
|
33
|
+
.min(1)
|
|
34
|
+
.describe('Function boundaries or recovered function records to import into the function index'),
|
|
35
|
+
source: z
|
|
36
|
+
.enum(['manual', 'pdata', 'symbols_recover', 'smart_recover', 'external'])
|
|
37
|
+
.optional()
|
|
38
|
+
.default('manual')
|
|
39
|
+
.describe('Provenance label recorded in the analysis and artifact metadata'),
|
|
40
|
+
replace_all: z
|
|
41
|
+
.boolean()
|
|
42
|
+
.optional()
|
|
43
|
+
.default(false)
|
|
44
|
+
.describe('When true, replace the existing function index for this sample before importing the new definitions'),
|
|
45
|
+
persist_artifact: z
|
|
46
|
+
.boolean()
|
|
47
|
+
.optional()
|
|
48
|
+
.default(true)
|
|
49
|
+
.describe('Persist the imported function definitions as a stable artifact in reports/function_definitions'),
|
|
50
|
+
register_analysis: z
|
|
51
|
+
.boolean()
|
|
52
|
+
.optional()
|
|
53
|
+
.default(true)
|
|
54
|
+
.describe('Insert a completed analysis row describing the imported function index'),
|
|
55
|
+
session_tag: z
|
|
56
|
+
.string()
|
|
57
|
+
.optional()
|
|
58
|
+
.describe('Optional session tag used in the persisted artifact name and analysis metadata'),
|
|
59
|
+
});
|
|
60
|
+
export const codeFunctionsDefineOutputSchema = z.object({
|
|
61
|
+
ok: z.boolean(),
|
|
62
|
+
data: z
|
|
63
|
+
.object({
|
|
64
|
+
sample_id: z.string(),
|
|
65
|
+
source: z.string(),
|
|
66
|
+
replace_all: z.boolean(),
|
|
67
|
+
imported_count: z.number().int().nonnegative(),
|
|
68
|
+
function_index_status: z.enum(['ready']),
|
|
69
|
+
decompile_status: z.enum(['missing']),
|
|
70
|
+
cfg_status: z.enum(['missing']),
|
|
71
|
+
image_base: z.number().nullable(),
|
|
72
|
+
imported_functions: z.array(z.object({
|
|
73
|
+
address: z.string(),
|
|
74
|
+
rva: z.number().nullable(),
|
|
75
|
+
size: z.number().nullable(),
|
|
76
|
+
name: z.string(),
|
|
77
|
+
is_entry_point: z.boolean(),
|
|
78
|
+
is_exported: z.boolean(),
|
|
79
|
+
})),
|
|
80
|
+
analysis_id: z.string().optional(),
|
|
81
|
+
artifact: z
|
|
82
|
+
.object({
|
|
83
|
+
id: z.string(),
|
|
84
|
+
type: z.string(),
|
|
85
|
+
path: z.string(),
|
|
86
|
+
sha256: z.string(),
|
|
87
|
+
mime: z.string().optional(),
|
|
88
|
+
})
|
|
89
|
+
.optional(),
|
|
90
|
+
next_steps: z.array(z.string()),
|
|
91
|
+
})
|
|
92
|
+
.optional(),
|
|
93
|
+
warnings: z.array(z.string()).optional(),
|
|
94
|
+
errors: z.array(z.string()).optional(),
|
|
95
|
+
artifacts: z.array(z.any()).optional(),
|
|
96
|
+
metrics: z
|
|
97
|
+
.object({
|
|
98
|
+
elapsed_ms: z.number(),
|
|
99
|
+
tool: z.string(),
|
|
100
|
+
})
|
|
101
|
+
.optional(),
|
|
102
|
+
});
|
|
103
|
+
export const codeFunctionsDefineToolDefinition = {
|
|
104
|
+
name: TOOL_NAME,
|
|
105
|
+
description: 'Define or import function boundaries manually or from recovered metadata so code.functions.list/rank/reconstruct can use a non-Ghidra function index.',
|
|
106
|
+
inputSchema: codeFunctionsDefineInputSchema,
|
|
107
|
+
outputSchema: codeFunctionsDefineOutputSchema,
|
|
108
|
+
};
|
|
109
|
+
function normalizeHexAddress(value) {
|
|
110
|
+
const trimmed = value.trim();
|
|
111
|
+
if (!trimmed) {
|
|
112
|
+
throw new Error('Function address cannot be empty.');
|
|
113
|
+
}
|
|
114
|
+
const hex = trimmed.toLowerCase().startsWith('0x') ? trimmed.slice(2) : trimmed;
|
|
115
|
+
if (!/^[0-9a-f]+$/i.test(hex)) {
|
|
116
|
+
throw new Error(`Invalid function address: ${value}`);
|
|
117
|
+
}
|
|
118
|
+
return `0x${hex.toLowerCase()}`;
|
|
119
|
+
}
|
|
120
|
+
function sanitizePathToken(value) {
|
|
121
|
+
const normalized = (value || '').trim().replace(/[^A-Za-z0-9._-]+/g, '_').replace(/^_+|_+$/g, '');
|
|
122
|
+
return normalized.slice(0, 48);
|
|
123
|
+
}
|
|
124
|
+
export function createCodeFunctionsDefineHandler(workspaceManager, database) {
|
|
125
|
+
return async (args) => {
|
|
126
|
+
const startTime = Date.now();
|
|
127
|
+
try {
|
|
128
|
+
const input = codeFunctionsDefineInputSchema.parse(args);
|
|
129
|
+
const sample = database.findSample(input.sample_id);
|
|
130
|
+
if (!sample) {
|
|
131
|
+
return {
|
|
132
|
+
ok: false,
|
|
133
|
+
errors: [`Sample not found: ${input.sample_id}`],
|
|
134
|
+
metrics: {
|
|
135
|
+
elapsed_ms: Date.now() - startTime,
|
|
136
|
+
tool: TOOL_NAME,
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
let imageBase = null;
|
|
141
|
+
if (input.definitions.some((item) => !item.address && item.va === undefined && item.rva !== undefined)) {
|
|
142
|
+
const { samplePath } = await resolvePrimarySamplePath(workspaceManager, input.sample_id);
|
|
143
|
+
imageBase = extractPdataFromPE(samplePath).imageBase;
|
|
144
|
+
}
|
|
145
|
+
const warnings = [];
|
|
146
|
+
const imported = [];
|
|
147
|
+
const importedSummary = [];
|
|
148
|
+
for (const item of input.definitions) {
|
|
149
|
+
const name = (item.name || item.recovered_name || '').trim();
|
|
150
|
+
if (!name) {
|
|
151
|
+
warnings.push(`Skipped function definition ${item.address || (item.va !== undefined ? `va:${item.va}` : `rva:${item.rva}`)} because no name or recovered_name was provided.`);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
let va;
|
|
155
|
+
let rva = item.rva ?? null;
|
|
156
|
+
if (item.address) {
|
|
157
|
+
const normalizedAddress = normalizeHexAddress(item.address);
|
|
158
|
+
va = Number.parseInt(normalizedAddress.slice(2), 16);
|
|
159
|
+
}
|
|
160
|
+
else if (item.va !== undefined) {
|
|
161
|
+
va = item.va;
|
|
162
|
+
}
|
|
163
|
+
else if (item.rva !== undefined) {
|
|
164
|
+
if (imageBase === null) {
|
|
165
|
+
throw new Error('Unable to resolve RVA definitions because the PE image base could not be determined.');
|
|
166
|
+
}
|
|
167
|
+
va = imageBase + item.rva;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
throw new Error('Each function definition must provide address, va, or rva.');
|
|
171
|
+
}
|
|
172
|
+
if (rva === null && imageBase !== null && va >= imageBase) {
|
|
173
|
+
rva = va - imageBase;
|
|
174
|
+
}
|
|
175
|
+
const address = normalizeHexAddress(`0x${va.toString(16)}`);
|
|
176
|
+
const tags = Array.from(new Set([`source:${input.source}`, ...(item.tags || []), ...(item.evidence?.map((e) => `evidence:${e}`) || [])]));
|
|
177
|
+
const summary = item.summary ||
|
|
178
|
+
`Function boundary imported via code.functions.define (source=${input.source}${rva !== null ? `, rva=0x${rva.toString(16)}` : ''}).`;
|
|
179
|
+
imported.push({
|
|
180
|
+
sample_id: input.sample_id,
|
|
181
|
+
address,
|
|
182
|
+
name,
|
|
183
|
+
size: item.size ?? null,
|
|
184
|
+
score: item.score ?? null,
|
|
185
|
+
tags: tags.length > 0 ? JSON.stringify(tags) : null,
|
|
186
|
+
summary,
|
|
187
|
+
caller_count: item.caller_count ?? 0,
|
|
188
|
+
callee_count: item.callee_count ?? 0,
|
|
189
|
+
is_entry_point: item.is_entry_point ? 1 : 0,
|
|
190
|
+
is_exported: item.is_exported ? 1 : 0,
|
|
191
|
+
callees: (item.callees || []).length > 0 ? JSON.stringify(item.callees) : null,
|
|
192
|
+
});
|
|
193
|
+
importedSummary.push({
|
|
194
|
+
address,
|
|
195
|
+
rva,
|
|
196
|
+
size: item.size ?? null,
|
|
197
|
+
name,
|
|
198
|
+
is_entry_point: Boolean(item.is_entry_point),
|
|
199
|
+
is_exported: Boolean(item.is_exported),
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
if (imported.length === 0) {
|
|
203
|
+
return {
|
|
204
|
+
ok: false,
|
|
205
|
+
errors: ['No function definitions were imported after validation.'],
|
|
206
|
+
warnings: warnings.length > 0 ? warnings : undefined,
|
|
207
|
+
metrics: {
|
|
208
|
+
elapsed_ms: Date.now() - startTime,
|
|
209
|
+
tool: TOOL_NAME,
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
if (input.replace_all) {
|
|
214
|
+
database.getDatabase().prepare('DELETE FROM functions WHERE sample_id = ?').run(input.sample_id);
|
|
215
|
+
}
|
|
216
|
+
database.insertFunctionsBatch(imported);
|
|
217
|
+
let artifact;
|
|
218
|
+
const artifacts = [];
|
|
219
|
+
if (input.persist_artifact) {
|
|
220
|
+
const workspace = await workspaceManager.createWorkspace(input.sample_id);
|
|
221
|
+
const reportDir = path.join(workspace.reports, 'function_definitions');
|
|
222
|
+
await fs.mkdir(reportDir, { recursive: true });
|
|
223
|
+
const sanitizedSessionTag = sanitizePathToken(input.session_tag);
|
|
224
|
+
const suffix = sanitizedSessionTag ? `_${sanitizedSessionTag}` : '';
|
|
225
|
+
const fileName = `defined_functions_${input.source}${suffix}_${Date.now()}.json`;
|
|
226
|
+
const absolutePath = path.join(reportDir, fileName);
|
|
227
|
+
const payload = {
|
|
228
|
+
schema_version: 1,
|
|
229
|
+
sample_id: input.sample_id,
|
|
230
|
+
source: input.source,
|
|
231
|
+
replace_all: input.replace_all,
|
|
232
|
+
created_at: new Date().toISOString(),
|
|
233
|
+
image_base: imageBase,
|
|
234
|
+
functions: importedSummary,
|
|
235
|
+
};
|
|
236
|
+
const serialized = JSON.stringify(payload, null, 2);
|
|
237
|
+
await fs.writeFile(absolutePath, serialized, 'utf-8');
|
|
238
|
+
const artifactId = randomUUID();
|
|
239
|
+
const artifactSha256 = createHash('sha256').update(serialized).digest('hex');
|
|
240
|
+
artifact = {
|
|
241
|
+
id: artifactId,
|
|
242
|
+
type: 'function_definition',
|
|
243
|
+
path: `reports/function_definitions/${fileName}`,
|
|
244
|
+
sha256: artifactSha256,
|
|
245
|
+
mime: 'application/json',
|
|
246
|
+
};
|
|
247
|
+
database.insertArtifact({
|
|
248
|
+
id: artifactId,
|
|
249
|
+
sample_id: input.sample_id,
|
|
250
|
+
type: artifact.type,
|
|
251
|
+
path: artifact.path,
|
|
252
|
+
sha256: artifact.sha256,
|
|
253
|
+
mime: artifact.mime || null,
|
|
254
|
+
created_at: new Date().toISOString(),
|
|
255
|
+
});
|
|
256
|
+
artifacts.push(artifact);
|
|
257
|
+
}
|
|
258
|
+
let analysisId;
|
|
259
|
+
if (input.register_analysis) {
|
|
260
|
+
analysisId = randomUUID();
|
|
261
|
+
database.insertAnalysis({
|
|
262
|
+
id: analysisId,
|
|
263
|
+
sample_id: input.sample_id,
|
|
264
|
+
stage: 'function_definition',
|
|
265
|
+
backend: input.source,
|
|
266
|
+
status: 'done',
|
|
267
|
+
started_at: new Date(startTime).toISOString(),
|
|
268
|
+
finished_at: new Date().toISOString(),
|
|
269
|
+
output_json: JSON.stringify({
|
|
270
|
+
function_count: imported.length,
|
|
271
|
+
function_source: input.source,
|
|
272
|
+
replace_all: input.replace_all,
|
|
273
|
+
artifact_id: artifact?.id || null,
|
|
274
|
+
readiness: {
|
|
275
|
+
function_index: {
|
|
276
|
+
available: true,
|
|
277
|
+
status: 'ready',
|
|
278
|
+
reason: 'Function index imported manually or from recovered metadata.',
|
|
279
|
+
},
|
|
280
|
+
decompile: {
|
|
281
|
+
available: false,
|
|
282
|
+
status: 'missing',
|
|
283
|
+
reason: 'Manual function definitions do not establish Ghidra decompile readiness.',
|
|
284
|
+
},
|
|
285
|
+
cfg: {
|
|
286
|
+
available: false,
|
|
287
|
+
status: 'missing',
|
|
288
|
+
reason: 'Manual function definitions do not establish Ghidra CFG readiness.',
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
}),
|
|
292
|
+
metrics_json: JSON.stringify({
|
|
293
|
+
imported_count: imported.length,
|
|
294
|
+
}),
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
return {
|
|
298
|
+
ok: true,
|
|
299
|
+
data: {
|
|
300
|
+
sample_id: input.sample_id,
|
|
301
|
+
source: input.source,
|
|
302
|
+
replace_all: input.replace_all,
|
|
303
|
+
imported_count: imported.length,
|
|
304
|
+
function_index_status: 'ready',
|
|
305
|
+
decompile_status: 'missing',
|
|
306
|
+
cfg_status: 'missing',
|
|
307
|
+
image_base: imageBase,
|
|
308
|
+
imported_functions: importedSummary,
|
|
309
|
+
analysis_id: analysisId,
|
|
310
|
+
artifact,
|
|
311
|
+
next_steps: [
|
|
312
|
+
'Run code.functions.list or code.functions.rank to inspect the imported function index.',
|
|
313
|
+
'Run code.functions.reconstruct to obtain degraded semantic reconstruction from the new function index.',
|
|
314
|
+
'Run ghidra.analyze later if you still need decompile or CFG readiness.',
|
|
315
|
+
],
|
|
316
|
+
},
|
|
317
|
+
warnings: warnings.length > 0 ? warnings : undefined,
|
|
318
|
+
artifacts: artifacts.length > 0 ? artifacts : undefined,
|
|
319
|
+
metrics: {
|
|
320
|
+
elapsed_ms: Date.now() - startTime,
|
|
321
|
+
tool: TOOL_NAME,
|
|
322
|
+
},
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
catch (error) {
|
|
326
|
+
return {
|
|
327
|
+
ok: false,
|
|
328
|
+
errors: [error instanceof Error ? error.message : String(error)],
|
|
329
|
+
metrics: {
|
|
330
|
+
elapsed_ms: Date.now() - startTime,
|
|
331
|
+
tool: TOOL_NAME,
|
|
332
|
+
},
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
//# sourceMappingURL=code-functions-define.js.map
|
|
@@ -21,7 +21,7 @@ export const codeFunctionsListInputSchema = z.object({
|
|
|
21
21
|
*/
|
|
22
22
|
export const codeFunctionsListToolDefinition = {
|
|
23
23
|
name: 'code.functions.list',
|
|
24
|
-
description: 'List all functions
|
|
24
|
+
description: 'List all indexed functions for a binary sample. Supports Ghidra-extracted, PE metadata-recovered, or manually defined function indexes.',
|
|
25
25
|
inputSchema: codeFunctionsListInputSchema
|
|
26
26
|
};
|
|
27
27
|
/**
|
|
@@ -20,7 +20,7 @@ export const codeFunctionsRankInputSchema = z.object({
|
|
|
20
20
|
*/
|
|
21
21
|
export const codeFunctionsRankToolDefinition = {
|
|
22
22
|
name: 'code.functions.rank',
|
|
23
|
-
description: 'Rank functions by interest score based on size, callers, sensitive API calls, and entry points.
|
|
23
|
+
description: 'Rank indexed functions by interest score based on size, callers, sensitive API calls, and entry points. Works with Ghidra, recovered, or manually defined function indexes.',
|
|
24
24
|
inputSchema: codeFunctionsRankInputSchema
|
|
25
25
|
};
|
|
26
26
|
/**
|