windows-exe-decompiler-mcp-server 0.1.0 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/CLAUDE_INSTALLATION.md +129 -0
  2. package/CODEX_INSTALLATION.md +25 -1
  3. package/COPILOT_INSTALLATION.md +29 -1
  4. package/LICENSE +21 -21
  5. package/README.md +232 -110
  6. package/dist/analysis-provenance.d.ts +50 -2
  7. package/dist/analysis-provenance.js +1 -0
  8. package/dist/analysis-task-runner.js +92 -0
  9. package/dist/config.d.ts +35 -16
  10. package/dist/config.js +37 -3
  11. package/dist/database.js +115 -115
  12. package/dist/decompiler-worker.d.ts +10 -5
  13. package/dist/decompiler-worker.js +240 -58
  14. package/dist/dynamic-trace.d.ts +6 -0
  15. package/dist/dynamic-trace.js +52 -1
  16. package/dist/ghidra-config.js +17 -1
  17. package/dist/index.js +38 -8
  18. package/dist/pe-runtime-functions.d.ts +90 -0
  19. package/dist/pe-runtime-functions.js +452 -0
  20. package/dist/prompts/module-reconstruction-review.d.ts +5 -0
  21. package/dist/prompts/module-reconstruction-review.js +65 -0
  22. package/dist/runtime-correlation.d.ts +5 -0
  23. package/dist/runtime-correlation.js +179 -2
  24. package/dist/sample-workspace.d.ts +28 -0
  25. package/dist/sample-workspace.js +186 -0
  26. package/dist/semantic-name-suggestion-artifacts.d.ts +56 -0
  27. package/dist/semantic-name-suggestion-artifacts.js +87 -0
  28. package/dist/server.js +1 -1
  29. package/dist/setup-guidance.d.ts +73 -0
  30. package/dist/setup-guidance.js +211 -0
  31. package/dist/tools/artifact-read.d.ts +10 -10
  32. package/dist/tools/artifacts-diff.d.ts +8 -8
  33. package/dist/tools/artifacts-list.d.ts +16 -16
  34. package/dist/tools/attack-map.d.ts +8 -8
  35. package/dist/tools/binary-role-profile.d.ts +1197 -0
  36. package/dist/tools/binary-role-profile.js +575 -0
  37. package/dist/tools/code-function-explain-apply.d.ts +12 -12
  38. package/dist/tools/code-function-explain-prepare.d.ts +12 -12
  39. package/dist/tools/code-function-explain-review.d.ts +58 -58
  40. package/dist/tools/code-function-rename-apply.d.ts +12 -12
  41. package/dist/tools/code-function-rename-prepare.d.ts +14 -14
  42. package/dist/tools/code-function-rename-review.d.ts +66 -66
  43. package/dist/tools/code-functions-define.d.ts +337 -0
  44. package/dist/tools/code-functions-define.js +337 -0
  45. package/dist/tools/code-functions-list.js +1 -1
  46. package/dist/tools/code-functions-rank.js +1 -1
  47. package/dist/tools/code-functions-reconstruct.d.ts +368 -58
  48. package/dist/tools/code-functions-reconstruct.js +130 -10
  49. package/dist/tools/code-functions-smart-recover.d.ts +352 -0
  50. package/dist/tools/code-functions-smart-recover.js +190 -0
  51. package/dist/tools/code-module-review-apply.d.ts +233 -0
  52. package/dist/tools/code-module-review-apply.js +209 -0
  53. package/dist/tools/code-module-review-prepare.d.ts +756 -0
  54. package/dist/tools/code-module-review-prepare.js +343 -0
  55. package/dist/tools/code-module-review.d.ts +474 -0
  56. package/dist/tools/code-module-review.js +566 -0
  57. package/dist/tools/code-reconstruct-export.d.ts +193 -21
  58. package/dist/tools/code-reconstruct-export.js +578 -21
  59. package/dist/tools/code-reconstruct-plan.d.ts +20 -20
  60. package/dist/tools/com-role-profile.d.ts +353 -0
  61. package/dist/tools/com-role-profile.js +186 -0
  62. package/dist/tools/dll-export-profile.d.ts +625 -0
  63. package/dist/tools/dll-export-profile.js +230 -0
  64. package/dist/tools/dotnet-metadata-extract.d.ts +122 -122
  65. package/dist/tools/dotnet-reconstruct-export.d.ts +49 -49
  66. package/dist/tools/dotnet-types-list.d.ts +66 -66
  67. package/dist/tools/dynamic-dependencies.d.ts +144 -8
  68. package/dist/tools/dynamic-dependencies.js +20 -1
  69. package/dist/tools/dynamic-memory-import.js +105 -2
  70. package/dist/tools/ghidra-analyze.d.ts +20 -0
  71. package/dist/tools/ghidra-analyze.js +10 -2
  72. package/dist/tools/ghidra-health.d.ts +177 -0
  73. package/dist/tools/ghidra-health.js +28 -0
  74. package/dist/tools/ioc-export.d.ts +8 -8
  75. package/dist/tools/packer-detect.d.ts +14 -14
  76. package/dist/tools/packer-detect.js +6 -9
  77. package/dist/tools/pe-exports-extract.d.ts +8 -8
  78. package/dist/tools/pe-exports-extract.js +6 -9
  79. package/dist/tools/pe-fingerprint.d.ts +36 -36
  80. package/dist/tools/pe-imports-extract.d.ts +8 -8
  81. package/dist/tools/pe-imports-extract.js +6 -9
  82. package/dist/tools/pe-pdata-extract.d.ts +448 -0
  83. package/dist/tools/pe-pdata-extract.js +219 -0
  84. package/dist/tools/pe-symbols-recover.d.ts +227 -0
  85. package/dist/tools/pe-symbols-recover.js +316 -0
  86. package/dist/tools/report-generate.d.ts +15 -1
  87. package/dist/tools/report-generate.js +139 -16
  88. package/dist/tools/report-summarize.d.ts +2242 -8
  89. package/dist/tools/report-summarize.js +246 -10
  90. package/dist/tools/runtime-detect.d.ts +8 -8
  91. package/dist/tools/runtime-detect.js +2 -12
  92. package/dist/tools/rust-binary-analyze.d.ts +2047 -0
  93. package/dist/tools/rust-binary-analyze.js +443 -0
  94. package/dist/tools/sample-profile-get.d.ts +135 -16
  95. package/dist/tools/sample-profile-get.js +35 -32
  96. package/dist/tools/sandbox-execute.d.ts +10 -10
  97. package/dist/tools/strings-extract.d.ts +8 -8
  98. package/dist/tools/strings-extract.js +2 -12
  99. package/dist/tools/strings-floss-decode.d.ts +8 -8
  100. package/dist/tools/system-health.d.ts +172 -36
  101. package/dist/tools/system-health.js +14 -0
  102. package/dist/tools/system-setup-guide.d.ts +179 -0
  103. package/dist/tools/system-setup-guide.js +62 -0
  104. package/dist/tools/tool-help.d.ts +16 -16
  105. package/dist/tools/tool-help.js +172 -0
  106. package/dist/tools/yara-scan.d.ts +8 -8
  107. package/dist/types.d.ts +2 -0
  108. package/dist/workflows/function-explanation-review.d.ts +3034 -76
  109. package/dist/workflows/function-explanation-review.js +172 -42
  110. package/dist/workflows/function-index-recover.d.ts +333 -0
  111. package/dist/workflows/function-index-recover.js +291 -0
  112. package/dist/workflows/module-reconstruction-review.d.ts +3537 -0
  113. package/dist/workflows/module-reconstruction-review.js +354 -0
  114. package/dist/workflows/reconstruct.d.ts +2182 -223
  115. package/dist/workflows/reconstruct.js +575 -32
  116. package/dist/workflows/semantic-name-review.d.ts +1436 -85
  117. package/dist/workflows/semantic-name-review.js +150 -58
  118. package/dist/workflows/triage.d.ts +8 -8
  119. package/ghidra_scripts/DecompileFunction.java +487 -487
  120. package/ghidra_scripts/ExtractCFG.java +256 -256
  121. package/ghidra_scripts/ExtractFunctions.java +442 -442
  122. package/ghidra_scripts/README.md +112 -112
  123. package/ghidra_scripts/SearchFunctionReferences.java +380 -380
  124. package/helpers/DotNetMetadataProbe/DotNetMetadataProbe.csproj +9 -9
  125. package/helpers/DotNetMetadataProbe/Program.cs +566 -566
  126. package/install-to-claude.ps1 +432 -0
  127. package/install-to-codex.ps1 +256 -178
  128. package/install-to-copilot.ps1 +389 -303
  129. package/package.json +4 -2
  130. package/requirements.txt +9 -9
  131. package/workers/requirements-dynamic.txt +11 -11
  132. package/workers/requirements.txt +8 -8
  133. package/workers/speakeasy_compat.py +175 -175
  134. package/workers/static_worker.py +3474 -3474
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.ZodOptional<z.ZodString>;
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().optional(),
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('./workspaces'),
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 fileConfig = configPath ? loadConfigFromFile(configPath) : {};
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
- * Resolve sample file path in workspace/original.
248
- * Prefer legacy "sample.exe" name, then fall back to first regular file.
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;