/** * 控制流简化工具 * 移除对象包装的简单操作 */ const fs = require('fs'); // 尝试使用 babel let babel, traverse, generate, t; try { babel = require('@babel/core'); traverse = require('@babel/traverse').default; generate = require('@babel/generator').default; t = require('@babel/types'); } catch (e) { console.log('需要安装 babel 依赖...'); require('child_process').execSync('npm install @babel/core @babel/traverse @babel/generator @babel/types --save-dev', { stdio: 'inherit', cwd: 'D:/temp/破解/cursorpro-0.4.5' }); babel = require('@babel/core'); traverse = require('@babel/traverse').default; generate = require('@babel/generator').default; 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_simplified.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] 收集对象定义...'); // 存储对象属性的映射 const objectMappings = new Map(); // 第一遍:收集所有 const varX = { 'key': function... } 形式的定义 traverse(ast, { VariableDeclarator(path) { if (!t.isIdentifier(path.node.id)) return; if (!t.isObjectExpression(path.node.init)) return; const varName = path.node.id.name; const props = {}; let isSimpleObject = true; for (const prop of path.node.init.properties) { if (!t.isObjectProperty(prop)) { isSimpleObject = false; break; } let key; if (t.isStringLiteral(prop.key)) { key = prop.key.value; } else if (t.isIdentifier(prop.key)) { key = prop.key.name; } else { continue; } // 检查是否是简单的函数包装器 if (t.isFunctionExpression(prop.value)) { const func = prop.value; if (func.body.body.length === 1 && t.isReturnStatement(func.body.body[0])) { const ret = func.body.body[0].argument; // 二元操作: return a === b if (t.isBinaryExpression(ret) && func.params.length === 2) { const [p1, p2] = func.params; if (t.isIdentifier(ret.left) && t.isIdentifier(ret.right) && ret.left.name === p1.name && ret.right.name === p2.name) { props[key] = { type: 'binary', operator: ret.operator }; } } // 逻辑操作: return a && b else if (t.isLogicalExpression(ret) && func.params.length === 2) { const [p1, p2] = func.params; if (t.isIdentifier(ret.left) && t.isIdentifier(ret.right) && ret.left.name === p1.name && ret.right.name === p2.name) { props[key] = { type: 'logical', operator: ret.operator }; } } // 函数调用: return a(b) 或 return a(b, c) else if (t.isCallExpression(ret)) { if (t.isIdentifier(ret.callee) && ret.callee.name === func.params[0]?.name) { props[key] = { type: 'call', argCount: ret.arguments.length }; } } } } // 字符串字面量 else if (t.isStringLiteral(prop.value)) { props[key] = { type: 'string', value: prop.value.value }; } // 数字字面量 else if (t.isNumericLiteral(prop.value)) { props[key] = { type: 'number', value: prop.value.value }; } } if (Object.keys(props).length > 0) { objectMappings.set(varName, props); } } }); console.log(`找到 ${objectMappings.size} 个可简化的对象定义`); console.log('\n[3] 简化调用...'); let simplifiedCount = 0; traverse(ast, { // 简化 obj.key(a, b) 或 obj['key'](a, b) 调用 CallExpression(path) { const callee = path.node.callee; if (!t.isMemberExpression(callee)) return; if (!t.isIdentifier(callee.object)) return; const objName = callee.object.name; const mapping = objectMappings.get(objName); if (!mapping) return; let propName; if (t.isStringLiteral(callee.property)) { propName = callee.property.value; } else if (t.isIdentifier(callee.property) && !callee.computed) { propName = callee.property.name; } else { return; } const propInfo = mapping[propName]; if (!propInfo) return; const args = path.node.arguments; // 二元操作 if (propInfo.type === 'binary' && args.length === 2) { path.replaceWith(t.binaryExpression(propInfo.operator, args[0], args[1])); simplifiedCount++; } // 逻辑操作 else if (propInfo.type === 'logical' && args.length === 2) { path.replaceWith(t.logicalExpression(propInfo.operator, args[0], args[1])); simplifiedCount++; } // 函数调用 else if (propInfo.type === 'call' && args.length >= 1) { const fn = args[0]; const fnArgs = args.slice(1); path.replaceWith(t.callExpression(fn, fnArgs)); simplifiedCount++; } }, // 简化 obj.key 或 obj['key'] 属性访问(字符串/数字) MemberExpression(path) { if (path.parent && t.isCallExpression(path.parent) && path.parent.callee === path.node) { return; // 已在 CallExpression 中处理 } if (!t.isIdentifier(path.node.object)) return; const objName = path.node.object.name; const mapping = objectMappings.get(objName); if (!mapping) return; let propName; if (t.isStringLiteral(path.node.property)) { propName = path.node.property.value; } else if (t.isIdentifier(path.node.property) && !path.node.computed) { propName = path.node.property.name; } else { return; } const propInfo = mapping[propName]; if (!propInfo) return; if (propInfo.type === 'string') { path.replaceWith(t.stringLiteral(propInfo.value)); simplifiedCount++; } else if (propInfo.type === 'number') { path.replaceWith(t.numericLiteral(propInfo.value)); simplifiedCount++; } } }); console.log(`简化了 ${simplifiedCount} 处调用`); console.log('\n[4] 移除未使用的对象定义...'); let removedCount = 0; // 收集所有标识符使用情况 const usedIdentifiers = new Set(); traverse(ast, { Identifier(path) { if (!path.isReferencedIdentifier()) return; usedIdentifiers.add(path.node.name); } }); // 移除未使用的变量声明 traverse(ast, { VariableDeclarator(path) { if (!t.isIdentifier(path.node.id)) return; const name = path.node.id.name; if (objectMappings.has(name) && !usedIdentifiers.has(name)) { path.remove(); removedCount++; } } }); console.log(`移除了 ${removedCount} 个未使用的对象`); console.log('\n[5] 生成代码...'); const output = generate(ast, { comments: false, compact: false, concise: false }, code); console.log('\n[6] 保存文件...'); fs.writeFileSync(outputPath, output.code); console.log(`保存到: ${outputPath}`); console.log(`新文件大小: ${(output.code.length / 1024).toFixed(2)} KB`); console.log('\n✅ 完成!');