Files
cursornew2026/deobfuscate_provider_v6.js

254 lines
7.6 KiB
JavaScript

/**
* 动态反混淆 provider.js v6
* 精确复制原始解码逻辑
*/
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 动态反混淆工具 v6 ║');
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);
// 获取字符串数组
console.log('\n[1] 获取字符串数组...');
let stringArray;
try {
const sandbox = { vip: 'cursor' };
const context = vm.createContext(sandbox);
const script = new vm.Script(`${initCode}\n_0x4ff4();`, { 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+/=';
function originalBase64Decode(input) {
let decoded = '';
let tempStr = '';
for (let i = 0, temp, charIndex, charPos = 0;
charIndex = input.charAt(charPos++);
~charIndex && (temp = i % 4 ? temp * 64 + charIndex : charIndex, i++ % 4) ?
decoded += String.fromCharCode(0xff & temp >> (-2 * i & 6)) : 0) {
charIndex = base64Chars.indexOf(charIndex);
}
// URI 解码
for (let k = 0, len = decoded.length; k < len; k++) {
tempStr += '%' + ('00' + decoded.charCodeAt(k).toString(16)).slice(-2);
}
return decodeURIComponent(tempStr);
}
// RC4 解密 (精确复制原始逻辑)
function rc4Decrypt(data, key) {
const S = [];
let j = 0;
let temp;
let result = '';
// 用原始 Base64 先解码
data = originalBase64Decode(data);
// KSA
for (let i = 0; i < 256; i++) {
S[i] = i;
}
for (let i = 0; i < 256; i++) {
j = (j + S[i] + key.charCodeAt(i % key.length)) % 256;
temp = S[i];
S[i] = S[j];
S[j] = temp;
}
// PRGA
let i = 0;
j = 0;
for (let k = 0; k < data.length; k++) {
i = (i + 1) % 256;
j = (j + S[i]) % 256;
temp = S[i];
S[i] = S[j];
S[j] = temp;
result += String.fromCharCode(data.charCodeAt(k) ^ S[(S[i] + S[j]) % 256]);
}
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 {
return rc4Decrypt(encoded, key);
} 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] 清理代码...');
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✅ 完成!');