/**
 * 动态反混淆 provider.js v5
 * 独立实现 RC4 + Base64 解码器
 */
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 动态反混淆工具 v5                 ║');
console.log('╚════════════════════════════════════════════════════╝');

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

// 找到 _0x4ff4 函数的结束位置
const arrayFuncStart = code.indexOf('function _0x4ff4()');
let braceCount = 0;
let arrayFuncEnd = arrayFuncStart;
let 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;
        }
    }
}

const initCode = code.slice(0, arrayFuncEnd);

// 获取字符串数组
const vmCode1 = `
${initCode}
_0x4ff4();
`;

console.log('\n[1] 获取字符串数组...');
let stringArray;
try {
    const sandbox = { vip: 'cursor' };
    const context = vm.createContext(sandbox);
    const script = new vm.Script(vmCode1, { timeout: 60000 });
    stringArray = script.runInContext(context, { timeout: 60000 });
    console.log(`数组长度: ${stringArray.length}`);
} catch (e) {
    console.error('获取数组失败:', e.message);
    process.exit(1);
}

// 独立实现解码器
// Base64 字母表 (小写优先)
const base64Chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';

// Base64 解码
function customBase64Decode(input) {
    let result = '';
    for (let i = 0, charCode, bits; i < input.length;) {
        charCode = base64Chars.indexOf(input.charAt(i++));
        if (charCode === -1) continue;

        if (bits === undefined) {
            bits = charCode;
            continue;
        }

        bits = (bits * 64) + charCode;
        if (i % 4 === 1) continue;

        result += String.fromCharCode(0xFF & (bits >> ((-2 * i) & 6)));
    }
    return result;
}

// 改进的 Base64 解码
function base64Decode(str) {
    let output = '';
    let temp = '';
    let i = 0;
    let charCode;

    for (let j = 0; j < str.length; j++) {
        charCode = base64Chars.indexOf(str.charAt(j));
        if (charCode === -1 || charCode === 64) continue; // 跳过无效字符和 '='

        i++;
        temp = (i % 4 === 1) ? charCode : (temp * 64 + charCode);

        if (i % 4 !== 1) {
            output += String.fromCharCode(0xFF & (temp >> ((-2 * i) & 6)));
        }
    }

    return output;
}

// RC4 解密
function rc4Decrypt(data, key) {
    const S = [];
    let j = 0;
    let result = '';

    // 初始化 S 盒
    for (let i = 0; i < 256; i++) {
        S[i] = i;
    }

    // 打乱 S 盒
    for (let i = 0; i < 256; i++) {
        j = (j + S[i] + key.charCodeAt(i % key.length)) % 256;
        [S[i], S[j]] = [S[j], S[i]];
    }

    // 生成密钥流并解密
    let i = 0;
    j = 0;
    for (let k = 0; k < data.length; k++) {
        i = (i + 1) % 256;
        j = (j + S[i]) % 256;
        [S[i], S[j]] = [S[j], S[i]];
        const keyByte = S[(S[i] + S[j]) % 256];
        result += String.fromCharCode(data.charCodeAt(k) ^ keyByte);
    }

    return result;
}

// 完整解码函数
function decode(index, key) {
    const actualIndex = index - 0x107; // 263
    if (actualIndex < 0 || actualIndex >= stringArray.length) {
        return null;
    }

    const encoded = stringArray[actualIndex];
    if (!encoded) return null;

    try {
        const decoded1 = base64Decode(encoded);
        const decoded2 = rc4Decrypt(decoded1, key);
        return decoded2;
    } catch (e) {
        return null;
    }
}

// 测试解码
console.log('\n[2] 测试解码...');
// 尝试找到代码中实际使用的一些调用来验证
const testCalls = [
    [0x532, 'ck7z'],
    [0x108, 'test'],
    [0x109, 'abcd']
];

for (const [index, key] of testCalls) {
    const actualIndex = index - 0x107;
    const encoded = stringArray[actualIndex];
    const result = decode(index, key);
    console.log(`  index=${index} (actual=${actualIndex})`);
    console.log(`    encoded: ${encoded?.slice(0, 30) || '(none)'}...`);
    console.log(`    decoded: ${result?.slice(0, 50) || '(null)'}${result?.length > 50 ? '...' : ''}`);
}

// 查找代码中实际的调用并验证
console.log('\n[3] 从代码中提取实际调用测试...');
const samplePattern = /_0x56bd\s*\(\s*(0x[a-f0-9]+)\s*,\s*'([^']*)'\s*\)/gi;
let sampleMatch;
let sampleCount = 0;
while ((sampleMatch = samplePattern.exec(code)) !== null && sampleCount < 5) {
    const idx = parseInt(sampleMatch[1], 16);
    const k = sampleMatch[2];
    const result = decode(idx, k);
    console.log(`  ${sampleMatch[0].slice(0, 40)}... => "${result?.slice(0, 40) || '(null)'}"`);
    sampleCount++;
}

// 查找所有 _0x56bd 调用并解码
console.log('\n[4] 查找所有解码调用...');
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)) {
        const index = parseInt(indexHex, 16);
        const decoded = decode(index, key);
        if (decoded && typeof decoded === 'string') {
            decodeMap.set(fullMatch, decoded);
            successCalls++;
        }
    }
}

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

    if (!decodeMap.has(fullMatch)) {
        const index = parseInt(indexHex, 16);
        const decoded = decode(index, key);
        if (decoded && typeof decoded === 'string') {
            decodeMap.set(fullMatch, decoded);
            successCalls++;
        }
    }
}

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

// 显示一些解码样本
console.log('\n[5] 解码样本:');
let sampCount = 0;
for (const [pattern, decoded] of decodeMap) {
    if (sampCount < 15) {
        console.log(`  => "${decoded.slice(0, 60)}${decoded.length > 60 ? '...' : ''}"`);
        sampCount++;
    }
}

// 替换
console.log('\n[6] 替换编码字符串...');
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[7] 清理代码...');

// 简化属性访问 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[8] 保存文件...');
fs.writeFileSync(outputPath, newCode);
console.log(`保存到: ${outputPath}`);
console.log(`新文件大小: ${(newCode.length / 1024).toFixed(2)} KB`);

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