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
package/dist/config.d.ts
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
* Handles loading and validating configuration from files and environment variables
|
|
4
4
|
*/
|
|
5
5
|
import { z } from 'zod';
|
|
6
|
+
export declare const APP_CONFIG_DIRNAME = ".windows-exe-decompiler-mcp-server";
|
|
7
|
+
export declare function getDefaultAppRoot(): string;
|
|
8
|
+
export declare function getDefaultWorkspaceRoot(): string;
|
|
9
|
+
export declare function getDefaultConfigPath(): string;
|
|
10
|
+
export declare function getDefaultDatabasePath(): string;
|
|
11
|
+
export declare function getDefaultCacheRoot(): string;
|
|
12
|
+
export declare function getDefaultAuditLogPath(): string;
|
|
6
13
|
export declare const ConfigSchema: z.ZodObject<{
|
|
7
14
|
server: z.ZodDefault<z.ZodObject<{
|
|
8
15
|
port: z.ZodDefault<z.ZodNumber>;
|
|
@@ -16,17 +23,17 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
16
23
|
}>>;
|
|
17
24
|
database: z.ZodDefault<z.ZodObject<{
|
|
18
25
|
type: z.ZodDefault<z.ZodEnum<["sqlite", "postgresql"]>>;
|
|
19
|
-
path: z.
|
|
26
|
+
path: z.ZodDefault<z.ZodString>;
|
|
20
27
|
host: z.ZodOptional<z.ZodString>;
|
|
21
28
|
port: z.ZodOptional<z.ZodNumber>;
|
|
22
29
|
database: z.ZodOptional<z.ZodString>;
|
|
23
30
|
user: z.ZodOptional<z.ZodString>;
|
|
24
31
|
password: z.ZodOptional<z.ZodString>;
|
|
25
32
|
}, "strip", z.ZodTypeAny, {
|
|
33
|
+
path: string;
|
|
26
34
|
type: "sqlite" | "postgresql";
|
|
27
35
|
port?: number | undefined;
|
|
28
36
|
host?: string | undefined;
|
|
29
|
-
path?: string | undefined;
|
|
30
37
|
database?: string | undefined;
|
|
31
38
|
user?: string | undefined;
|
|
32
39
|
password?: string | undefined;
|
|
@@ -147,34 +154,45 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
147
154
|
}>>;
|
|
148
155
|
cache: z.ZodDefault<z.ZodObject<{
|
|
149
156
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
157
|
+
root: z.ZodDefault<z.ZodString>;
|
|
150
158
|
ttl: z.ZodDefault<z.ZodNumber>;
|
|
151
159
|
}, "strip", z.ZodTypeAny, {
|
|
160
|
+
root: string;
|
|
152
161
|
enabled: boolean;
|
|
153
162
|
ttl: number;
|
|
154
163
|
}, {
|
|
164
|
+
root?: string | undefined;
|
|
155
165
|
enabled?: boolean | undefined;
|
|
156
166
|
ttl?: number | undefined;
|
|
157
167
|
}>>;
|
|
158
168
|
logging: z.ZodDefault<z.ZodObject<{
|
|
159
169
|
level: z.ZodDefault<z.ZodEnum<["trace", "debug", "info", "warn", "error", "fatal"]>>;
|
|
160
170
|
pretty: z.ZodDefault<z.ZodBoolean>;
|
|
171
|
+
auditPath: z.ZodDefault<z.ZodString>;
|
|
161
172
|
}, "strip", z.ZodTypeAny, {
|
|
162
173
|
level: "trace" | "debug" | "info" | "warn" | "error" | "fatal";
|
|
163
174
|
pretty: boolean;
|
|
175
|
+
auditPath: string;
|
|
164
176
|
}, {
|
|
165
177
|
level?: "trace" | "debug" | "info" | "warn" | "error" | "fatal" | undefined;
|
|
166
178
|
pretty?: boolean | undefined;
|
|
179
|
+
auditPath?: string | undefined;
|
|
167
180
|
}>>;
|
|
168
181
|
}, "strip", z.ZodTypeAny, {
|
|
182
|
+
cache: {
|
|
183
|
+
root: string;
|
|
184
|
+
enabled: boolean;
|
|
185
|
+
ttl: number;
|
|
186
|
+
};
|
|
169
187
|
server: {
|
|
170
188
|
port: number;
|
|
171
189
|
host: string;
|
|
172
190
|
};
|
|
173
191
|
database: {
|
|
192
|
+
path: string;
|
|
174
193
|
type: "sqlite" | "postgresql";
|
|
175
194
|
port?: number | undefined;
|
|
176
195
|
host?: string | undefined;
|
|
177
|
-
path?: string | undefined;
|
|
178
196
|
database?: string | undefined;
|
|
179
197
|
user?: string | undefined;
|
|
180
198
|
password?: string | undefined;
|
|
@@ -205,15 +223,17 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
205
223
|
timeout: number;
|
|
206
224
|
};
|
|
207
225
|
};
|
|
208
|
-
cache: {
|
|
209
|
-
enabled: boolean;
|
|
210
|
-
ttl: number;
|
|
211
|
-
};
|
|
212
226
|
logging: {
|
|
213
227
|
level: "trace" | "debug" | "info" | "warn" | "error" | "fatal";
|
|
214
228
|
pretty: boolean;
|
|
229
|
+
auditPath: string;
|
|
215
230
|
};
|
|
216
231
|
}, {
|
|
232
|
+
cache?: {
|
|
233
|
+
root?: string | undefined;
|
|
234
|
+
enabled?: boolean | undefined;
|
|
235
|
+
ttl?: number | undefined;
|
|
236
|
+
} | undefined;
|
|
217
237
|
server?: {
|
|
218
238
|
port?: number | undefined;
|
|
219
239
|
host?: string | undefined;
|
|
@@ -253,13 +273,10 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
253
273
|
timeout?: number | undefined;
|
|
254
274
|
} | undefined;
|
|
255
275
|
} | undefined;
|
|
256
|
-
cache?: {
|
|
257
|
-
enabled?: boolean | undefined;
|
|
258
|
-
ttl?: number | undefined;
|
|
259
|
-
} | undefined;
|
|
260
276
|
logging?: {
|
|
261
277
|
level?: "trace" | "debug" | "info" | "warn" | "error" | "fatal" | undefined;
|
|
262
278
|
pretty?: boolean | undefined;
|
|
279
|
+
auditPath?: string | undefined;
|
|
263
280
|
} | undefined;
|
|
264
281
|
}>;
|
|
265
282
|
export type Config = z.infer<typeof ConfigSchema>;
|
|
@@ -284,15 +301,20 @@ export declare function loadConfig(configPath?: string): Config;
|
|
|
284
301
|
* Loads configuration from environment variables and default config file
|
|
285
302
|
*/
|
|
286
303
|
export declare const config: {
|
|
304
|
+
cache: {
|
|
305
|
+
root: string;
|
|
306
|
+
enabled: boolean;
|
|
307
|
+
ttl: number;
|
|
308
|
+
};
|
|
287
309
|
server: {
|
|
288
310
|
port: number;
|
|
289
311
|
host: string;
|
|
290
312
|
};
|
|
291
313
|
database: {
|
|
314
|
+
path: string;
|
|
292
315
|
type: "sqlite" | "postgresql";
|
|
293
316
|
port?: number | undefined;
|
|
294
317
|
host?: string | undefined;
|
|
295
|
-
path?: string | undefined;
|
|
296
318
|
database?: string | undefined;
|
|
297
319
|
user?: string | undefined;
|
|
298
320
|
password?: string | undefined;
|
|
@@ -323,13 +345,10 @@ export declare const config: {
|
|
|
323
345
|
timeout: number;
|
|
324
346
|
};
|
|
325
347
|
};
|
|
326
|
-
cache: {
|
|
327
|
-
enabled: boolean;
|
|
328
|
-
ttl: number;
|
|
329
|
-
};
|
|
330
348
|
logging: {
|
|
331
349
|
level: "trace" | "debug" | "info" | "warn" | "error" | "fatal";
|
|
332
350
|
pretty: boolean;
|
|
351
|
+
auditPath: string;
|
|
333
352
|
};
|
|
334
353
|
};
|
|
335
354
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.js
CHANGED
|
@@ -4,6 +4,27 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
import fs from 'fs';
|
|
7
|
+
import os from 'os';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
export const APP_CONFIG_DIRNAME = '.windows-exe-decompiler-mcp-server';
|
|
10
|
+
export function getDefaultAppRoot() {
|
|
11
|
+
return path.join(os.homedir(), APP_CONFIG_DIRNAME);
|
|
12
|
+
}
|
|
13
|
+
export function getDefaultWorkspaceRoot() {
|
|
14
|
+
return path.join(getDefaultAppRoot(), 'workspaces');
|
|
15
|
+
}
|
|
16
|
+
export function getDefaultConfigPath() {
|
|
17
|
+
return path.join(getDefaultAppRoot(), 'config.json');
|
|
18
|
+
}
|
|
19
|
+
export function getDefaultDatabasePath() {
|
|
20
|
+
return path.join(getDefaultAppRoot(), 'data', 'database.db');
|
|
21
|
+
}
|
|
22
|
+
export function getDefaultCacheRoot() {
|
|
23
|
+
return path.join(getDefaultAppRoot(), 'cache');
|
|
24
|
+
}
|
|
25
|
+
export function getDefaultAuditLogPath() {
|
|
26
|
+
return path.join(getDefaultAppRoot(), 'audit.log');
|
|
27
|
+
}
|
|
7
28
|
// Configuration schema using Zod
|
|
8
29
|
export const ConfigSchema = z.object({
|
|
9
30
|
server: z.object({
|
|
@@ -12,7 +33,7 @@ export const ConfigSchema = z.object({
|
|
|
12
33
|
}).default({}),
|
|
13
34
|
database: z.object({
|
|
14
35
|
type: z.enum(['sqlite', 'postgresql']).default('sqlite'),
|
|
15
|
-
path: z.string().
|
|
36
|
+
path: z.string().default(getDefaultDatabasePath()),
|
|
16
37
|
host: z.string().optional(),
|
|
17
38
|
port: z.number().int().optional(),
|
|
18
39
|
database: z.string().optional(),
|
|
@@ -20,7 +41,7 @@ export const ConfigSchema = z.object({
|
|
|
20
41
|
password: z.string().optional(),
|
|
21
42
|
}).default({}),
|
|
22
43
|
workspace: z.object({
|
|
23
|
-
root: z.string().default(
|
|
44
|
+
root: z.string().default(getDefaultWorkspaceRoot()),
|
|
24
45
|
maxSampleSize: z.number().int().min(1).default(500 * 1024 * 1024), // 500MB
|
|
25
46
|
}).default({}),
|
|
26
47
|
workers: z.object({
|
|
@@ -47,11 +68,13 @@ export const ConfigSchema = z.object({
|
|
|
47
68
|
}).default({}),
|
|
48
69
|
cache: z.object({
|
|
49
70
|
enabled: z.boolean().default(true),
|
|
71
|
+
root: z.string().default(getDefaultCacheRoot()),
|
|
50
72
|
ttl: z.number().int().min(0).default(30 * 24 * 60 * 60), // 30 days
|
|
51
73
|
}).default({}),
|
|
52
74
|
logging: z.object({
|
|
53
75
|
level: z.enum(['trace', 'debug', 'info', 'warn', 'error', 'fatal']).default('info'),
|
|
54
76
|
pretty: z.boolean().default(false),
|
|
77
|
+
auditPath: z.string().default(getDefaultAuditLogPath()),
|
|
55
78
|
}).default({}),
|
|
56
79
|
});
|
|
57
80
|
/**
|
|
@@ -112,6 +135,11 @@ export function loadConfigFromEnv() {
|
|
|
112
135
|
config.workspace = {};
|
|
113
136
|
config.workspace.root = process.env.WORKSPACE_ROOT;
|
|
114
137
|
}
|
|
138
|
+
if (process.env.CACHE_ROOT) {
|
|
139
|
+
if (!config.cache)
|
|
140
|
+
config.cache = {};
|
|
141
|
+
config.cache.root = process.env.CACHE_ROOT;
|
|
142
|
+
}
|
|
115
143
|
if (process.env.MAX_SAMPLE_SIZE) {
|
|
116
144
|
if (!config.workspace)
|
|
117
145
|
config.workspace = {};
|
|
@@ -139,6 +167,11 @@ export function loadConfigFromEnv() {
|
|
|
139
167
|
config.logging = {};
|
|
140
168
|
config.logging.level = process.env.LOG_LEVEL;
|
|
141
169
|
}
|
|
170
|
+
if (process.env.AUDIT_LOG_PATH) {
|
|
171
|
+
if (!config.logging)
|
|
172
|
+
config.logging = {};
|
|
173
|
+
config.logging.auditPath = process.env.AUDIT_LOG_PATH;
|
|
174
|
+
}
|
|
142
175
|
return config;
|
|
143
176
|
}
|
|
144
177
|
/**
|
|
@@ -176,7 +209,8 @@ export function mergeConfigs(...configs) {
|
|
|
176
209
|
* Load and validate configuration from all sources
|
|
177
210
|
*/
|
|
178
211
|
export function loadConfig(configPath) {
|
|
179
|
-
const
|
|
212
|
+
const resolvedConfigPath = configPath || process.env.CONFIG_PATH || getDefaultConfigPath();
|
|
213
|
+
const fileConfig = loadConfigFromFile(resolvedConfigPath);
|
|
180
214
|
const envConfig = loadConfigFromEnv();
|
|
181
215
|
const mergedConfig = mergeConfigs(fileConfig, envConfig);
|
|
182
216
|
const result = ConfigSchema.safeParse(mergedConfig);
|
package/dist/database.js
CHANGED
|
@@ -9,84 +9,84 @@ import { logger, logDebug } from './logger.js';
|
|
|
9
9
|
/**
|
|
10
10
|
* Database schema SQL statements
|
|
11
11
|
*/
|
|
12
|
-
const SCHEMA_SQL = `
|
|
13
|
-
-- samples 表:存储样本基础信息
|
|
14
|
-
CREATE TABLE IF NOT EXISTS samples (
|
|
15
|
-
id TEXT PRIMARY KEY,
|
|
16
|
-
sha256 TEXT UNIQUE NOT NULL,
|
|
17
|
-
md5 TEXT,
|
|
18
|
-
size INTEGER NOT NULL,
|
|
19
|
-
file_type TEXT,
|
|
20
|
-
created_at TEXT NOT NULL,
|
|
21
|
-
source TEXT
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
CREATE INDEX IF NOT EXISTS idx_samples_sha256 ON samples(sha256);
|
|
25
|
-
CREATE INDEX IF NOT EXISTS idx_samples_created_at ON samples(created_at);
|
|
26
|
-
|
|
27
|
-
-- analyses 表:存储分析任务记录
|
|
28
|
-
CREATE TABLE IF NOT EXISTS analyses (
|
|
29
|
-
id TEXT PRIMARY KEY,
|
|
30
|
-
sample_id TEXT NOT NULL,
|
|
31
|
-
stage TEXT NOT NULL,
|
|
32
|
-
backend TEXT NOT NULL,
|
|
33
|
-
status TEXT NOT NULL,
|
|
34
|
-
started_at TEXT,
|
|
35
|
-
finished_at TEXT,
|
|
36
|
-
output_json TEXT,
|
|
37
|
-
metrics_json TEXT,
|
|
38
|
-
FOREIGN KEY (sample_id) REFERENCES samples(id)
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
CREATE INDEX IF NOT EXISTS idx_analyses_sample_stage ON analyses(sample_id, stage);
|
|
42
|
-
CREATE INDEX IF NOT EXISTS idx_analyses_status ON analyses(status);
|
|
43
|
-
|
|
44
|
-
-- functions 表:存储函数信息
|
|
45
|
-
CREATE TABLE IF NOT EXISTS functions (
|
|
46
|
-
sample_id TEXT NOT NULL,
|
|
47
|
-
address TEXT NOT NULL,
|
|
48
|
-
name TEXT,
|
|
49
|
-
size INTEGER,
|
|
50
|
-
score REAL,
|
|
51
|
-
tags TEXT,
|
|
52
|
-
summary TEXT,
|
|
53
|
-
caller_count INTEGER DEFAULT 0,
|
|
54
|
-
callee_count INTEGER DEFAULT 0,
|
|
55
|
-
is_entry_point INTEGER DEFAULT 0,
|
|
56
|
-
is_exported INTEGER DEFAULT 0,
|
|
57
|
-
callees TEXT,
|
|
58
|
-
PRIMARY KEY (sample_id, address),
|
|
59
|
-
FOREIGN KEY (sample_id) REFERENCES samples(id)
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
CREATE INDEX IF NOT EXISTS idx_functions_name ON functions(sample_id, name);
|
|
63
|
-
CREATE INDEX IF NOT EXISTS idx_functions_score ON functions(sample_id, score DESC);
|
|
64
|
-
|
|
65
|
-
-- artifacts 表:存储分析产物
|
|
66
|
-
CREATE TABLE IF NOT EXISTS artifacts (
|
|
67
|
-
id TEXT PRIMARY KEY,
|
|
68
|
-
sample_id TEXT NOT NULL,
|
|
69
|
-
type TEXT NOT NULL,
|
|
70
|
-
path TEXT NOT NULL,
|
|
71
|
-
sha256 TEXT NOT NULL,
|
|
72
|
-
mime TEXT,
|
|
73
|
-
created_at TEXT NOT NULL,
|
|
74
|
-
FOREIGN KEY (sample_id) REFERENCES samples(id)
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
CREATE INDEX IF NOT EXISTS idx_artifacts_sample_type ON artifacts(sample_id, type);
|
|
78
|
-
|
|
79
|
-
-- cache 表:存储缓存结果
|
|
80
|
-
CREATE TABLE IF NOT EXISTS cache (
|
|
81
|
-
key TEXT PRIMARY KEY,
|
|
82
|
-
data TEXT NOT NULL,
|
|
83
|
-
sample_sha256 TEXT,
|
|
84
|
-
created_at TEXT NOT NULL,
|
|
85
|
-
expires_at TEXT
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
CREATE INDEX IF NOT EXISTS idx_cache_expires_at ON cache(expires_at);
|
|
89
|
-
CREATE INDEX IF NOT EXISTS idx_cache_sample_sha256 ON cache(sample_sha256);
|
|
12
|
+
const SCHEMA_SQL = `
|
|
13
|
+
-- samples 表:存储样本基础信息
|
|
14
|
+
CREATE TABLE IF NOT EXISTS samples (
|
|
15
|
+
id TEXT PRIMARY KEY,
|
|
16
|
+
sha256 TEXT UNIQUE NOT NULL,
|
|
17
|
+
md5 TEXT,
|
|
18
|
+
size INTEGER NOT NULL,
|
|
19
|
+
file_type TEXT,
|
|
20
|
+
created_at TEXT NOT NULL,
|
|
21
|
+
source TEXT
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
CREATE INDEX IF NOT EXISTS idx_samples_sha256 ON samples(sha256);
|
|
25
|
+
CREATE INDEX IF NOT EXISTS idx_samples_created_at ON samples(created_at);
|
|
26
|
+
|
|
27
|
+
-- analyses 表:存储分析任务记录
|
|
28
|
+
CREATE TABLE IF NOT EXISTS analyses (
|
|
29
|
+
id TEXT PRIMARY KEY,
|
|
30
|
+
sample_id TEXT NOT NULL,
|
|
31
|
+
stage TEXT NOT NULL,
|
|
32
|
+
backend TEXT NOT NULL,
|
|
33
|
+
status TEXT NOT NULL,
|
|
34
|
+
started_at TEXT,
|
|
35
|
+
finished_at TEXT,
|
|
36
|
+
output_json TEXT,
|
|
37
|
+
metrics_json TEXT,
|
|
38
|
+
FOREIGN KEY (sample_id) REFERENCES samples(id)
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
CREATE INDEX IF NOT EXISTS idx_analyses_sample_stage ON analyses(sample_id, stage);
|
|
42
|
+
CREATE INDEX IF NOT EXISTS idx_analyses_status ON analyses(status);
|
|
43
|
+
|
|
44
|
+
-- functions 表:存储函数信息
|
|
45
|
+
CREATE TABLE IF NOT EXISTS functions (
|
|
46
|
+
sample_id TEXT NOT NULL,
|
|
47
|
+
address TEXT NOT NULL,
|
|
48
|
+
name TEXT,
|
|
49
|
+
size INTEGER,
|
|
50
|
+
score REAL,
|
|
51
|
+
tags TEXT,
|
|
52
|
+
summary TEXT,
|
|
53
|
+
caller_count INTEGER DEFAULT 0,
|
|
54
|
+
callee_count INTEGER DEFAULT 0,
|
|
55
|
+
is_entry_point INTEGER DEFAULT 0,
|
|
56
|
+
is_exported INTEGER DEFAULT 0,
|
|
57
|
+
callees TEXT,
|
|
58
|
+
PRIMARY KEY (sample_id, address),
|
|
59
|
+
FOREIGN KEY (sample_id) REFERENCES samples(id)
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
CREATE INDEX IF NOT EXISTS idx_functions_name ON functions(sample_id, name);
|
|
63
|
+
CREATE INDEX IF NOT EXISTS idx_functions_score ON functions(sample_id, score DESC);
|
|
64
|
+
|
|
65
|
+
-- artifacts 表:存储分析产物
|
|
66
|
+
CREATE TABLE IF NOT EXISTS artifacts (
|
|
67
|
+
id TEXT PRIMARY KEY,
|
|
68
|
+
sample_id TEXT NOT NULL,
|
|
69
|
+
type TEXT NOT NULL,
|
|
70
|
+
path TEXT NOT NULL,
|
|
71
|
+
sha256 TEXT NOT NULL,
|
|
72
|
+
mime TEXT,
|
|
73
|
+
created_at TEXT NOT NULL,
|
|
74
|
+
FOREIGN KEY (sample_id) REFERENCES samples(id)
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
CREATE INDEX IF NOT EXISTS idx_artifacts_sample_type ON artifacts(sample_id, type);
|
|
78
|
+
|
|
79
|
+
-- cache 表:存储缓存结果
|
|
80
|
+
CREATE TABLE IF NOT EXISTS cache (
|
|
81
|
+
key TEXT PRIMARY KEY,
|
|
82
|
+
data TEXT NOT NULL,
|
|
83
|
+
sample_sha256 TEXT,
|
|
84
|
+
created_at TEXT NOT NULL,
|
|
85
|
+
expires_at TEXT
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
CREATE INDEX IF NOT EXISTS idx_cache_expires_at ON cache(expires_at);
|
|
89
|
+
CREATE INDEX IF NOT EXISTS idx_cache_sample_sha256 ON cache(sample_sha256);
|
|
90
90
|
`;
|
|
91
91
|
/**
|
|
92
92
|
* Database manager class
|
|
@@ -139,9 +139,9 @@ export class DatabaseManager {
|
|
|
139
139
|
* Insert a new sample
|
|
140
140
|
*/
|
|
141
141
|
insertSample(sample) {
|
|
142
|
-
const stmt = this.db.prepare(`
|
|
143
|
-
INSERT INTO samples (id, sha256, md5, size, file_type, created_at, source)
|
|
144
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
142
|
+
const stmt = this.db.prepare(`
|
|
143
|
+
INSERT INTO samples (id, sha256, md5, size, file_type, created_at, source)
|
|
144
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
145
145
|
`);
|
|
146
146
|
stmt.run(sample.id, sample.sha256, sample.md5, sample.size, sample.file_type, sample.created_at, sample.source);
|
|
147
147
|
}
|
|
@@ -164,9 +164,9 @@ export class DatabaseManager {
|
|
|
164
164
|
* Insert a new analysis
|
|
165
165
|
*/
|
|
166
166
|
insertAnalysis(analysis) {
|
|
167
|
-
const stmt = this.db.prepare(`
|
|
168
|
-
INSERT INTO analyses (id, sample_id, stage, backend, status, started_at, finished_at, output_json, metrics_json)
|
|
169
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
167
|
+
const stmt = this.db.prepare(`
|
|
168
|
+
INSERT INTO analyses (id, sample_id, stage, backend, status, started_at, finished_at, output_json, metrics_json)
|
|
169
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
170
170
|
`);
|
|
171
171
|
stmt.run(analysis.id, analysis.sample_id, analysis.stage, analysis.backend, analysis.status, analysis.started_at, analysis.finished_at, analysis.output_json, analysis.metrics_json);
|
|
172
172
|
}
|
|
@@ -208,8 +208,8 @@ export class DatabaseManager {
|
|
|
208
208
|
return; // No updates to perform
|
|
209
209
|
}
|
|
210
210
|
values.push(analysisId);
|
|
211
|
-
const stmt = this.db.prepare(`
|
|
212
|
-
UPDATE analyses SET ${fields.join(', ')} WHERE id = ?
|
|
211
|
+
const stmt = this.db.prepare(`
|
|
212
|
+
UPDATE analyses SET ${fields.join(', ')} WHERE id = ?
|
|
213
213
|
`);
|
|
214
214
|
stmt.run(...values);
|
|
215
215
|
}
|
|
@@ -337,9 +337,9 @@ export class DatabaseManager {
|
|
|
337
337
|
* Insert a new function
|
|
338
338
|
*/
|
|
339
339
|
insertFunction(func) {
|
|
340
|
-
const stmt = this.db.prepare(`
|
|
341
|
-
INSERT INTO functions (sample_id, address, name, size, score, tags, summary, caller_count, callee_count, is_entry_point, is_exported, callees)
|
|
342
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
340
|
+
const stmt = this.db.prepare(`
|
|
341
|
+
INSERT INTO functions (sample_id, address, name, size, score, tags, summary, caller_count, callee_count, is_entry_point, is_exported, callees)
|
|
342
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
343
343
|
`);
|
|
344
344
|
stmt.run(func.sample_id, func.address, func.name, func.size, func.score, func.tags, func.summary, func.caller_count ?? 0, func.callee_count ?? 0, func.is_entry_point ?? 0, func.is_exported ?? 0, func.callees);
|
|
345
345
|
}
|
|
@@ -391,8 +391,8 @@ export class DatabaseManager {
|
|
|
391
391
|
return; // No updates to perform
|
|
392
392
|
}
|
|
393
393
|
values.push(sampleId, address);
|
|
394
|
-
const stmt = this.db.prepare(`
|
|
395
|
-
UPDATE functions SET ${fields.join(', ')} WHERE sample_id = ? AND address = ?
|
|
394
|
+
const stmt = this.db.prepare(`
|
|
395
|
+
UPDATE functions SET ${fields.join(', ')} WHERE sample_id = ? AND address = ?
|
|
396
396
|
`);
|
|
397
397
|
stmt.run(...values);
|
|
398
398
|
}
|
|
@@ -401,9 +401,9 @@ export class DatabaseManager {
|
|
|
401
401
|
* Insert a new artifact
|
|
402
402
|
*/
|
|
403
403
|
insertArtifact(artifact) {
|
|
404
|
-
const stmt = this.db.prepare(`
|
|
405
|
-
INSERT INTO artifacts (id, sample_id, type, path, sha256, mime, created_at)
|
|
406
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
404
|
+
const stmt = this.db.prepare(`
|
|
405
|
+
INSERT INTO artifacts (id, sample_id, type, path, sha256, mime, created_at)
|
|
406
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
407
407
|
`);
|
|
408
408
|
stmt.run(artifact.id, artifact.sample_id, artifact.type, artifact.path, artifact.sha256, artifact.mime, artifact.created_at);
|
|
409
409
|
}
|
|
@@ -452,9 +452,9 @@ export class DatabaseManager {
|
|
|
452
452
|
* Requirements: 20.5
|
|
453
453
|
*/
|
|
454
454
|
async setCachedResult(key, data, expiresAt, sampleSha256) {
|
|
455
|
-
const stmt = this.db.prepare(`
|
|
456
|
-
INSERT OR REPLACE INTO cache (key, data, sample_sha256, created_at, expires_at)
|
|
457
|
-
VALUES (?, ?, ?, ?, ?)
|
|
455
|
+
const stmt = this.db.prepare(`
|
|
456
|
+
INSERT OR REPLACE INTO cache (key, data, sample_sha256, created_at, expires_at)
|
|
457
|
+
VALUES (?, ?, ?, ?, ?)
|
|
458
458
|
`);
|
|
459
459
|
stmt.run(key, JSON.stringify(data), sampleSha256 || null, new Date().toISOString(), expiresAt || null);
|
|
460
460
|
}
|
|
@@ -474,12 +474,12 @@ export class DatabaseManager {
|
|
|
474
474
|
* @returns Array of cache entries ordered by creation time (most recent first)
|
|
475
475
|
*/
|
|
476
476
|
async getRecentCacheEntries(limit) {
|
|
477
|
-
const stmt = this.db.prepare(`
|
|
478
|
-
SELECT key, data, expires_at
|
|
479
|
-
FROM cache
|
|
480
|
-
WHERE expires_at IS NULL OR expires_at > ?
|
|
481
|
-
ORDER BY created_at DESC
|
|
482
|
-
LIMIT ?
|
|
477
|
+
const stmt = this.db.prepare(`
|
|
478
|
+
SELECT key, data, expires_at
|
|
479
|
+
FROM cache
|
|
480
|
+
WHERE expires_at IS NULL OR expires_at > ?
|
|
481
|
+
ORDER BY created_at DESC
|
|
482
|
+
LIMIT ?
|
|
483
483
|
`);
|
|
484
484
|
return stmt.all(new Date().toISOString(), limit);
|
|
485
485
|
}
|
|
@@ -492,12 +492,12 @@ export class DatabaseManager {
|
|
|
492
492
|
*/
|
|
493
493
|
async getCacheEntriesBySample(sampleSha256) {
|
|
494
494
|
// Query cache entries by sample_sha256 column
|
|
495
|
-
const stmt = this.db.prepare(`
|
|
496
|
-
SELECT key, data, expires_at
|
|
497
|
-
FROM cache
|
|
498
|
-
WHERE sample_sha256 = ?
|
|
499
|
-
AND (expires_at IS NULL OR expires_at > ?)
|
|
500
|
-
ORDER BY created_at DESC
|
|
495
|
+
const stmt = this.db.prepare(`
|
|
496
|
+
SELECT key, data, expires_at
|
|
497
|
+
FROM cache
|
|
498
|
+
WHERE sample_sha256 = ?
|
|
499
|
+
AND (expires_at IS NULL OR expires_at > ?)
|
|
500
|
+
ORDER BY created_at DESC
|
|
501
501
|
`);
|
|
502
502
|
return stmt.all(sampleSha256, new Date().toISOString());
|
|
503
503
|
}
|
|
@@ -512,9 +512,9 @@ export class DatabaseManager {
|
|
|
512
512
|
return;
|
|
513
513
|
}
|
|
514
514
|
// Use transaction for batch insert
|
|
515
|
-
const insertStmt = this.db.prepare(`
|
|
516
|
-
INSERT OR REPLACE INTO functions (sample_id, address, name, size, score, tags, summary, caller_count, callee_count, is_entry_point, is_exported, callees)
|
|
517
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
515
|
+
const insertStmt = this.db.prepare(`
|
|
516
|
+
INSERT OR REPLACE INTO functions (sample_id, address, name, size, score, tags, summary, caller_count, callee_count, is_entry_point, is_exported, callees)
|
|
517
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
518
518
|
`);
|
|
519
519
|
const insertMany = this.db.transaction((funcs) => {
|
|
520
520
|
for (const func of funcs) {
|
|
@@ -534,9 +534,9 @@ export class DatabaseManager {
|
|
|
534
534
|
return;
|
|
535
535
|
}
|
|
536
536
|
// Use transaction for batch insert
|
|
537
|
-
const insertStmt = this.db.prepare(`
|
|
538
|
-
INSERT INTO artifacts (id, sample_id, type, path, sha256, mime, created_at)
|
|
539
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
537
|
+
const insertStmt = this.db.prepare(`
|
|
538
|
+
INSERT INTO artifacts (id, sample_id, type, path, sha256, mime, created_at)
|
|
539
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
540
540
|
`);
|
|
541
541
|
const insertMany = this.db.transaction((arts) => {
|
|
542
542
|
for (const artifact of arts) {
|
|
@@ -22,6 +22,10 @@ export interface GhidraOptions {
|
|
|
22
22
|
analysisOptions?: Record<string, unknown>;
|
|
23
23
|
timeout?: number;
|
|
24
24
|
maxCpu?: string;
|
|
25
|
+
processor?: string;
|
|
26
|
+
languageId?: string;
|
|
27
|
+
cspec?: string;
|
|
28
|
+
scriptPaths?: string[];
|
|
25
29
|
abortSignal?: AbortSignal;
|
|
26
30
|
}
|
|
27
31
|
/**
|
|
@@ -243,11 +247,10 @@ export declare class DecompilerWorker {
|
|
|
243
247
|
private delay;
|
|
244
248
|
private isProjectLockFailure;
|
|
245
249
|
private runWithProjectLockRetry;
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
private resolveSamplePath;
|
|
250
|
+
private resolveSamplePathForSample;
|
|
251
|
+
private getAlternateWorkspaceRoot;
|
|
252
|
+
private findLatestProjectInGhidraDir;
|
|
253
|
+
private findRecoveredProject;
|
|
251
254
|
/**
|
|
252
255
|
* Spawn Ghidra process with Windows batch-script compatibility.
|
|
253
256
|
* On Windows, spawning .bat/.cmd directly can throw EINVAL; route through
|
|
@@ -257,12 +260,14 @@ export declare class DecompilerWorker {
|
|
|
257
260
|
private buildProcessDiagnostics;
|
|
258
261
|
private runGhidraCommand;
|
|
259
262
|
private buildAnalyzeBaseArgs;
|
|
263
|
+
private buildScriptPath;
|
|
260
264
|
private buildAnalysisArgs;
|
|
261
265
|
private buildExtractFunctionsArgs;
|
|
262
266
|
private executeMainAnalysis;
|
|
263
267
|
private executeFunctionExtractionScript;
|
|
264
268
|
private tryExtractFunctionsWithFallback;
|
|
265
269
|
private selectProbeTarget;
|
|
270
|
+
private tryRecoverFunctionsFromPE;
|
|
266
271
|
private buildCapabilityReadyStatus;
|
|
267
272
|
private buildCapabilityFailureStatus;
|
|
268
273
|
private probeCapability;
|