/** * 第二轮变量重命名 - 处理 API 调用结果和常见模式 */ 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', plugins: [] }); console.log('AST 解析成功'); } catch (e) { console.error('AST 解析失败:', e.message); process.exit(1); } console.log('\n[2] 智能变量重命名...'); let renamedCount = 0; const usedNamesPerScope = new Map(); function getScopeUsedNames(scope) { if (!usedNamesPerScope.has(scope.uid)) { usedNamesPerScope.set(scope.uid, new Set()); } return usedNamesPerScope.get(scope.uid); } function isNameUsedInScope(scope, name) { if (scope.hasBinding(name)) return true; let s = scope; while (s) { if (getScopeUsedNames(s).has(name)) return true; s = s.parent; } return false; } function renameBinding(path, varName, newName) { const scope = path.scope; let finalName = newName; let counter = 1; while (isNameUsedInScope(scope, finalName)) { finalName = newName + counter++; } getScopeUsedNames(scope).add(finalName); const binding = scope.getBinding(varName); if (binding) { path.node.id.name = finalName; binding.referencePaths.forEach(ref => { ref.node.name = finalName; }); return true; } return false; } // API 调用模式匹配 const apiPatterns = { 'verifyKey': 'verifyResult', 'switchSeamlessToken': 'switchResult', 'getAccount': 'accountResult', 'getUsage': 'usageResult', 'getAnnouncement': 'announcement', 'checkVersion': 'versionResult', 'getProxyStatus': 'proxyStatus', 'getSeamlessStatus': 'seamlessStatus', }; traverse(ast, { VariableDeclarator(path) { if (!t.isIdentifier(path.node.id)) return; const varName = path.node.id.name; if (!/^var\d+$/.test(varName)) return; const init = path.node.init; let newName = null; // await client_1.xxx() -> xxxResult if (t.isAwaitExpression(init)) { const arg = init.argument; if (t.isCallExpression(arg)) { const callee = arg.callee; if (t.isMemberExpression(callee)) { const objName = callee.object.name || ''; const methodName = callee.property.name || ''; // client_1.xxx if (objName === 'client_1' && apiPatterns[methodName]) { newName = apiPatterns[methodName]; } // this._xxx else if (t.isThisExpression(callee.object)) { if (methodName.startsWith('_get')) { const base = methodName.slice(4); newName = base.charAt(0).toLowerCase() + base.slice(1); } else if (methodName.startsWith('_check')) { newName = 'checkResult'; } } // xxx.exec() else if (methodName === 'exec') { newName = 'execResult'; } } } } // 字符串方法调用结果 if (t.isCallExpression(init)) { const callee = init.callee; if (t.isMemberExpression(callee)) { const methodName = callee.property.name || ''; if (methodName === 'replace') newName = 'replaced'; else if (methodName === 'trim') newName = 'trimmed'; else if (methodName === 'toLowerCase') newName = 'lowerStr'; else if (methodName === 'toUpperCase') newName = 'upperStr'; else if (methodName === 'slice') newName = 'sliced'; else if (methodName === 'substring') newName = 'substr'; else if (methodName === 'concat') newName = 'concatenated'; else if (methodName === 'normalize') newName = 'normalized'; } } if (newName && renameBinding(path, varName, newName)) { renamedCount++; } } }); console.log(`重命名了 ${renamedCount} 个变量`); console.log('\n[3] 处理方法参数...'); let paramCount = 0; // 收集方法名和参数的映射 const methodParamNames = { 'constructor': ['extensionUri', 'context'], '_handleActivate': ['key'], '_handleSwitch': [], '_handleReset': [], '_handleDisable': [], '_writeAccountToLocal': ['accountData'], '_writeHostsFile': ['content'], '_handleToggleProxy': ['enabled', 'silent'], '_handleToggleSeamless': ['enabled'], '_handleGetAccountUsage': ['forceRefresh'], '_handleCheckUsageBeforeSwitch': ['silent'], '_postMessage': ['message'], '_grantHostsWritePermission': [], 'resolveWebviewView': ['webviewView', 'context', 'token'], '_handleInjectSeamless': [], '_handleRestoreSeamless': [], '_handleManualSeamlessSwitch': [], }; traverse(ast, { ClassMethod(path) { const methodName = path.node.key.name || ''; const expectedParams = methodParamNames[methodName]; if (!expectedParams) return; const params = path.node.params; for (let i = 0; i < params.length && i < expectedParams.length; i++) { const param = params[i]; const newName = expectedParams[i]; if (!newName) continue; // 跳过空名称 if (t.isIdentifier(param) && /^arg\d+$/.test(param.name)) { const binding = path.scope.getBinding(param.name); if (binding) { param.name = newName; binding.referencePaths.forEach(ref => { ref.node.name = newName; }); paramCount++; } } } } }); console.log(`重命名了 ${paramCount} 个参数`); 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)\d+\b/g) || []); const unique = [...new Set(remaining)]; console.log(`\n剩余通用变量名: ${unique.length} 个唯一名称`); console.log('\n✅ 完成!');