/** * 完整反混淆脚本 v3 - 更强大的字符串解码 * 策略:先执行完整的解码器设置,再遍历所有可能的调用参数 */ const fs = require('fs'); const path = require('path'); const vm = require('vm'); const deobfuscateIO = require('obfuscator-io-deobfuscator').deobfuscate; const beautify = require('js-beautify').js; const outputDir = 'D:/temp/破解/cursorpro-0.4.5/deobfuscated_full/extension/out'; function ensureDir(dir) { if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } } /** * 提取并执行完整的解码器设置代码 */ function setupFullDecoder(code) { // 查找字符串数组函数名 const arrayFuncMatch = code.match(/function\s+(_0x[a-f0-9]+)\s*\(\)\s*\{/); if (!arrayFuncMatch) { console.log(' 未找到字符串数组函数'); return null; } const arrayFuncName = arrayFuncMatch[1]; // 查找解码函数 - 更宽松的匹配 const decoderPatterns = [ /function\s+(_0x[a-f0-9]+)\s*\(\s*_0x[a-f0-9]+\s*,\s*_0x[a-f0-9]+\s*\)\s*\{\s*const\s+_0x[a-f0-9]+\s*=\s*_0x[a-f0-9]+\s*\(\s*\)\s*;/, /function\s+(_0x[a-f0-9]+)\s*\(\s*_0x[a-f0-9]+\s*,\s*_0x[a-f0-9]+\s*\)\s*\{/ ]; let decoderFuncName = null; for (const pattern of decoderPatterns) { const match = code.match(pattern); if (match) { decoderFuncName = match[1]; break; } } if (!decoderFuncName) { console.log(' 未找到解码函数'); return null; } console.log(` 字符串数组函数: ${arrayFuncName}`); console.log(` 解码函数: ${decoderFuncName}`); // 提取从开头到解码函数结束的所有代码 // 找到解码函数的结束位置 const decoderStart = code.indexOf(`function ${decoderFuncName}(`); if (decoderStart === -1) { console.log(' 未找到解码函数定义'); return null; } // 找到解码函数的结束 let braceCount = 0; let decoderEnd = decoderStart; let foundStart = false; for (let i = decoderStart; i < code.length; i++) { if (code[i] === '{') { braceCount++; foundStart = true; } else if (code[i] === '}') { braceCount--; if (foundStart && braceCount === 0) { decoderEnd = i + 1; break; } } } // 提取从文件开头到解码函数结束的所有代码 // 这包括 vip 变量、IIFE、数组函数、解码函数 const setupCode = code.substring(0, decoderEnd); // 创建沙盒并执行 const sandbox = { console: { log: () => {}, warn: () => {}, error: () => {} }, parseInt: parseInt, String: String, decodeURIComponent: decodeURIComponent }; try { vm.runInNewContext(setupCode, sandbox); // 检查解码函数是否可用 const testResult = vm.runInNewContext(`typeof ${decoderFuncName}`, sandbox); if (testResult !== 'function') { console.log(` 解码函数不可用: ${testResult}`); return null; } console.log(` 解码器设置成功`); return { sandbox, decoderFuncName, arrayFuncName, setupCode }; } catch (e) { console.log(` 沙盒执行失败: ${e.message}`); // 尝试更激进的方法 - 执行整个文件的前半部分 return setupAggressiveDecoder(code, decoderFuncName, arrayFuncName); } } /** * 更激进的解码器设置 - 执行更多代码 */ function setupAggressiveDecoder(code, decoderFuncName, arrayFuncName) { console.log(' 尝试激进模式...'); // 找到第一个 exports 或 Object.defineProperty 之前的所有代码 const exportIndex = Math.min( code.indexOf('Object.defineProperty(exports') !== -1 ? code.indexOf('Object.defineProperty(exports') : Infinity, code.indexOf('exports.') !== -1 ? code.indexOf('exports.') : Infinity ); if (exportIndex === Infinity) { console.log(' 未找到 exports 边界'); return null; } const setupCode = code.substring(0, exportIndex); const sandbox = { console: { log: () => {}, warn: () => {}, error: () => {} }, parseInt: parseInt, String: String, decodeURIComponent: decodeURIComponent, this: {}, Object: Object }; try { vm.runInNewContext(setupCode, sandbox); const testResult = vm.runInNewContext(`typeof ${decoderFuncName}`, sandbox); if (testResult === 'function') { console.log(` 激进模式成功`); return { sandbox, decoderFuncName, arrayFuncName, setupCode }; } } catch (e) { console.log(` 激进模式失败: ${e.message}`); } return null; } /** * 收集并解码所有字符串调用 */ function decodeAllStrings(code, decoder) { if (!decoder) return { code, decodedCount: 0 }; const { sandbox, decoderFuncName } = decoder; // 收集所有解码函数别名 const aliasPattern = new RegExp(`const\\s+(_0x[a-f0-9]+)\\s*=\\s*${decoderFuncName}\\s*;`, 'g'); const aliases = [decoderFuncName]; let match; while ((match = aliasPattern.exec(code)) !== null) { aliases.push(match[1]); } console.log(` 解码函数别名: ${aliases.join(', ')}`); // 构建所有可能的调用模式 const decodedMap = new Map(); let totalFound = 0; for (const alias of aliases) { // 匹配多种调用格式 const patterns = [ new RegExp(`${alias}\\s*\\(\\s*(0x[a-f0-9]+)\\s*,\\s*'([^']*)'\\s*\\)`, 'g'), new RegExp(`${alias}\\s*\\(\\s*(0x[a-f0-9]+)\\s*,\\s*"([^"]*)"\\s*\\)`, 'g'), ]; for (const pattern of patterns) { let callMatch; while ((callMatch = pattern.exec(code)) !== null) { const fullMatch = callMatch[0]; const num = callMatch[1]; const key = callMatch[2]; if (!decodedMap.has(fullMatch)) { try { const decoded = vm.runInNewContext( `${decoderFuncName}(${num},'${key.replace(/'/g, "\\'")}')`, sandbox ); if (typeof decoded === 'string') { decodedMap.set(fullMatch, decoded); totalFound++; } } catch (e) { // 解码失败,跳过 } } } } } console.log(` 找到 ${totalFound} 个字符串调用`); // 替换所有解码后的字符串 let decodedCount = 0; for (const [original, decoded] of decodedMap) { // 选择合适的引号 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 escapedOriginal = original.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); const regex = new RegExp(escapedOriginal, 'g'); const before = code.length; code = code.replace(regex, replacement); if (code.length !== before) { decodedCount++; } } console.log(` 替换了 ${decodedCount} 个不同的字符串`); // 移除解码器代码(可选,让代码更干净) // 注释掉解码器相关代码而不是删除 return { code, decodedCount }; } /** * 清理混淆的变量引用 */ function cleanObfuscatedReferences(code) { // 将 obj['property'] 转换为 obj.property code = code.replace(/\['([a-zA-Z_$][a-zA-Z0-9_$]*)'\]/g, '.$1'); // 简化 !![] 为 true code = code.replace(/!!\[\]/g, 'true'); // 简化 ![] 为 false 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; } } /** * 处理单个文件 */ async function processFile(inputPath, outputPath, filename) { 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 decoder = setupFullDecoder(code); // Step 2: 解码所有字符串 console.log('\nStep 2: 解码字符串...'); const decodeResult = decodeAllStrings(code, decoder); code = decodeResult.code; // Step 3: 清理混淆引用 console.log('\nStep 3: 清理混淆引用...'); code = cleanObfuscatedReferences(code); // Step 4: AST 清洗 console.log('\nStep 4: AST 清洗...'); code = astClean(code, filename); // Step 5: 再次清理(AST 可能引入新的混淆) console.log('\nStep 5: 二次清理...'); code = cleanObfuscatedReferences(code); // Step 6: 美化 console.log('\nStep 6: 美化代码...'); 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('║ 完整反混淆脚本 v3 ║'); console.log('║ 完整解码器执行 + 批量字符串替换 + AST清洗 ║'); console.log('╚════════════════════════════════════════════════════╝\n'); const files = [ { input: 'D:/temp/破解/cursorpro-0.4.5/原版本/extension/out/webview/provider.js', output: 'webview/provider.js' }, { input: 'D:/temp/破解/cursorpro-0.4.5/原版本/extension/out/extension.js', output: 'extension.js' }, { input: 'D:/temp/破解/cursorpro-0.4.5/原版本/extension/out/utils/account.js', output: 'utils/account.js' }, { input: 'D:/temp/破解/cursorpro-0.4.5/原版本/extension/out/utils/sqlite.js', output: 'utils/sqlite.js' }, { input: 'D:/temp/破解/cursorpro-0.4.5/原版本/extension/out/api/client.js', output: 'api/client.js' }, ]; for (const file of files) { if (fs.existsSync(file.input)) { await processFile(file.input, path.join(outputDir, file.output), file.output); } else { console.log(`\n跳过: ${file.input} (不存在)`); } } console.log('\n╔════════════════════════════════════════════════════╗'); console.log('║ 完成! ║'); console.log('╚════════════════════════════════════════════════════╝'); console.log(`\n输出目录: ${outputDir}`); } main().catch(console.error);