/**
 * 动态反混淆 provider.js v4
 * 直接执行 provider_clean.js 前半部分代码来初始化解码器
 */
const fs = require('fs');
const vm = require('vm');

const inputPath = 'D:/temp/破解/cursorpro-0.4.5/deobfuscated_full/extension/out/webview/provider_clean.js';
const outputPath = 'D:/temp/破解/cursorpro-0.4.5/deobfuscated_full/extension/out/webview/provider.js';

console.log('╔════════════════════════════════════════════════════╗');
console.log('║       Provider.js 动态反混淆工具 v4                 ║');
console.log('╚════════════════════════════════════════════════════╝');

let code = fs.readFileSync(inputPath, 'utf8');
console.log(`读取文件: ${(code.length / 1024).toFixed(2)} KB`);

// 找到 _0x56bd 函数的结束位置
// 函数定义在文件开头附近
const decoderStart = code.indexOf('function _0x56bd(');
if (decoderStart === -1) {
    console.error('未找到 _0x56bd 函数');
    process.exit(1);
}

// 找到 _0x56bd 函数结束 - 通过匹配花括号
let braceCount = 0;
let decoderEnd = decoderStart;
let started = false;
for (let i = decoderStart; i < code.length; i++) {
    if (code[i] === '{') {
        braceCount++;
        started = true;
    } else if (code[i] === '}') {
        braceCount--;
        if (started && braceCount === 0) {
            decoderEnd = i + 1;
            break;
        }
    }
}

console.log(`_0x56bd 函数结束位置: ${decoderEnd}`);

// 找到 _0x4ff4 函数的结束位置
const arrayFuncStart = code.indexOf('function _0x4ff4()');
if (arrayFuncStart === -1) {
    console.error('未找到 _0x4ff4 函数');
    process.exit(1);
}

// 找到 _0x4ff4 函数结束
braceCount = 0;
let arrayFuncEnd = arrayFuncStart;
started = false;
for (let i = arrayFuncStart; i < code.length; i++) {
    if (code[i] === '{') {
        braceCount++;
        started = true;
    } else if (code[i] === '}') {
        braceCount--;
        if (started && braceCount === 0) {
            arrayFuncEnd = i + 1;
            break;
        }
    }
}

console.log(`_0x4ff4 函数结束位置: ${arrayFuncEnd}`);

// 取前半部分代码（包括两个函数定义）
const initCodeEnd = Math.max(decoderEnd, arrayFuncEnd);
const initCode = code.slice(0, initCodeEnd);

console.log(`初始化代码长度: ${(initCode.length / 1024).toFixed(2)} KB`);

// 创建沙盒执行代码
const vmCode = `
${initCode}

// 导出解码器
({
    _0x56bd: _0x56bd,
    _0x4ff4: _0x4ff4
});
`;

console.log('\n[1] 在沙盒中执行初始化代码...');
let decoder;
try {
    const sandbox = {
        console: { log: () => {}, error: () => {} },
        vip: 'cursor'  // 可能需要这个变量
    };
    const context = vm.createContext(sandbox);
    const script = new vm.Script(vmCode, { timeout: 60000 });
    decoder = script.runInContext(context, { timeout: 60000 });
    console.log('解码器初始化成功');
} catch (e) {
    console.error('沙盒执行失败:', e.message);
    console.error(e.stack?.slice(0, 500));
    process.exit(1);
}

// 测试解码
console.log('\n[2] 测试解码...');
try {
    // 尝试几个不同的调用来验证解码器
    const tests = [
        [0x532, 'ck7z'],
        [0x107, 'test'],
        [0x200, 'abcd']
    ];

    for (const [index, key] of tests) {
        try {
            const result = decoder._0x56bd(index, key);
            console.log(`  _0x56bd(0x${index.toString(16)}, '${key}') = "${result?.slice(0, 50) || '(empty)'}${result?.length > 50 ? '...' : ''}"`);
        } catch (e) {
            console.log(`  _0x56bd(0x${index.toString(16)}, '${key}') = ERROR: ${e.message}`);
        }
    }
} catch (e) {
    console.log('测试解码失败:', e.message);
}

// 查找所有 _0x56bd 调用并解码
console.log('\n[3] 查找所有解码调用...');
// 两种模式: _0x56bd(0x..., '...') 和 _0x56bd(0x..., "...")
const callPattern1 = /_0x56bd\s*\(\s*(0x[a-f0-9]+)\s*,\s*'([^']*)'\s*\)/gi;
const callPattern2 = /_0x56bd\s*\(\s*(0x[a-f0-9]+)\s*,\s*"([^"]*)"\s*\)/gi;

const decodeMap = new Map();
let match;
let totalCalls = 0;
let successCalls = 0;

// 匹配单引号
while ((match = callPattern1.exec(code)) !== null) {
    const fullMatch = match[0];
    const indexHex = match[1];
    const key = match[2];
    totalCalls++;

    if (!decodeMap.has(fullMatch)) {
        try {
            const index = parseInt(indexHex, 16);
            const decoded = decoder._0x56bd(index, key);
            if (decoded && typeof decoded === 'string') {
                decodeMap.set(fullMatch, decoded);
                successCalls++;
            }
        } catch (e) {
            // 跳过解码失败的
        }
    }
}

// 匹配双引号
while ((match = callPattern2.exec(code)) !== null) {
    const fullMatch = match[0];
    const indexHex = match[1];
    const key = match[2];
    totalCalls++;

    if (!decodeMap.has(fullMatch)) {
        try {
            const index = parseInt(indexHex, 16);
            const decoded = decoder._0x56bd(index, key);
            if (decoded && typeof decoded === 'string') {
                decodeMap.set(fullMatch, decoded);
                successCalls++;
            }
        } catch (e) {
            // 跳过解码失败的
        }
    }
}

console.log(`总调用数: ${totalCalls}, 成功解码: ${successCalls}, 唯一模式: ${decodeMap.size}`);

// 显示一些解码样本
console.log('\n[4] 解码样本:');
let sampleCount = 0;
for (const [pattern, decoded] of decodeMap) {
    if (sampleCount < 10 && decoded.length < 50) {
        console.log(`  ${pattern.slice(0, 30)}... => "${decoded}"`);
        sampleCount++;
    }
}

// 替换
console.log('\n[5] 替换编码字符串...');
let newCode = code;
let replaceCount = 0;

for (const [pattern, decoded] of decodeMap) {
    let replacement;
    // 处理特殊字符
    if (decoded.includes('\n') || decoded.includes('\r') || decoded.includes('`') || decoded.includes('${')) {
        replacement = JSON.stringify(decoded);
    } else if (decoded.includes("'") && !decoded.includes('"')) {
        replacement = `"${decoded}"`;
    } else if (decoded.includes('"') && !decoded.includes("'")) {
        replacement = `'${decoded}'`;
    } else {
        replacement = JSON.stringify(decoded);
    }

    const before = newCode.length;
    newCode = newCode.split(pattern).join(replacement);
    if (newCode.length !== before) {
        replaceCount++;
    }
}

console.log(`替换了 ${replaceCount} 个模式`);

// 清理代码
console.log('\n[6] 清理代码...');

// 简化属性访问 obj['prop'] => obj.prop
newCode = newCode.replace(/\['([a-zA-Z_$][a-zA-Z0-9_$]*)'\]/g, '.$1');

// 简化布尔值
newCode = newCode.replace(/!!\[\]/g, 'true');
newCode = newCode.replace(/!\[\]/g, 'false');

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

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