/** * 第四轮 - 基于使用点的精确重命名 */ const fs = require('fs'); const babel = require('@babel/core'); const traverse = require('@babel/traverse').default; const generate = require('@babel/generator').default; const t = require('@babel/types'); const inputPath = 'D:/temp/破解/cursorpro-0.4.5/deobfuscated_full/extension/out/webview/provider.js'; const outputPath = 'D:/temp/破解/cursorpro-0.4.5/deobfuscated_full/extension/out/webview/provider.js'; console.log('╔════════════════════════════════════════════════════╗'); console.log('║ 第四轮精确变量重命名 ║'); console.log('╚════════════════════════════════════════════════════╝'); const code = fs.readFileSync(inputPath, 'utf8'); console.log(`读取文件: ${(code.length / 1024).toFixed(2)} KB`); console.log('\n[1] 解析 AST...'); let ast; try { ast = babel.parseSync(code, { sourceType: 'script' }); console.log('AST 解析成功'); } catch (e) { console.error('AST 解析失败:', e.message); process.exit(1); } const usedNames = new Map(); function getUniqueName(scope, baseName) { const key = scope.uid; if (!usedNames.has(key)) usedNames.set(key, new Set()); const used = usedNames.get(key); // 也检查 scope bindings let name = baseName; let counter = 1; while (used.has(name) || scope.hasBinding(name)) { name = baseName + counter++; } used.add(name); return name; } console.log('\n[2] 分析对象属性赋值...'); let renamedCount = 0; // 收集变量被赋值到哪些属性 const varToProps = new Map(); traverse(ast, { ObjectProperty(path) { const key = path.node.key; const value = path.node.value; // { 'prop': varXXX } if (t.isIdentifier(value) && /^(var|v)\d+$/.test(value.name)) { let propName; if (t.isStringLiteral(key)) propName = key.value; else if (t.isIdentifier(key)) propName = key.name; if (propName) { if (!varToProps.has(value.name)) { varToProps.set(value.name, new Set()); } varToProps.get(value.name).add(propName); } } } }); // 属性名到变量名的映射 const propToVarName = { 'is_injected': 'isInjected', 'workbench_path': 'workbenchPath', 'cursor_path': 'cursorPath', 'machine_id': 'machineId', 'email': 'email', 'token': 'token', 'success': 'success', 'error': 'errorMsg', 'message': 'message', 'data': 'data', 'result': 'result', 'status': 'status', 'enabled': 'enabled', 'online': 'isOnline', 'running': 'isRunning', 'installed': 'isInstalled', 'injected': 'isInjected', 'can_switch': 'canSwitch', 'switch_remaining': 'switchRemaining', 'expire_date': 'expireDate', 'version': 'version', 'path': 'filePath', 'content': 'content', 'type': 'msgType', }; // 推断变量名 const inferredNames = new Map(); for (const [varName, props] of varToProps) { for (const prop of props) { if (propToVarName[prop]) { inferredNames.set(varName, propToVarName[prop]); break; } } } console.log(`从属性推断了 ${inferredNames.size} 个变量名`); // 应用推断 traverse(ast, { VariableDeclarator(path) { if (!t.isIdentifier(path.node.id)) return; const varName = path.node.id.name; if (!inferredNames.has(varName)) return; const binding = path.scope.getBinding(varName); if (!binding) return; const newName = getUniqueName(path.scope, inferredNames.get(varName)); path.node.id.name = newName; binding.referencePaths.forEach(ref => { ref.node.name = newName; }); renamedCount++; } }); console.log(`重命名了 ${renamedCount} 个变量`); // 第二轮:基于初始化值 console.log('\n[3] 分析初始化值...'); let initCount = 0; traverse(ast, { VariableDeclarator(path) { if (!t.isIdentifier(path.node.id)) return; const varName = path.node.id.name; if (!/^(var|v|arg)\d+$/.test(varName)) return; const init = path.node.init; let newName = null; // 布尔字面量 if (t.isBooleanLiteral(init)) { // 检查使用上下文 const binding = path.scope.getBinding(varName); if (binding) { for (const ref of binding.referencePaths) { if (t.isObjectProperty(ref.parent)) { const key = ref.parent.key; let prop; if (t.isStringLiteral(key)) prop = key.value; else if (t.isIdentifier(key)) prop = key.name; if (prop && propToVarName[prop]) { newName = propToVarName[prop]; break; } } } } if (!newName) newName = init.value ? 'isTrue' : 'isFalse'; } // 数组字面量 if (t.isArrayExpression(init) && init.elements.length === 0) { newName = 'items'; } // 字符串字面量 if (t.isStringLiteral(init)) { const val = init.value; if (val.includes('/') || val.includes('\\')) newName = 'pathStr'; else if (val.includes('@')) newName = 'emailStr'; else if (val.length > 50) newName = 'longStr'; else newName = 'str'; } // 数字字面量 if (t.isNumericLiteral(init)) { if (init.value === 0) newName = 'count'; else newName = 'num'; } // 正则表达式 if (t.isRegExpLiteral(init)) { newName = 'regex'; } if (newName) { const binding = path.scope.getBinding(varName); if (binding) { const finalName = getUniqueName(path.scope, newName); path.node.id.name = finalName; binding.referencePaths.forEach(ref => { ref.node.name = finalName; }); initCount++; } } } }); console.log(`基于初始化值重命名了 ${initCount} 个变量`); console.log('\n[4] 生成代码...'); const output = generate(ast, { comments: false, compact: false, concise: false }, code); let finalCode = output.code; finalCode = finalCode.replace(/\["([a-zA-Z_$][a-zA-Z0-9_$]*)"\]/g, '.$1'); console.log('\n[5] 保存文件...'); fs.writeFileSync(outputPath, finalCode); console.log(`保存到: ${outputPath}`); console.log(`新文件大小: ${(finalCode.length / 1024).toFixed(2)} KB`); const remaining = (finalCode.match(/\b(var|arg|v)\d+\b/g) || []); const unique = [...new Set(remaining)]; console.log(`\n剩余通用变量名: ${unique.length} 个唯一名称`); console.log('\n✅ 完成!');