@jshookmcp/jshook 0.1.7 → 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 (44) hide show
  1. package/README.md +145 -100
  2. package/README.zh.md +81 -36
  3. package/dist/constants.d.ts +1 -1
  4. package/dist/constants.js +3 -1
  5. package/dist/modules/analyzer/QualityAnalyzer.js +1 -1
  6. package/dist/modules/browser/BrowserDiscovery.js +2 -2
  7. package/dist/modules/browser/BrowserModeManager.js +3 -3
  8. package/dist/modules/captcha/AICaptchaDetector.d.ts +12 -16
  9. package/dist/modules/captcha/AICaptchaDetector.js +209 -189
  10. package/dist/modules/captcha/CaptchaDetector.constants.d.ts +2 -0
  11. package/dist/modules/captcha/CaptchaDetector.constants.js +116 -25
  12. package/dist/modules/captcha/CaptchaDetector.d.ts +2 -11
  13. package/dist/modules/captcha/CaptchaDetector.js +102 -51
  14. package/dist/modules/captcha/types.d.ts +46 -0
  15. package/dist/modules/captcha/types.js +52 -0
  16. package/dist/modules/deobfuscator/AdvancedDeobfuscator.d.ts +15 -20
  17. package/dist/modules/deobfuscator/AdvancedDeobfuscator.js +66 -234
  18. package/dist/modules/deobfuscator/Deobfuscator.d.ts +3 -10
  19. package/dist/modules/deobfuscator/Deobfuscator.js +125 -404
  20. package/dist/modules/deobfuscator/webcrack.d.ts +13 -0
  21. package/dist/modules/deobfuscator/webcrack.js +164 -0
  22. package/dist/modules/detector/ObfuscationDetector.d.ts +6 -0
  23. package/dist/modules/detector/ObfuscationDetector.js +53 -2
  24. package/dist/modules/hook/AIHookGenerator.js +1 -1
  25. package/dist/modules/process/memory/writer.js +1 -1
  26. package/dist/server/domains/analysis/definitions.js +223 -2
  27. package/dist/server/domains/analysis/handlers.impl.d.ts +2 -3
  28. package/dist/server/domains/analysis/handlers.impl.js +60 -15
  29. package/dist/server/domains/analysis/manifest.js +2 -5
  30. package/dist/server/domains/browser/definitions.tools.behavior.js +36 -24
  31. package/dist/server/domains/browser/definitions.tools.security.js +13 -10
  32. package/dist/server/domains/browser/handlers/camoufox-flow.js +0 -1
  33. package/dist/server/domains/browser/handlers/captcha-solver.d.ts +1 -1
  34. package/dist/server/domains/browser/handlers/captcha-solver.js +121 -54
  35. package/dist/server/domains/browser/handlers/page-navigation.js +0 -2
  36. package/dist/server/domains/browser/handlers.impl.d.ts +1 -1
  37. package/dist/server/domains/browser/handlers.impl.js +3 -3
  38. package/dist/server/domains/browser/manifest.js +1 -1
  39. package/dist/server/domains/shared/modules.d.ts +1 -0
  40. package/dist/types/deobfuscator.d.ts +43 -1
  41. package/dist/types/index.d.ts +1 -1
  42. package/dist/utils/config.js +19 -10
  43. package/package.json +6 -3
  44. package/scripts/postinstall.cjs +37 -0
@@ -1,252 +1,84 @@
1
1
  import { logger } from '../../utils/logger.js';
