/**
 * 变量名反混淆工具
 * 将 _0x 前缀的变量名重命名为可读形式
 */
const fs = require('fs');
const path = require('path');

// 尝试使用 babel
let babel, traverse, generate;
try {
    babel = require('@babel/core');
    traverse = require('@babel/traverse').default;
    generate = require('@babel/generator').default;
} catch (e) {
    console.log('需要安装 babel 依赖，正在安装...');
    require('child_process').execSync('npm install @babel/core @babel/traverse @babel/generator @babel/parser --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;
}

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_readable.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 varMapping = new Map();
let varCounter = 1;
let paramCounter = 1;

// 变量名生成器
function generateVarName(prefix, counter) {
    return prefix + counter;
}

// 检查是否是混淆变量名
function isObfuscatedName(name) {
    return /^_0x[a-f0-9]+$/i.test(name);
}

// 遍历 AST 收集所有混淆变量名
traverse(ast, {
    Identifier(path) {
        const name = path.node.name;
        if (isObfuscatedName(name) && !varMapping.has(name)) {
            // 根据上下文决定新名称
            let newName;
            if (path.parentPath.isFunction() && path.listKey === 'params') {
                newName = 'arg' + paramCounter++;
            } else if (path.parentPath.isVariableDeclarator() && path.key === 'id') {
                newName = 'var' + varCounter++;
            } else if (path.parentPath.isFunctionDeclaration() && path.key === 'id') {
                newName = 'func' + varCounter++;
            } else if (!varMapping.has(name)) {
                newName = 'v' + varCounter++;
            }
            if (newName) {
                varMapping.set(name, newName);
            }
        }
    }
});

console.log(`找到 ${varMapping.size} 个混淆变量名`);

console.log('\n[3] 重命名变量...');
let renamedCount = 0;

traverse(ast, {
    Identifier(path) {
        const name = path.node.name;
        if (varMapping.has(name)) {
            path.node.name = varMapping.get(name);
            renamedCount++;
        }
    }
});

console.log(`重命名了 ${renamedCount} 处`);

console.log('\n[4] 生成代码...');
const output = generate(ast, {
    comments: true,
    compact: false,
    concise: false
}, code);

console.log('\n[5] 保存文件...');
fs.writeFileSync(outputPath, output.code);
console.log(`保存到: ${outputPath}`);
console.log(`新文件大小: ${(output.code.length / 1024).toFixed(2)} KB`);

// 验证
const remaining = (output.code.match(/_0x[a-f0-9]+/gi) || []).length;
console.log(`\n剩余混淆变量名: ${remaining}`);

console.log('\n✅ 完成！');
