@jshookmcp/jshook 0.1.6 → 0.1.8

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 (65) hide show
  1. package/LICENSE +661 -661
  2. package/README.md +145 -100
  3. package/README.zh.md +81 -36
  4. package/dist/constants.d.ts +1 -1
  5. package/dist/constants.js +3 -1
  6. package/dist/index.js +0 -0
  7. package/dist/modules/analyzer/QualityAnalyzer.js +1 -1
  8. package/dist/modules/browser/BrowserDiscovery.js +2 -2
  9. package/dist/modules/browser/BrowserModeManager.js +3 -3
  10. package/dist/modules/captcha/AICaptchaDetector.d.ts +12 -16
  11. package/dist/modules/captcha/AICaptchaDetector.js +229 -209
  12. package/dist/modules/captcha/CaptchaDetector.constants.d.ts +2 -0
  13. package/dist/modules/captcha/CaptchaDetector.constants.js +116 -25
  14. package/dist/modules/captcha/CaptchaDetector.d.ts +2 -11
  15. package/dist/modules/captcha/CaptchaDetector.js +102 -51
  16. package/dist/modules/captcha/types.d.ts +46 -0
  17. package/dist/modules/captcha/types.js +52 -0
  18. package/dist/modules/deobfuscator/AdvancedDeobfuscator.d.ts +15 -20
  19. package/dist/modules/deobfuscator/AdvancedDeobfuscator.js +66 -234
  20. package/dist/modules/deobfuscator/Deobfuscator.d.ts +3 -10
  21. package/dist/modules/deobfuscator/Deobfuscator.js +125 -404
  22. package/dist/modules/deobfuscator/webcrack.d.ts +13 -0
  23. package/dist/modules/deobfuscator/webcrack.js +164 -0
  24. package/dist/modules/detector/ObfuscationDetector.d.ts +6 -0
  25. package/dist/modules/detector/ObfuscationDetector.js +53 -2
  26. package/dist/modules/hook/AIHookGenerator.js +1 -1
  27. package/dist/modules/process/MacProcessManager.js +25 -25
  28. package/dist/modules/process/memory/availability.js +49 -49
  29. package/dist/modules/process/memory/injector.js +185 -185
  30. package/dist/modules/process/memory/reader.js +50 -50
  31. package/dist/modules/process/memory/scanner.js +165 -165
  32. package/dist/modules/process/memory/writer.js +55 -55
  33. package/dist/native/scripts/linux/enum-windows.sh +12 -12
  34. package/dist/native/scripts/macos/enum-windows.applescript +22 -22
  35. package/dist/native/scripts/windows/enum-windows-by-class.ps1 +51 -51
  36. package/dist/native/scripts/windows/enum-windows.ps1 +44 -44
  37. package/dist/native/scripts/windows/inject-dll.ps1 +21 -21
  38. package/dist/server/domains/analysis/definitions.js +223 -2
  39. package/dist/server/domains/analysis/handlers.impl.d.ts +2 -3
  40. package/dist/server/domains/analysis/handlers.impl.js +60 -15
  41. package/dist/server/domains/analysis/manifest.js +2 -5
  42. package/dist/server/domains/browser/definitions.tools.behavior.js +36 -24
  43. package/dist/server/domains/browser/definitions.tools.page-core.js +53 -53
  44. package/dist/server/domains/browser/definitions.tools.runtime.js +40 -40
  45. package/dist/server/domains/browser/definitions.tools.security.js +80 -77
  46. package/dist/server/domains/browser/handlers/camoufox-flow.js +0 -1
  47. package/dist/server/domains/browser/handlers/captcha-solver.d.ts +1 -1
  48. package/dist/server/domains/browser/handlers/captcha-solver.js +121 -54
  49. package/dist/server/domains/browser/handlers/page-navigation.js +0 -2
  50. package/dist/server/domains/browser/handlers.impl.d.ts +1 -1
  51. package/dist/server/domains/browser/handlers.impl.js +3 -3
  52. package/dist/server/domains/browser/manifest.js +1 -1
  53. package/dist/server/domains/shared/modules.d.ts +1 -0
  54. package/dist/server/domains/transform/handlers.impl.transform-base.js +102 -102
  55. package/dist/server/domains/workflow/handlers.impl.workflow-base.js +51 -51
  56. package/dist/types/deobfuscator.d.ts +43 -1
  57. package/dist/types/index.d.ts +1 -1
  58. package/dist/utils/config.js +19 -10
  59. package/package.json +30 -44
  60. package/scripts/postinstall.cjs +37 -0
  61. package/src/native/scripts/linux/enum-windows.sh +12 -12
  62. package/src/native/scripts/macos/enum-windows.applescript +22 -22
  63. package/src/native/scripts/windows/enum-windows-by-class.ps1 +51 -51
  64. package/src/native/scripts/windows/enum-windows.ps1 +44 -44
  65. package/src/native/scripts/windows/inject-dll.ps1 +21 -21
