/** * 完整反混淆脚本 v4 - 使用预计算的解码映射 * 策略:读取已有的 decoded_map.json 文件,直接替换字符串 */ const fs = require('fs'); const path = require('path'); const deobfuscateIO = require('obfuscator-io-deobfuscator').deobfuscate; const beautify = require('js-beautify').js; const baseDir = 'D:/temp/破解/cursorpro-0.4.5'; const outputDir = path.join(baseDir, 'deobfuscated_full/extension/out'); function ensureDir(dir) { if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } } /** * 加载解码映射 */ function loadDecodeMap(mapPath) { if (!fs.existsSync(mapPath)) { console.log(` 映射文件不存在: ${mapPath}`); return null; } try { const map = JSON.parse(fs.readFileSync(mapPath, 'utf8')); console.log(` 加载了 ${Object.keys(map).length} 个解码映射`); return map; } catch (e) { console.log(` 加载映射失败: ${e.message}`); return null; } } /** * 使用映射替换字符串 */ function replaceWithMap(code, decodeMap) { if (!decodeMap) return { code, count: 0 }; let count = 0; for (const [pattern, decoded] of Object.entries(decodeMap)) { // 转义正则特殊字符 const escapedPattern = pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); const regex = new RegExp(escapedPattern, 'g'); // 选择合适的引号 let replacement; if (decoded.includes('\n') || decoded.includes('\r')) { replacement = '`' + decoded.replace(/`/g, '\\`').replace(/\$/g, '\\$') + '`'; } else if (decoded.includes("'") && !decoded.includes('"')) { replacement = JSON.stringify(decoded); } else { replacement = `'${decoded.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`; } const before = code; code = code.replace(regex, replacement); if (code !== before) { count++; } } console.log(` 替换了 ${count} 个字符串模式`); return { code, count }; } /** * 清理混淆的引用 */ function cleanObfuscatedReferences(code) { // 将 obj['property'] 转换为 obj.property code = code.replace(/\['([a-zA-Z_$][a-zA-Z0-9_$]*)'\]/g, '.$1'); // 简化布尔值 code = code.replace(/!!\[\]/g, 'true'); code = code.replace(/!\[\]/g, 'false'); return code; } /** * AST 清洗 */ function astClean(code, filename) { try { console.log(` [AST] 处理...`); return deobfuscateIO(code); } catch (e) { console.log(` [AST] 失败: ${e.message}`); return code; } } /** * 移除解码器相关代码 */ function removeDecoderCode(code) { // 移除字符串数组函数(大量字符串数组) code = code.replace(/function\s+_0x[a-f0-9]+\s*\(\)\s*\{\s*const\s+_0x[a-f0-9]+\s*=\s*function\s*\(\)\s*\{\s*return\s*\[[^\]]*\]\.concat\(function\s*\(\)\s*\{[\s\S]*?\}\(\)\)[\s\S]*?\};[\s\S]*?return\s+_0x[a-f0-9]+;\s*\}/g, '/* [STRING_ARRAY_REMOVED] */'); // 移除解码函数 code = code.replace(/function\s+_0x[a-f0-9]+\s*\(\s*_0x[a-f0-9]+\s*,\s*_0x[a-f0-9]+\s*\)\s*\{[\s\S]*?return\s+_0x[a-f0-9]+\s*\(\s*_0x[a-f0-9]+\s*,\s*_0x[a-f0-9]+\s*\)\s*;\s*\}/g, '/* [DECODER_REMOVED] */'); // 移除 IIFE 初始化 code = code.replace(/;\s*\(function\s*\(\s*_0x[a-f0-9]+[\s\S]*?\)\s*\)\s*\(\s*0x[a-f0-9]+\s*,\s*0x[a-f0-9]+\s*,\s*_0x[a-f0-9]+\s*,\s*0x[a-f0-9]+\s*\)\s*;/g, '/* [IIFE_REMOVED] */'); return code; } /** * 处理单个文件 */ async function processFile(inputPath, outputPath, filename, mapPath) { console.log(`\n${'='.repeat(50)}`); console.log(`处理: ${filename}`); console.log('='.repeat(50)); let code = fs.readFileSync(inputPath, 'utf8'); console.log(`原始大小: ${(code.length / 1024).toFixed(2)} KB`); // Step 1: 加载解码映射 console.log('\nStep 1: 加载解码映射...'); const decodeMap = loadDecodeMap(mapPath); // Step 2: 替换字符串 console.log('\nStep 2: 替换字符串...'); const replaceResult = replaceWithMap(code, decodeMap); code = replaceResult.code; // Step 3: 移除解码器代码 console.log('\nStep 3: 移除解码器代码...'); code = removeDecoderCode(code); // Step 4: 清理混淆引用 console.log('\nStep 4: 清理混淆引用...'); code = cleanObfuscatedReferences(code); // Step 5: AST 清洗 console.log('\nStep 5: AST 清洗...'); code = astClean(code, filename); // Step 6: 再次清理 console.log('\nStep 6: 二次清理...'); code = cleanObfuscatedReferences(code); // Step 7: 美化 console.log('\nStep 7: 美化代码...'); code = beautify(code, { indent_size: 4, preserve_newlines: true, max_preserve_newlines: 2, space_in_empty_paren: true, jslint_happy: false, brace_style: 'collapse' }); console.log(`\n处理后大小: ${(code.length / 1024).toFixed(2)} KB`); // 保存 ensureDir(path.dirname(outputPath)); fs.writeFileSync(outputPath, code); console.log(`已保存: ${outputPath}`); } // 主函数 async function main() { console.log('╔════════════════════════════════════════════════════════╗'); console.log('║ 完整反混淆脚本 v4 ║'); console.log('║ 使用预计算解码映射 + AST清洗 + 美化 ║'); console.log('╚════════════════════════════════════════════════════════╝\n'); // 首先为每个文件生成解码映射(如果不存在) const files = [ { input: path.join(baseDir, '原版本/extension/out/webview/provider.js'), output: 'webview/provider.js', map: path.join(baseDir, 'provider_decoded_map.json') }, { input: path.join(baseDir, '原版本/extension/out/extension.js'), output: 'extension.js', map: path.join(baseDir, 'extension_decoded_map.json') }, { input: path.join(baseDir, '原版本/extension/out/utils/account.js'), output: 'utils/account.js', map: path.join(baseDir, 'account_decoded_map.json') }, { input: path.join(baseDir, '原版本/extension/out/utils/sqlite.js'), output: 'utils/sqlite.js', map: path.join(baseDir, 'sqlite_decoded_map.json') }, { input: path.join(baseDir, '原版本/extension/out/api/client.js'), output: 'api/client.js', map: path.join(baseDir, 'client_decoded_map.json') } ]; for (const file of files) { if (fs.existsSync(file.input)) { await processFile(file.input, path.join(outputDir, file.output), file.output, file.map); } else { console.log(`\n跳过: ${file.input} (不存在)`); } } console.log('\n╔════════════════════════════════════════════════════════╗'); console.log('║ 完成! ║'); console.log('╚════════════════════════════════════════════════════════╝'); console.log(`\n输出目录: ${outputDir}`); } main().catch(console.error);