2
- import { ADV_DEOBF_LLM_MAX_TOKENS } from '../../constants.js';
3
- import { generateCodeCleanupMessages, generateControlFlowUnflatteningMessages, } from '../../services/prompts/deobfuscation.js';
4
- import { VMDeobfuscator } from '../deobfuscator/VMDeobfuscator.js';
5
- import { applyASTOptimizations as applyASTOptimizationsUtil, decodeStrings as decodeStringsUtil, derotateStringArray as derotateStringArrayUtil, estimateCodeComplexity as estimateCodeComplexityUtil, removeDeadCode as removeDeadCodeUtil, removeOpaquePredicates as removeOpaquePredicatesUtil, } from '../deobfuscator/AdvancedDeobfuscator.ast.js';
2
+ import { runWebcrack } from '../deobfuscator/webcrack.js';
3
+ import { detectObfuscationType as detectObfuscationTypeUtil } from '../deobfuscator/Deobfuscator.utils.js';
6
4
  export class AdvancedDeobfuscator {
7
- llm;
8
- vmDeobfuscator;
9
- constructor(llm) {
10
- this.llm = llm;
11
- this.vmDeobfuscator = new VMDeobfuscator(llm);
12
- }
13
5
  async deobfuscate(options) {
14
- logger.info('Starting advanced deobfuscation...');
15
- const startTime = Date.now();
16
- let code = options.code;
17
- const detectedTechniques = [];
6
+ logger.info('Starting advanced webcrack deobfuscation...');
7
+ const detectedTechniques = detectObfuscationTypeUtil(options.code);
18
8
  const warnings = [];
19
- let vmDetected;
20
- let astOptimized = false;
21
- try {
22
- code = this.normalizeCode(code);
23
- if (this.detectInvisibleUnicode(code)) {
24
- detectedTechniques.push('invisible-unicode');
25
- logger.info('Detected: Invisible Unicode Obfuscation');
26
- code = this.decodeInvisibleUnicode(code);
27
- }
28
- if (this.detectStringEncoding(code)) {
29
- detectedTechniques.push('string-encoding');
30
- logger.info('Detected: String Encoding');
31
- code = this.decodeStrings(code);
32
- }
33
- const vmInfo = this.vmDeobfuscator.detectVMProtection(code);
34
- if (vmInfo.detected) {
35
- detectedTechniques.push('vm-protection');
36
- logger.info(`Detected: VM Protection (${vmInfo.type})`);
37
- vmDetected = {
38
- type: vmInfo.type,
39
- instructions: vmInfo.instructionCount,
40
- deobfuscated: false,
41
- };
42
- if (options.aggressiveVM) {
43
- const vmResult = await this.vmDeobfuscator.deobfuscateVM(code, vmInfo);
44
- if (vmResult.success) {
45
- code = vmResult.code;
46
- vmDetected.deobfuscated = true;
47
- }
48
- else {
49
- warnings.push('VM deobfuscation failed, code may be incomplete');
50
- }
51
- }
52
- }
53
- if (this.detectControlFlowFlattening(code)) {
54
- detectedTechniques.push('control-flow-flattening');
55
- logger.info('Detected: Control Flow Flattening');
56
- code = await this.unflattenControlFlow(code);
57
- }
58
- if (this.detectStringArrayRotation(code)) {
59
- detectedTechniques.push('string-array-rotation');
60
- logger.info('Detected: String Array Rotation');
61
- code = this.derotateStringArray(code);
62
- }
63
- if (this.detectDeadCodeInjection(code)) {
64
- detectedTechniques.push('dead-code-injection');
65
- logger.info('Detected: Dead Code Injection');
66
- code = this.removeDeadCode(code);
67
- }
68
- if (this.detectOpaquePredicates(code)) {
69
- detectedTechniques.push('opaque-predicates');
70
- logger.info('Detected: Opaque Predicates');
71
- code = this.removeOpaquePredicates(code);
72
- }
73
- if (options.useASTOptimization !== false) {
74
- logger.info('Applying AST optimizations...');
75
- const optimized = this.applyASTOptimizations(code);
76
- if (optimized !== code) {
77
- code = optimized;
78
- astOptimized = true;
79
- detectedTechniques.push('ast-optimized');
80
- }
81
- }
82
- if (this.llm && detectedTechniques.length > 0) {
83
- logger.info('Using LLM for final cleanup...');
84
- const llmResult = await this.llmCleanup(code, detectedTechniques);
85
- if (llmResult) {
86
- code = llmResult;
87
- }
88
- }
89
- const duration = Date.now() - startTime;
90
- const confidence = this.calculateConfidence(detectedTechniques, warnings, code);
91
- logger.success(`Advanced deobfuscation completed in ${duration}ms`);
9
+ if (options.aggressiveVM !== undefined) {
10
+ warnings.push('aggressiveVM is deprecated and ignored; VM-specific legacy logic has been removed.');
11
+ }
12
+ if (options.useASTOptimization !== undefined) {
13
+ warnings.push('useASTOptimization is deprecated and ignored; legacy AST post-processing has been removed.');
14
+ }
15
+ if (options.timeout !== undefined) {
16
+ warnings.push('timeout is currently ignored; webcrack controls its own execution flow.');
17
+ }
18
+ if (options.detectOnly) {
92
19
  return {
93
- code,
20
+ code: options.code,
94
21
  detectedTechniques,
95
- confidence,
96
- warnings,
97
- vmDetected,
98
- astOptimized,
22
+ confidence: Math.min(0.6 + detectedTechniques.length * 0.05, 0.9),
23
+ warnings: [
24
+ ...warnings,
25
+ 'detectOnly does not invoke a separate legacy detector anymore; techniques are inferred from the current static signature pass.',
26
+ ],
27
+ astOptimized: false,
28
+ engine: 'webcrack',
29
+ webcrackApplied: false,
99
30
  };
100
31
  }
101
- catch (error) {
102
- logger.error('Advanced deobfuscation failed', error);
103
- throw error;
32
+ const webcrackResult = await runWebcrack(options.code, {
33
+ unpack: options.unpack,
34
+ unminify: options.unminify,
35
+ jsx: options.jsx,
36
+ mangle: options.mangle,
37
+ mappings: options.mappings,
38
+ includeModuleCode: options.includeModuleCode,
39
+ maxBundleModules: options.maxBundleModules,
40
+ outputDir: options.outputDir,
41
+ forceOutput: options.forceOutput,
42
+ });
43
+ if (!webcrackResult.applied) {
44
+ const reason = webcrackResult.reason ?? 'webcrack did not return a result';
45
+ logger.error(`advanced webcrack deobfuscation failed: ${reason}`);
46
+ throw new Error(reason);
104
47
  }
105
- }
106
- detectInvisibleUnicode(code) {
107
- const invisibleChars = ['\u200B', '\u200C', '\u200D', '\u2060', '\uFEFF'];
108
- return invisibleChars.some((char) => code.includes(char));
109
- }
110
- decodeInvisibleUnicode(code) {
111
- logger.info('Decoding invisible unicode...');
112
- const charToBit = {
113
- '\u200B': '0',
114
- '\u200C': '1',
115
- '\u200D': '00',
116
- '\u2060': '01',
117
- '\uFEFF': '10',
118
- };
119
- let decoded = code;
120
- const invisiblePattern = /[\u200B\u200C\u200D\u2060\uFEFF]+/g;
121
- const matches = code.match(invisiblePattern);
122
- if (matches) {
123
- matches.forEach((match) => {
124
- let binary = '';
125
- for (const char of match) {
126
- binary += charToBit[char] || '';
127
- }
128
- if (binary.length % 8 === 0) {
129
- let text = '';
130
- for (let i = 0; i < binary.length; i += 8) {
131
- const byte = binary.substring(i, i + 8);
132
- text += String.fromCharCode(parseInt(byte, 2));
133
- }
134
- decoded = decoded.replace(match, text);
135
- }
136
- });
48
+ if (webcrackResult.bundle) {
49
+ detectedTechniques.push('bundle-unpack');
137
50
  }
138
- return decoded;
139
- }
140
- detectControlFlowFlattening(code) {
141
- const pattern = /while\s*\(\s*!!\s*\[\s*\]\s*\)\s*\{[\s\S]*?switch\s*\(/i;
142
- return pattern.test(code);
143
- }
144
- async unflattenControlFlow(code) {
145
- logger.info('Unflattening control flow...');
146
- if (this.llm) {
147
- try {
148
- const codeSnippet = code.length > 2000 ? code.slice(0, 2000) + '\n...(truncated)' : code;
149
- const response = await this.llm.chat(generateControlFlowUnflatteningMessages(codeSnippet), {
150
- temperature: 0.1,
151
- maxTokens: ADV_DEOBF_LLM_MAX_TOKENS,
152
- });
153
- return this.vmDeobfuscator.extractCodeFromLLMResponse(response.content);
154
- }
155
- catch (error) {
156
- logger.warn('LLM control flow unflattening failed', error);
157
- }
51
+ if (webcrackResult.optionsUsed.unminify) {
52
+ detectedTechniques.push('unminify');
158
53
  }
159
- return code;
160
- }
161
- detectStringArrayRotation(code) {
162
- return /\w+\s*=\s*\w+\s*\+\s*0x[0-9a-f]+/.test(code);
163
- }
164
- derotateStringArray(code) {
165
- return derotateStringArrayUtil(code);
166
- }
167
- detectDeadCodeInjection(code) {
168
- return /if\s*\(\s*false\s*\)|if\s*\(\s*!!\s*\[\s*\]\s*\)/.test(code);
169
- }
170
- removeDeadCode(code) {
171
- return removeDeadCodeUtil(code);
172
- }
173
- detectOpaquePredicates(code) {
174
- return /if\s*\(\s*\d+\s*[<>!=]+\s*\d+\s*\)/.test(code);
175
- }
176
- removeOpaquePredicates(code) {
177
- return removeOpaquePredicatesUtil(code);
178
- }
179
- async llmCleanup(code, techniques) {
180
- if (!this.llm)
181
- return null;
182
- try {
183
- const response = await this.llm.chat(generateCodeCleanupMessages(code, techniques), {
184
- temperature: 0.15,
185
- maxTokens: 3000,
186
- });
187
- const cleanedCode = this.vmDeobfuscator.extractCodeFromLLMResponse(response.content);
188
- if (this.vmDeobfuscator.isValidJavaScript(cleanedCode)) {
189
- logger.success('LLM cleanup succeeded');
190
- return cleanedCode;
191
- }
192
- else {
193
- logger.warn('LLM cleanup produced invalid JavaScript');
194
- return null;
195
- }
54
+ if (webcrackResult.optionsUsed.jsx) {
55
+ detectedTechniques.push('jsx-decompile');
196
56
  }
197
- catch (error) {
198
- logger.warn('LLM cleanup failed', error);
199
- return null;
57
+ if (webcrackResult.optionsUsed.mangle) {
58
+ detectedTechniques.push('mangle');
200
59
  }
60
+ detectedTechniques.push('webcrack');
61
+ return {
62
+ code: webcrackResult.code,
63
+ detectedTechniques: Array.from(new Set(detectedTechniques)),
64
+ confidence: this.calculateConfidence(webcrackResult, detectedTechniques),
65
+ warnings,
66
+ astOptimized: false,
67
+ bundle: webcrackResult.bundle,
68
+ savedTo: webcrackResult.savedTo,
69
+ savedArtifacts: webcrackResult.savedArtifacts,
70
+ engine: 'webcrack',
71
+ webcrackApplied: true,
72
+ };
201
73
  }
202
- normalizeCode(code) {
203
- code = code.replace(/\s+/g, ' ');
204
- code = code.replace(/\/\*[\s\S]*?\*\//g, '');
205
- code = code.replace(/\/\/.*/g, '');
206
- return code.trim();
207
- }
208
- detectStringEncoding(code) {
209
- const patterns = [/\\x[0-9a-f]{2}/i, /\\u[0-9a-f]{4}/i, /String\.fromCharCode/i, /atob\(/i];
210
- return patterns.some((p) => p.test(code));
211
- }
212
- decodeStrings(code) {
213
- return decodeStringsUtil(code);
214
- }
215
- applyASTOptimizations(code) {
216
- return applyASTOptimizationsUtil(code);
217
- }
218
- calculateConfidence(techniques, warnings, code) {
219
- let confidence = 0.3;
220
- const techniqueBonus = Math.min(techniques.length * 0.12, 0.5);
221
- confidence += techniqueBonus;
222
- const warningPenalty = warnings.length * 0.08;
223
- confidence -= warningPenalty;
224
- const highConfidenceTechniques = [
225
- 'invisible-unicode',
226
- 'string-array-rotation',
227
- 'dead-code-injection',
228
- 'opaque-predicates',
229
- 'string-encoding',
230
- 'ast-optimized',
231
- ];
232
- const highConfidenceCount = techniques.filter((t) => highConfidenceTechniques.some((ht) => t.includes(ht))).length;
233
- confidence += highConfidenceCount * 0.05;
234
- if (techniques.some((t) => t.includes('vm-protection'))) {
235
- confidence -= 0.15;
74
+ calculateConfidence(webcrackResult, detectedTechniques) {
75
+ let confidence = 0.72 + detectedTechniques.length * 0.03;
76
+ if (webcrackResult.bundle) {
77
+ confidence += 0.08;
236
78
  }
237
- if (techniques.some((t) => t.includes('control-flow-flattening'))) {
238
- confidence -= 0.05;
79
+ if (webcrackResult.savedTo) {
80
+ confidence += 0.04;
239
81
  }
240
- const complexity = this.estimateCodeComplexity(code);
241
- if (complexity < 10) {
242
- confidence += 0.1;
243
- }
244
- else if (complexity > 100) {
245
- confidence -= 0.1;
246
- }
247
- return Math.max(0.1, Math.min(0.95, confidence));
248
- }
249
- estimateCodeComplexity(code) {
250
- return estimateCodeComplexityUtil(code);
82
+ return Math.min(confidence, 0.99);
251
83
  }
252
84
  }
@@ -2,21 +2,14 @@ import type { DeobfuscateOptions, DeobfuscateResult } from '../../types/index.js
2
2
  import { LLMService } from '../../services/LLMService.js';
3
3
  export declare class Deobfuscator {
4
4
  private llm?;
5
- private stringArrays;
6
5
  private resultCache;
7
6
  private maxCacheSize;
8
7
  constructor(llm?: LLMService);
9
8
  private generateCacheKey;
10
9
  deobfuscate(options: DeobfuscateOptions): Promise<DeobfuscateResult>;
11
10
  private detectObfuscationType;
12
- private basicTransform;
13
- private decodeStrings;
14
- private llmAnalysis;
15
- private calculateConfidence;
16
- private extractStringArrays;
17
- private decryptArrays;
18
- private unflattenControlFlow;
19
- private simplifyExpressions;
20
- private renameVariables;
21
11
  private calculateReadabilityScore;
12
+ private calculateConfidence;
13
+ private buildAnalysis;
14
+ private llmAnalysis;
22
15
  }