@@ -1,44 +1,44 @@
1
- param(
2
- [int]$TargetPid
3
- )
4
-
5
- Add-Type @"
6
- using System;
7
- using System.Runtime.InteropServices;
8
- public class Win32 {
9
- [DllImport("user32.dll")] public static extern IntPtr FindWindowEx(IntPtr parent, IntPtr childAfter, string className, string title);
10
- [DllImport("user32.dll")] public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int pid);
11
- [DllImport("user32.dll")] public static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder text, int count);
12
- [DllImport("user32.dll")] public static extern int GetClassName(IntPtr hWnd, System.Text.StringBuilder className, int maxCount);
13
- [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr hWnd, out RECT rect);
14
- [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left, Top, Right, Bottom; }
15
- }
16
- "@
17
-
18
- $windows = @()
19
- $hwnd = [IntPtr]::Zero
20
- while ($true) {
21
- $hwnd = [Win32]::FindWindowEx([IntPtr]::Zero, $hwnd, $null, $null)
22
- if ($hwnd -eq [IntPtr]::Zero) { break }
23
- $windowPid = 0
24
- [Win32]::GetWindowThreadProcessId($hwnd, [ref]$windowPid) | Out-Null
25
- if ($windowPid -eq $TargetPid) {
26
- $title = New-Object System.Text.StringBuilder 256
27
- $className = New-Object System.Text.StringBuilder 256
28
- [Win32]::GetWindowText($hwnd, $title, 256) | Out-Null
29
- [Win32]::GetClassName($hwnd, $className, 256) | Out-Null
30
- $rect = New-Object Win32+RECT
31
- [Win32]::GetWindowRect($hwnd, [ref]$rect) | Out-Null
32
- $windows += @{
33
- Handle = $hwnd.ToString()
34
- Title = $title.ToString()
35
- ClassName = $className.ToString()
36
- ProcessId = $windowPid
37
- Left = $rect.Left
38
- Top = $rect.Top
39
- Right = $rect.Right
40
- Bottom = $rect.Bottom
41
- }
42
- }
43
- }
44
- $windows | ConvertTo-Json -Compress
1
+ param(
2
+ [int]$TargetPid
3
+ )
4
+
5
+ Add-Type @"
6
+ using System;
7
+ using System.Runtime.InteropServices;
8
+ public class Win32 {
9
+ [DllImport("user32.dll")] public static extern IntPtr FindWindowEx(IntPtr parent, IntPtr childAfter, string className, string title);
10
+ [DllImport("user32.dll")] public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int pid);
11
+ [DllImport("user32.dll")] public static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder text, int count);
12
+ [DllImport("user32.dll")] public static extern int GetClassName(IntPtr hWnd, System.Text.StringBuilder className, int maxCount);
13
+ [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr hWnd, out RECT rect);
14
+ [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left, Top, Right, Bottom; }
15
+ }
16
+ "@
17
+
18
+ $windows = @()
19
+ $hwnd = [IntPtr]::Zero
20
+ while ($true) {
21
+ $hwnd = [Win32]::FindWindowEx([IntPtr]::Zero, $hwnd, $null, $null)
22
+ if ($hwnd -eq [IntPtr]::Zero) { break }
23
+ $windowPid = 0
24
+ [Win32]::GetWindowThreadProcessId($hwnd, [ref]$windowPid) | Out-Null
25
+ if ($windowPid -eq $TargetPid) {
26
+ $title = New-Object System.Text.StringBuilder 256
27
+ $className = New-Object System.Text.StringBuilder 256
28
+ [Win32]::GetWindowText($hwnd, $title, 256) | Out-Null
29
+ [Win32]::GetClassName($hwnd, $className, 256) | Out-Null
30
+ $rect = New-Object Win32+RECT
31
+ [Win32]::GetWindowRect($hwnd, [ref]$rect) | Out-Null
32
+ $windows += @{
33
+ Handle = $hwnd.ToString()
34
+ Title = $title.ToString()
35
+ ClassName = $className.ToString()
36
+ ProcessId = $windowPid
37
+ Left = $rect.Left
38
+ Top = $rect.Top
39
+ Right = $rect.Right
40
+ Bottom = $rect.Bottom
41
+ }
42
+ }
43
+ }
44
+ $windows | ConvertTo-Json -Compress
@@ -1,21 +1,21 @@
1
- param(
2
- [int]$TargetPid,
3
- [string]$DllPath
4
- )
5
-
6
- Add-Type @"
7
- using System;
8
- using System.Runtime.InteropServices;
9
- public class Injector {
10
- [DllImport("kernel32.dll")] public static extern IntPtr OpenProcess(int access, bool inherit, int pid);
11
- [DllImport("kernel32.dll")] public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr addr, int size, int alloc, int protect);
12
- [DllImport("kernel32.dll")] public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr addr, byte[] buffer, int size, out int written);
13
- [DllImport("kernel32.dll")] public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr attr, int stack, IntPtr start, IntPtr param, int flags, out int threadId);
14
- [DllImport("kernel32.dll")] public static extern IntPtr GetModuleHandle(string name);
15
- [DllImport("kernel32.dll")] public static extern IntPtr GetProcAddress(IntPtr hModule, string name);
16
- [DllImport("kernel32.dll")] public static extern bool CloseHandle(IntPtr handle);
17
- }
18
- "@
19
-
20
- # Injection requires elevated privileges and is disabled for safety
21
- Write-Output "DLL injection is disabled for safety in this implementation. PID: $TargetPid, DLL: $DllPath"
1
+ param(
2
+ [int]$TargetPid,
3
+ [string]$DllPath
4
+ )
5
+
6
+ Add-Type @"
7
+ using System;
8
+ using System.Runtime.InteropServices;
9
+ public class Injector {
10
+ [DllImport("kernel32.dll")] public static extern IntPtr OpenProcess(int access, bool inherit, int pid);
11
+ [DllImport("kernel32.dll")] public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr addr, int size, int alloc, int protect);
12
+ [DllImport("kernel32.dll")] public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr addr, byte[] buffer, int size, out int written);
13
+ [DllImport("kernel32.dll")] public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr attr, int stack, IntPtr start, IntPtr param, int flags, out int threadId);
14
+ [DllImport("kernel32.dll")] public static extern IntPtr GetModuleHandle(string name);
15
+ [DllImport("kernel32.dll")] public static extern IntPtr GetProcAddress(IntPtr hModule, string name);
16
+ [DllImport("kernel32.dll")] public static extern bool CloseHandle(IntPtr handle);
17
+ }
18
+ "@
19
+
20
+ # Injection requires elevated privileges and is disabled for safety
21
+ Write-Output "DLL injection is disabled for safety in this implementation. PID: $TargetPid, DLL: $DllPath"
@@ -138,7 +138,7 @@ export const coreTools = [
138
138
  },
