Files
cursornew2026/deobfuscate_provider_full.js

433 lines
13 KiB
JavaScript

/**
* 完整反混淆 provider.js
* 使用 RC4 + 非标准 Base64 解码
*/
const fs = require('fs');
const path = require('path');
// 非标准 Base64 字母表(小写在前)
const BASE64_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';
/**
* 非标准 Base64 解码
*/
function base64Decode(input) {
let output = '';
let buffer = 0;
let bitsCollected = 0;
for (let i = 0; i < input.length; i++) {
const char = input[i];
if (char === '=') break;
const value = BASE64_CHARS.indexOf(char);
if (value === -1) continue;
buffer = (buffer << 6) | value;
bitsCollected += 6;
if (bitsCollected >= 8) {
bitsCollected -= 8;
output += String.fromCharCode((buffer >> bitsCollected) & 0xFF);
}
}
return output;
}
/**
* RC4 解密
*/
function rc4Decrypt(data, key) {
const s = [];
let j = 0;
let result = '';
// 初始化 S-box
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;
[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 decodeString(encoded, key) {
try {
const base64Decoded = base64Decode(encoded);
const decrypted = rc4Decrypt(base64Decoded, key);
return decrypted;
} catch (e) {
return null;
}
}
/**
* 从代码中提取字符串数组
*/
function extractStringArray(code) {
// 找到字符串数组函数
const arrayMatch = code.match(/function\s+_0x[a-f0-9]+\(\)\s*\{\s*const\s+_0x[a-f0-9]+\s*=\s*\(function\(\)\s*\{\s*return\s*\[vip,([\s\S]*?)\]\.concat/);
if (!arrayMatch) {
console.log('未找到字符串数组,尝试其他模式...');
// 尝试直接匹配数组内容
const directMatch = code.match(/return\s*\[\s*vip\s*,\s*'([^']+)'/);
if (directMatch) {
console.log('找到数组起始');
}
return null;
}
console.log('找到字符串数组定义');
// 提取所有字符串
const arrayContent = arrayMatch[1];
const strings = ['cursor']; // vip = 'cursor'
// 匹配所有字符串
const stringRegex = /'([^'\\]*(?:\\.[^'\\]*)*)'/g;
let match;
while ((match = stringRegex.exec(arrayContent)) !== null) {
strings.push(match[1]);
}
console.log(`提取了 ${strings.length} 个字符串`);
return strings;
}
/**
* 动态执行提取字符串数组
*/
function extractStringArrayDynamic(code) {
console.log('使用动态方法提取字符串数组...');
// 提取 _0x4ff4 或类似函数
const funcMatch = code.match(/(function\s+(_0x[a-f0-9]+)\(\)\s*\{[\s\S]*?return\s+_0x[a-f0-9]+;\s*\})/);
if (!funcMatch) {
console.log('未找到字符串数组函数');
return null;
}
const funcName = funcMatch[2];
console.log(`找到函数: ${funcName}`);
// 提取完整的数组定义部分
// 找到 concat 链的结束
let depth = 0;
let start = code.indexOf('return[vip,');
if (start === -1) start = code.indexOf("return [vip,");
if (start === -1) {
console.log('未找到数组起始');
return null;
}
let end = start;
let inString = false;
let stringChar = '';
for (let i = start; i < code.length; i++) {
const char = code[i];
if (!inString) {
if (char === '"' || char === "'") {
inString = true;
stringChar = char;
} else if (char === '[') {
depth++;
} else if (char === ']') {
depth--;
if (depth === 0) {
// 检查后面是否还有 .concat
const after = code.slice(i + 1, i + 20);
if (!after.match(/^\s*\.\s*concat/)) {
end = i + 1;
break;
}
}
}
} else {
if (char === stringChar && code[i-1] !== '\\') {
inString = false;
}
}
}
// 构建可执行代码
const arrayCode = `
var vip = 'cursor';
${code.slice(start, end)};
`;
try {
const result = eval(arrayCode);
console.log(`动态提取了 ${result.length} 个字符串`);
return result;
} catch (e) {
console.log('动态执行失败:', e.message);
return null;
}
}
/**
* 手动解析提取字符串数组
*/
function extractStringsManual(code) {
console.log('使用手动解析方法...');
const strings = ['cursor'];
// 找到所有在数组中的字符串字面量
// 模式: 'xxxxx' 在数组上下文中
const regex = /\[vip,([\s\S]*?)\]\.concat\(\(function\(\)/g;
let match;
while ((match = regex.exec(code)) !== null) {
const content = match[1];
const strRegex = /'([^'\\]*(?:\\.[^'\\]*)*)'/g;
let strMatch;
while ((strMatch = strRegex.exec(content)) !== null) {
strings.push(strMatch[1].replace(/\\'/g, "'"));
}
}
// 继续查找 concat 中的字符串
const concatRegex = /return\s*\[([\s\S]*?)\](?:\s*;\s*\}|\s*\.\s*concat)/g;
while ((match = concatRegex.exec(code)) !== null) {
const content = match[1];
if (content.includes('vip')) continue; // 跳过第一个
const strRegex = /'([^'\\]*(?:\\.[^'\\]*)*)'/g;
let strMatch;
while ((strMatch = strRegex.exec(content)) !== null) {
const str = strMatch[1].replace(/\\'/g, "'");
if (!strings.includes(str)) {
strings.push(str);
}
}
}
console.log(`手动提取了 ${strings.length} 个字符串`);
return strings;
}
/**
* 在沙盒中执行代码提取字符串数组
*/
function extractWithSandbox(code) {
console.log('尝试沙盒执行...');
// 找到字符串数组函数名
const funcNameMatch = code.match(/function\s+(_0x[a-f0-9]+)\(\)\s*\{\s*const\s+_0x[a-f0-9]+\s*=\s*\(function\(\)\s*\{/);
if (!funcNameMatch) {
console.log('未找到数组函数');
return null;
}
const funcName = funcNameMatch[1];
console.log(`数组函数名: ${funcName}`);
// 提取整个函数定义
const funcStart = code.indexOf(`function ${funcName}()`);
let braceCount = 0;
let funcEnd = funcStart;
let started = false;
for (let i = funcStart; i < code.length; i++) {
if (code[i] === '{') {
braceCount++;
started = true;
} else if (code[i] === '}') {
braceCount--;
if (started && braceCount === 0) {
funcEnd = i + 1;
break;
}
}
}
const funcCode = code.slice(funcStart, funcEnd);
// 执行并获取结果
const execCode = `
var vip = 'cursor';
${funcCode}
${funcName}();
`;
try {
const result = eval(execCode);
console.log(`沙盒执行成功,获取 ${result.length} 个字符串`);
return result;
} catch (e) {
console.log('沙盒执行失败:', e.message);
return null;
}
}
/**
* 主函数
*/
async function main() {
console.log('╔════════════════════════════════════════════════════╗');
console.log('║ Provider.js 完整反混淆工具 ║');
console.log('╚════════════════════════════════════════════════════╝');
const inputPath = 'D:/temp/破解/cursorpro-0.4.5/原版本/extension/out/webview/provider.js';
const outputPath = 'D:/temp/破解/cursorpro-0.4.5/deobfuscated_full/extension/out/webview/provider.js';
// 读取文件
console.log('\n[1] 读取文件...');
let code = fs.readFileSync(inputPath, 'utf8');
console.log(`文件大小: ${(code.length / 1024).toFixed(2)} KB`);
// 提取字符串数组
console.log('\n[2] 提取字符串数组...');
let stringArray = extractWithSandbox(code);
if (!stringArray || stringArray.length < 100) {
console.log('沙盒方法失败,尝试手动解析...');
stringArray = extractStringsManual(code);
}
if (!stringArray || stringArray.length < 10) {
console.log('错误:无法提取字符串数组');
return;
}
console.log(`成功提取 ${stringArray.length} 个编码字符串`);
// 找到解码器函数名和密钥
console.log('\n[3] 分析解码器...');
const decoderMatch = code.match(/const\s+(_0x[a-f0-9]+)\s*=\s*(_0x[a-f0-9]+);/);
let decoderName = '_0x56bd';
let decoderAlias = '_0xa6d6ac';
if (decoderMatch) {
decoderAlias = decoderMatch[1];
decoderName = decoderMatch[2];
console.log(`解码器: ${decoderName}, 别名: ${decoderAlias}`);
}
// 构建解码映射
console.log('\n[4] 解码字符串...');
const decodeMap = new Map();
let decodedCount = 0;
// 找到所有解码器调用: _0x56bd(0x123, 'key') 或 _0xa6d6ac(0x123, 'key')
const callPattern = new RegExp(
`(?:${decoderName}|${decoderAlias})\\s*\\(\\s*(0x[a-f0-9]+)\\s*,\\s*'([^']*)'\\s*\\)`,
'gi'
);
const calls = new Set();
let callMatch;
while ((callMatch = callPattern.exec(code)) !== null) {
calls.add(JSON.stringify([callMatch[0], callMatch[1], callMatch[2]]));
}
console.log(`找到 ${calls.size} 个唯一的解码器调用`);
// 解码每个调用
const baseIndex = 0x107; // 从混淆代码中提取的基准索引
for (const callStr of calls) {
const [fullMatch, indexHex, key] = JSON.parse(callStr);
const index = parseInt(indexHex, 16) - baseIndex;
if (index >= 0 && index < stringArray.length) {
const encoded = stringArray[index];
const decoded = decodeString(encoded, key);
if (decoded && decoded.length > 0 && !decoded.includes('\x00')) {
decodeMap.set(fullMatch, decoded);
decodedCount++;
}
}
}
console.log(`成功解码 ${decodedCount} 个字符串`);
// 替换代码中的调用
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('`')) {
// 使用 JSON.stringify 处理复杂字符串
replacement = JSON.stringify(decoded);
} else if (decoded.includes("'") && !decoded.includes('"')) {
replacement = `"${decoded}"`;
} else {
replacement = `'${decoded.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`;
}
const before = newCode.length;
newCode = newCode.split(pattern).join(replacement);
if (newCode.length !== before) {
replaceCount++;
}
}
console.log(`替换了 ${replaceCount} 个模式`);
// 清理代码
console.log('\n[6] 清理代码...');
// 简化属性访问
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] 保存文件...');
const outputDir = path.dirname(outputPath);
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
fs.writeFileSync(outputPath, newCode);
console.log(`保存到: ${outputPath}`);
console.log(`新文件大小: ${(newCode.length / 1024).toFixed(2)} KB`);
// 保存解码映射供调试
const mapPath = 'D:/temp/破解/cursorpro-0.4.5/provider_decode_map.json';
const mapObj = {};
for (const [k, v] of decodeMap) {
if (v.length < 500) { // 只保存较短的字符串
mapObj[k] = v;
}
}
fs.writeFileSync(mapPath, JSON.stringify(mapObj, null, 2));
console.log(`解码映射保存到: ${mapPath}`);
console.log('\n✅ 完成!');
}
main().catch(console.error);