139
139
  {
140
140
  name: 'deobfuscate',
141
- description: 'Run LLM-assisted JavaScript deobfuscation.',
141
+ description: 'Run webcrack-powered JavaScript deobfuscation with bundle unpacking support.',
142
142
  inputSchema: {
143
143
  type: 'object',
144
144
  properties: {
@@ -157,6 +157,75 @@ export const coreTools = [
157
157
  description: 'Enable aggressive deobfuscation strategy',
158
158
  default: false,
159
159
  },
160
+ unpack: {
161
+ type: 'boolean',
162
+ description: 'Use webcrack to unpack webpack/browserify bundles when possible',
163
+ default: true,
164
+ },
165
+ unminify: {
166
+ type: 'boolean',
167
+ description: 'Use webcrack to reformat and unminify code before post-processing',
168
+ default: true,
169
+ },
170
+ jsx: {
171
+ type: 'boolean',
172
+ description: 'Ask webcrack to decompile React.createElement trees back to JSX when supported',
173
+ default: true,
174
+ },
175
+ mangle: {
176
+ type: 'boolean',
177
+ description: 'Rename obfuscated identifiers using webcrack mangle pass',
178
+ default: false,
179
+ },
180
+ outputDir: {
181
+ type: 'string',
182
+ description: 'Optional directory where webcrack should save the deobfuscated code and extracted bundle',
183
+ },
184
+ forceOutput: {
185
+ type: 'boolean',
186
+ description: 'Remove outputDir before saving webcrack artifacts',
187
+ default: false,
188
+ },
189
+ includeModuleCode: {
190
+ type: 'boolean',
191
+ description: 'Include unpacked module source in bundle output when returning bundle details',
192
+ default: false,
193
+ },
194
+ maxBundleModules: {
195
+ type: 'number',
196
+ description: 'Maximum number of bundle modules to return in the response',
197
+ default: 100,
198
+ },
199
+ mappings: {
200
+ type: 'array',
201
+ description: 'Optional remapping rules applied to unpacked bundle module paths. Each rule can match against module code or current path.',
202
+ items: {
203
+ type: 'object',
204
+ properties: {
205
+ path: {
206
+ type: 'string',
207
+ description: 'New module path to assign when the rule matches',
208
+ },
209
+ pattern: {
210
+ type: 'string',
211
+ description: 'Text or regex used to match module code/path',
212
+ },
213
+ matchType: {
214
+ type: 'string',
215
+ enum: ['includes', 'regex', 'exact'],
216
+ description: 'How to interpret pattern',
217
+ default: 'includes',
218
+ },
219
+ target: {
220
+ type: 'string',
221
+ enum: ['code', 'path'],
222
+ description: 'Whether to match against module source code or the current module path',
223
+ default: 'code',
224
+ },
225
+ },
226
+ required: ['path', 'pattern'],
227
+ },
228
+ },
160
229
  },
161
230
  required: ['code'],
162
231
  },
@@ -258,7 +327,7 @@ export const coreTools = [
258
327
  },
259
328
  {
260
329
  name: 'advanced_deobfuscate',
261
- description: 'Run advanced deobfuscation with VM-oriented strategies.',
330
+ description: 'Run advanced deobfuscation with webcrack backend (deprecated legacy flags ignored).',
262
331
  inputSchema: {
263
332
  type: 'object',
264
333
  properties: {
@@ -286,6 +355,158 @@ export const coreTools = [
286
355
  description: 'Operation timeout in milliseconds',
287
356
  default: 60000,
288
357
  },
358
+ unpack: {
359
+ type: 'boolean',
360
+ description: 'Use webcrack to unpack webpack/browserify bundles before advanced cleanup',
361
+ default: true,
362
+ },
363
+ unminify: {
364
+ type: 'boolean',
365
+ description: 'Use webcrack unminify pass before VM and AST-oriented cleanup',
366
+ default: true,
367
+ },
368
+ jsx: {
369
+ type: 'boolean',
370
+ description: 'Allow webcrack to decompile React.createElement back to JSX when supported',
371
+ default: true,
372
+ },
373
+ mangle: {
374
+ type: 'boolean',
375
+ description: 'Rename obfuscated identifiers during the webcrack phase',
376
+ default: false,
377
+ },
378
+ outputDir: {
379
+ type: 'string',
380
+ description: 'Optional directory where webcrack should save the deobfuscated code and extracted bundle',
381
+ },
382
+ forceOutput: {
383
+ type: 'boolean',
384
+ description: 'Remove outputDir before saving webcrack artifacts',
385
+ default: false,
386
+ },
387
+ includeModuleCode: {
388
+ type: 'boolean',
389
+ description: 'Include unpacked module source in bundle output when returning bundle details',
390
+ default: false,
391
+ },
392
+ maxBundleModules: {
393
+ type: 'number',
394
+ description: 'Maximum number of bundle modules to return in the response',
395
+ default: 100,
396
+ },
397
+ mappings: {
398
+ type: 'array',
399
+ description: 'Optional remapping rules applied to unpacked bundle module paths. Each rule can match against module code or current path.',
400
+ items: {
401
+ type: 'object',
402
+ properties: {
403
+ path: {
404
+ type: 'string',
405
+ description: 'New module path to assign when the rule matches',
406
+ },
407
+ pattern: {
408
+ type: 'string',
409
+ description: 'Text or regex used to match module code/path',
410
+ },
411
+ matchType: {
412
+ type: 'string',
413
+ enum: ['includes', 'regex', 'exact'],
414
+ description: 'How to interpret pattern',
415
+ default: 'includes',
416
+ },
417
+ target: {
418
+ type: 'string',
419
+ enum: ['code', 'path'],
420
+ description: 'Whether to match against module source code or the current module path',
421
+ default: 'code',
422
+ },
423
+ },
424
+ required: ['path', 'pattern'],
425
+ },
426
+ },
427
+ },
428
+ required: ['code'],
429
+ },
430
+ },
431
+ {
432
+ name: 'webcrack_unpack',
433
+ description: 'Run webcrack bundle unpacking directly and return extracted module graph details.',
434
+ inputSchema: {
435
+ type: 'object',
436
+ properties: {
437
+ code: {
438
+ type: 'string',
439
+ description: 'Bundled or obfuscated JavaScript source',
440
+ },
441
+ unpack: {
442
+ type: 'boolean',
443
+ description: 'Extract modules from the bundle when supported',
444
+ default: true,
445
+ },
446
+ unminify: {
447
+ type: 'boolean',
448
+ description: 'Unminify the code before extracting bundle modules',
449
+ default: true,
450
+ },
451
+ jsx: {
452
+ type: 'boolean',
453
+ description: 'Decompile React.createElement trees back to JSX when supported',
454
+ default: true,
455
+ },
456
+ mangle: {
457
+ type: 'boolean',
458
+ description: 'Rename obfuscated identifiers during the webcrack pass',
459
+ default: false,
460
+ },
461
+ outputDir: {
462
+ type: 'string',
463
+ description: 'Optional directory where webcrack should save the extracted bundle files',
464
+ },
465
+ forceOutput: {
466
+ type: 'boolean',
467
+ description: 'Remove outputDir before saving webcrack artifacts',
468
+ default: false,
469
+ },
470
+ includeModuleCode: {
471
+ type: 'boolean',
472
+ description: 'Include unpacked module source in bundle output',
473
+ default: false,
474
+ },
475
+ maxBundleModules: {
476
+ type: 'number',
477
+ description: 'Maximum number of bundle modules to return in the response',
478
+ default: 100,
479
+ },
480
+ mappings: {
481
+ type: 'array',
482
+ description: 'Optional remapping rules applied to unpacked bundle module paths. Each rule can match against module code or current path.',
483
+ items: {
484
+ type: 'object',
485
+ properties: {
486
+ path: {
487
+ type: 'string',
488
+ description: 'New module path to assign when the rule matches',
489
+ },
490
+ pattern: {
491
+ type: 'string',
492
+ description: 'Text or regex used to match module code/path',
493
+ },
494
+ matchType: {
495
+ type: 'string',
496
+ enum: ['includes', 'regex', 'exact'],
497
+ description: 'How to interpret pattern',
498
+ default: 'includes',
499
+ },
500
+ target: {
501
+ type: 'string',
502
+ enum: ['code', 'path'],
503
+ description: 'Whether to match against module source code or the current module path',
504
+ default: 'code',
505
+ },
506
+ },
507
+ required: ['path', 'pattern'],
508
+ },
509
+ },
289
510
  },
290
511
  required: ['code'],
291
512
  },
@@ -3,7 +3,6 @@ import { CodeCollector } from '../../domains/shared/modules.js';
3
3
  import { ScriptManager } from '../../domains/shared/modules.js';
4
4
  import { Deobfuscator } from '../../domains/shared/modules.js';
5
5
  import { AdvancedDeobfuscator } from '../../domains/shared/modules.js';
6
- import { ASTOptimizer } from '../../domains/shared/modules.js';
7
6
  import { ObfuscationDetector } from '../../domains/shared/modules.js';
8
7
  import { CodeAnalyzer } from '../../domains/shared/modules.js';
9
8
  import { CryptoDetector } from '../../domains/shared/modules.js';
@@ -13,7 +12,6 @@ interface CoreAnalysisHandlerDeps {
13
12
  scriptManager: ScriptManager;
14
13
  deobfuscator: Deobfuscator;
15
14
  advancedDeobfuscator: AdvancedDeobfuscator;
16
- astOptimizer: ASTOptimizer;
17
15
  obfuscationDetector: ObfuscationDetector;
18
16
  analyzer: CodeAnalyzer;
19
17
  cryptoDetector: CryptoDetector;
@@ -24,13 +22,13 @@ export declare class CoreAnalysisHandlers {
24
22
  private readonly scriptManager;
25
23
  private readonly deobfuscator;
26
24
  private readonly advancedDeobfuscator;
27
- private readonly astOptimizer;
28
25
  private readonly obfuscationDetector;
29
26
  private readonly analyzer;
30
27
  private readonly cryptoDetector;
31
28
  private readonly hookManager;
32
29
  constructor(deps: CoreAnalysisHandlerDeps);
33
30
  private requireCodeArg;
31
+ private extractWebcrackArgs;
34
32
  handleCollectCode(args: ToolArgs): Promise<ToolResponse>;
35
33
  handleSearchInScripts(args: ToolArgs): Promise<ToolResponse>;
36
34
  handleExtractFunctionTree(args: ToolArgs): Promise<ToolResponse>;
@@ -40,6 +38,7 @@ export declare class CoreAnalysisHandlers {
40
38
  handleManageHooks(args: ToolArgs): Promise<ToolResponse>;
41
39
  handleDetectObfuscation(args: ToolArgs): Promise<ToolResponse>;
42
40
  handleAdvancedDeobfuscate(args: ToolArgs): Promise<ToolResponse>;
41
+ handleWebcrackUnpack(args: ToolArgs): Promise<ToolResponse>;
43
42
  handleWebpackEnumerate(args: ToolArgs): Promise<ToolResponse>;
44
43
  handleSourceMapExtract(args: ToolArgs): Promise<ToolResponse>;
45
44
  handleClearCollectedData(): Promise<ToolResponse>;
@@ -1,12 +1,12 @@
1
1
  import { logger } from '../../../utils/logger.js';
2
2
  import { asJsonResponse, asTextResponse, serializeError } from '../../domains/shared/response.js';
3
3
  import { runSourceMapExtract, runWebpackEnumerate } from '../../domains/analysis/handlers.web-tools.js';
4
+ import { runWebcrack } from '../../../modules/deobfuscator/webcrack.js';
4
5
  export class CoreAnalysisHandlers {
5
6
  collector;
6
7
  scriptManager;
7
8
  deobfuscator;
8
9
  advancedDeobfuscator;
9
- astOptimizer;
10
10
  obfuscationDetector;
11
11
  analyzer;
12
12
  cryptoDetector;
@@ -16,7 +16,6 @@ export class CoreAnalysisHandlers {
16
16
  this.scriptManager = deps.scriptManager;
17
17
  this.deobfuscator = deps.deobfuscator;
18
18
  this.advancedDeobfuscator = deps.advancedDeobfuscator;
19
- this.astOptimizer = deps.astOptimizer;
20
19
  this.obfuscationDetector = deps.obfuscationDetector;
21
20
  this.analyzer = deps.analyzer;
22
21
  this.cryptoDetector = deps.cryptoDetector;
@@ -30,6 +29,33 @@ export class CoreAnalysisHandlers {
30
29
  }
31
30
  return code;
32
31
  }
32
+ extractWebcrackArgs(args) {
33
+ const extracted = {};
34
+ if (typeof args.unpack === 'boolean')
35
+ extracted.unpack = args.unpack;
36
+ if (typeof args.unminify === 'boolean')
37
+ extracted.unminify = args.unminify;
38
+ if (typeof args.jsx === 'boolean')
39
+ extracted.jsx = args.jsx;
40
+ if (typeof args.mangle === 'boolean')
41
+ extracted.mangle = args.mangle;
42
+ if (typeof args.outputDir === 'string' && args.outputDir.trim().length > 0) {
43
+ extracted.outputDir = args.outputDir;
44
+ }
45
+ if (typeof args.forceOutput === 'boolean')
46
+ extracted.forceOutput = args.forceOutput;
47
+ if (typeof args.includeModuleCode === 'boolean')
48
+ extracted.includeModuleCode = args.includeModuleCode;
49
+ if (typeof args.maxBundleModules === 'number')
50
+ extracted.maxBundleModules = args.maxBundleModules;
51
+ if (Array.isArray(args.mappings)) {
52
+ extracted.mappings = args.mappings.filter((item) => typeof item === 'object' &&
53
+ item !== null &&
54
+ typeof item.path === 'string' &&
55
+ typeof item.pattern === 'string');
56
+ }
57
+ return extracted;
58
+ }
33
59
  async handleCollectCode(args) {
34
60
  const returnSummaryOnly = args.returnSummaryOnly ?? false;
35
61
  let smartMode = args.smartMode;
@@ -200,6 +226,7 @@ export class CoreAnalysisHandlers {
200
226
  code,
201
227
  llm: args.llm,
202
228
  aggressive: args.aggressive,
229
+ ...this.extractWebcrackArgs(args),
203
230
  });
204
231
  return asJsonResponse(result);
205
232
  }
@@ -280,24 +307,42 @@ export class CoreAnalysisHandlers {
280
307
  error: 'code is required and must be a non-empty string',
281
308
  });
282
309
  }
283
- const detectOnly = args.detectOnly ?? false;
284
- const aggressiveVM = args.aggressiveVM ?? false;
285
- const useASTOptimization = args.useASTOptimization ?? true;
286
- const timeout = args.timeout ?? 60000;
287
310
  const result = await this.advancedDeobfuscator.deobfuscate({
288
311
  code,
289
- detectOnly,
290
- aggressiveVM,
291
- timeout,
312
+ ...this.extractWebcrackArgs(args),
313
+ ...(typeof args.detectOnly === 'boolean' ? { detectOnly: args.detectOnly } : {}),
314
+ ...(typeof args.aggressiveVM === 'boolean' ? { aggressiveVM: args.aggressiveVM } : {}),
315
+ ...(typeof args.useASTOptimization === 'boolean'
316
+ ? { useASTOptimization: args.useASTOptimization }
317
+ : {}),
318
+ ...(typeof args.timeout === 'number' ? { timeout: args.timeout } : {}),
292
319
  });
293
- let finalCode = result.code;
294
- if (useASTOptimization && !detectOnly) {
295
- finalCode = this.astOptimizer.optimize(finalCode);
320
+ return asJsonResponse(result);
321
+ }
322
+ async handleWebcrackUnpack(args) {
323
+ const code = this.requireCodeArg(args, 'webcrack_unpack');
324
+ if (!code) {
325
+ return asJsonResponse({
326
+ success: false,
327
+ error: 'code is required and must be a non-empty string',
328
+ });
296
329
  }
330
+ const result = await runWebcrack(code, {
331
+ unpack: args.unpack ?? true,
332
+ unminify: args.unminify ?? true,
333
+ jsx: args.jsx ?? true,
334
+ mangle: args.mangle ?? false,
335
+ ...this.extractWebcrackArgs(args),
336
+ });
297
337
  return asJsonResponse({
298
- ...result,
299
- code: finalCode,
300
- astOptimized: useASTOptimization && !detectOnly,
338
+ success: result.applied,
339
+ code: result.code,
340
+ bundle: result.bundle,
341
+ savedTo: result.savedTo,
342
+ savedArtifacts: result.savedArtifacts,
343
+ optionsUsed: result.optionsUsed,
344
+ warning: result.reason,
345
+ engine: 'webcrack',
301
346
  });
302
347
  }
303
348
  async handleWebpackEnumerate(args) {
@@ -3,7 +3,6 @@ import { coreTools } from '../../domains/analysis/definitions.js';
3
3
  import { CoreAnalysisHandlers } from '../../domains/analysis/index.js';
4
4
  import { Deobfuscator } from '../../domains/shared/modules.js';
5
5
  import { AdvancedDeobfuscator } from '../../domains/shared/modules.js';
6
- import { ASTOptimizer } from '../../domains/shared/modules.js';
7
6
  import { ObfuscationDetector } from '../../domains/shared/modules.js';
8
7
  import { CodeAnalyzer } from '../../domains/shared/modules.js';
9
8
  import { CryptoDetector } from '../../domains/shared/modules.js';
@@ -17,9 +16,7 @@ function ensure(ctx) {
17
16
  if (!ctx.deobfuscator)
18
17
  ctx.deobfuscator = new Deobfuscator(ctx.llm);
19
18
  if (!ctx.advancedDeobfuscator)
20
- ctx.advancedDeobfuscator = new AdvancedDeobfuscator(ctx.llm);
21
- if (!ctx.astOptimizer)
22
- ctx.astOptimizer = new ASTOptimizer();
19
+ ctx.advancedDeobfuscator = new AdvancedDeobfuscator();
23
20
  if (!ctx.obfuscationDetector)
24
21
  ctx.obfuscationDetector = new ObfuscationDetector();
25
22
  if (!ctx.analyzer)
@@ -34,7 +31,6 @@ function ensure(ctx) {
34
31
  scriptManager: ctx.scriptManager,
35
32
  deobfuscator: ctx.deobfuscator,
36
33
  advancedDeobfuscator: ctx.advancedDeobfuscator,
37
- astOptimizer: ctx.astOptimizer,
38
34
  obfuscationDetector: ctx.obfuscationDetector,
39
35
  analyzer: ctx.analyzer,
40
36
  cryptoDetector: ctx.cryptoDetector,
@@ -60,6 +56,7 @@ const manifest = {
60
56
  { tool: t('manage_hooks'), domain: DOMAIN, bind: b((h, a) => h.handleManageHooks(a)) },
61
57
  { tool: t('detect_obfuscation'), domain: DOMAIN, bind: b((h, a) => h.handleDetectObfuscation(a)) },
62
58
  { tool: t('advanced_deobfuscate'), domain: DOMAIN, bind: b((h, a) => h.handleAdvancedDeobfuscate(a)) },
59
+ { tool: t('webcrack_unpack'), domain: DOMAIN, bind: b((h, a) => h.handleWebcrackUnpack(a)) },
63
60
  { tool: t('clear_collected_data'), domain: DOMAIN, bind: b((h) => h.handleClearCollectedData()) },
64
61
  { tool: t('get_collection_stats'), domain: DOMAIN, bind: b((h) => h.handleGetCollectionStats()) },
65
62
  { tool: t('webpack_enumerate'), domain: DOMAIN, bind: b((h, a) => h.handleWebpackEnumerate(a)) },