Files
cursornew2026/full_deobfuscate_v3.js

350 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 完整反混淆脚本 v3 - 更强大的字符串解码
* 策略:先执行完整的解码器设置,再遍历所有可能的调用参数
*/
const fs = require('fs');
const path = require('path');
const vm = require('vm');
const deobfuscateIO = require('obfuscator-io-deobfuscator').deobfuscate;
const beautify = require('js-beautify').js;
const outputDir = 'D:/temp/破解/cursorpro-0.4.5/deobfuscated_full/extension/out';
function ensureDir(dir) {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
}
/**
* 提取并执行完整的解码器设置代码
*/
function setupFullDecoder(code) {
// 查找字符串数组函数名
const arrayFuncMatch = code.match(/function\s+(_0x[a-f0-9]+)\s*\(\)\s*\{/);
if (!arrayFuncMatch) {
console.log(' 未找到字符串数组函数');
return null;
}
const arrayFuncName = arrayFuncMatch[1];
// 查找解码函数 - 更宽松的匹配
const decoderPatterns = [
/function\s+(_0x[a-f0-9]+)\s*\(\s*_0x[a-f0-9]+\s*,\s*_0x[a-f0-9]+\s*\)\s*\{\s*const\s+_0x[a-f0-9]+\s*=\s*_0x[a-f0-9]+\s*\(\s*\)\s*;/,
/function\s+(_0x[a-f0-9]+)\s*\(\s*_0x[a-f0-9]+\s*,\s*_0x[a-f0-9]+\s*\)\s*\{/
];
let decoderFuncName = null;
for (const pattern of decoderPatterns) {
const match = code.match(pattern);
if (match) {
decoderFuncName = match[1];
break;
}
}
if (!decoderFuncName) {
console.log(' 未找到解码函数');
return null;
}
console.log(` 字符串数组函数: ${arrayFuncName}`);
console.log(` 解码函数: ${decoderFuncName}`);
// 提取从开头到解码函数结束的所有代码
// 找到解码函数的结束位置
const decoderStart = code.indexOf(`function ${decoderFuncName}(`);
if (decoderStart === -1) {
console.log(' 未找到解码函数定义');
return null;
}
// 找到解码函数的结束
let braceCount = 0;
let decoderEnd = decoderStart;
let foundStart = false;
for (let i = decoderStart; i < code.length; i++) {
if (code[i] === '{') {
braceCount++;
foundStart = true;
} else if (code[i] === '}') {
braceCount--;
if (foundStart && braceCount === 0) {
decoderEnd = i + 1;
break;
}
}
}
// 提取从文件开头到解码函数结束的所有代码
// 这包括 vip 变量、IIFE、数组函数、解码函数
const setupCode = code.substring(0, decoderEnd);
// 创建沙盒并执行
const sandbox = {
console: { log: () => {}, warn: () => {}, error: () => {} },
parseInt: parseInt,
String: String,
decodeURIComponent: decodeURIComponent
};
try {
vm.runInNewContext(setupCode, sandbox);
// 检查解码函数是否可用
const testResult = vm.runInNewContext(`typeof ${decoderFuncName}`, sandbox);
if (testResult !== 'function') {
console.log(` 解码函数不可用: ${testResult}`);
return null;
}
console.log(` 解码器设置成功`);
return { sandbox, decoderFuncName, arrayFuncName, setupCode };
} catch (e) {
console.log(` 沙盒执行失败: ${e.message}`);
// 尝试更激进的方法 - 执行整个文件的前半部分
return setupAggressiveDecoder(code, decoderFuncName, arrayFuncName);
}
}
/**
* 更激进的解码器设置 - 执行更多代码
*/
function setupAggressiveDecoder(code, decoderFuncName, arrayFuncName) {
console.log(' 尝试激进模式...');
// 找到第一个 exports 或 Object.defineProperty 之前的所有代码
const exportIndex = Math.min(
code.indexOf('Object.defineProperty(exports') !== -1 ? code.indexOf('Object.defineProperty(exports') : Infinity,
code.indexOf('exports.') !== -1 ? code.indexOf('exports.') : Infinity
);
if (exportIndex === Infinity) {
console.log(' 未找到 exports 边界');
return null;
}
const setupCode = code.substring(0, exportIndex);
const sandbox = {
console: { log: () => {}, warn: () => {}, error: () => {} },
parseInt: parseInt,
String: String,
decodeURIComponent: decodeURIComponent,
this: {},
Object: Object
};
try {
vm.runInNewContext(setupCode, sandbox);
const testResult = vm.runInNewContext(`typeof ${decoderFuncName}`, sandbox);
if (testResult === 'function') {
console.log(` 激进模式成功`);
return { sandbox, decoderFuncName, arrayFuncName, setupCode };
}
} catch (e) {
console.log(` 激进模式失败: ${e.message}`);
}
return null;
}
/**
* 收集并解码所有字符串调用
*/
function decodeAllStrings(code, decoder) {
if (!decoder) return { code, decodedCount: 0 };
const { sandbox, decoderFuncName } = decoder;
// 收集所有解码函数别名
const aliasPattern = new RegExp(`const\\s+(_0x[a-f0-9]+)\\s*=\\s*${decoderFuncName}\\s*;`, 'g');
const aliases = [decoderFuncName];
let match;
while ((match = aliasPattern.exec(code)) !== null) {
aliases.push(match[1]);
}
console.log(` 解码函数别名: ${aliases.join(', ')}`);
// 构建所有可能的调用模式
const decodedMap = new Map();
let totalFound = 0;
for (const alias of aliases) {
// 匹配多种调用格式
const patterns = [
new RegExp(`${alias}\\s*\\(\\s*(0x[a-f0-9]+)\\s*,\\s*'([^']*)'\\s*\\)`, 'g'),
new RegExp(`${alias}\\s*\\(\\s*(0x[a-f0-9]+)\\s*,\\s*"([^"]*)"\\s*\\)`, 'g'),
];
for (const pattern of patterns) {
let callMatch;
while ((callMatch = pattern.exec(code)) !== null) {
const fullMatch = callMatch[0];
const num = callMatch[1];
const key = callMatch[2];
if (!decodedMap.has(fullMatch)) {
try {
const decoded = vm.runInNewContext(
`${decoderFuncName}(${num},'${key.replace(/'/g, "\\'")}')`,
sandbox
);
if (typeof decoded === 'string') {
decodedMap.set(fullMatch, decoded);
totalFound++;
}
} catch (e) {
// 解码失败,跳过
}
}
}
}
}
console.log(` 找到 ${totalFound} 个字符串调用`);
// 替换所有解码后的字符串
let decodedCount = 0;
for (const [original, decoded] of decodedMap) {
// 选择合适的引号
let replacement;
if (decoded.includes('\n') || decoded.includes('\r')) {
replacement = '`' + decoded.replace(/`/g, '\\`').replace(/\$/g, '\\$') + '`';
} else if (decoded.includes("'") && !decoded.includes('"')) {
replacement = JSON.stringify(decoded);
} else {
replacement = `'${decoded.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`;
}
// 全局替换
const escapedOriginal = original.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const regex = new RegExp(escapedOriginal, 'g');
const before = code.length;
code = code.replace(regex, replacement);
if (code.length !== before) {
decodedCount++;
}
}
console.log(` 替换了 ${decodedCount} 个不同的字符串`);
// 移除解码器代码(可选,让代码更干净)
// 注释掉解码器相关代码而不是删除
return { code, decodedCount };
}
/**
* 清理混淆的变量引用
*/
function cleanObfuscatedReferences(code) {
// 将 obj['property'] 转换为 obj.property
code = code.replace(/\['([a-zA-Z_$][a-zA-Z0-9_$]*)'\]/g, '.$1');
// 简化 !![] 为 true
code = code.replace(/!!\[\]/g, 'true');
// 简化 ![] 为 false
code = code.replace(/!\[\]/g, 'false');
return code;
}
/**
* AST 清洗
*/
function astClean(code, filename) {
try {
console.log(` [AST] 处理...`);
return deobfuscateIO(code);
} catch (e) {
console.log(` [AST] 失败: ${e.message}`);
return code;
}
}
/**
* 处理单个文件
*/
async function processFile(inputPath, outputPath, filename) {
console.log(`\n${'='.repeat(50)}`);
console.log(`处理: ${filename}`);
console.log('='.repeat(50));
let code = fs.readFileSync(inputPath, 'utf8');
console.log(`原始大小: ${(code.length / 1024).toFixed(2)} KB`);
// Step 1: 设置解码器
console.log('\nStep 1: 设置解码器...');
const decoder = setupFullDecoder(code);
// Step 2: 解码所有字符串
console.log('\nStep 2: 解码字符串...');
const decodeResult = decodeAllStrings(code, decoder);
code = decodeResult.code;
// Step 3: 清理混淆引用
console.log('\nStep 3: 清理混淆引用...');
code = cleanObfuscatedReferences(code);
// Step 4: AST 清洗
console.log('\nStep 4: AST 清洗...');
code = astClean(code, filename);
// Step 5: 再次清理AST 可能引入新的混淆)
console.log('\nStep 5: 二次清理...');
code = cleanObfuscatedReferences(code);
// Step 6: 美化
console.log('\nStep 6: 美化代码...');
code = beautify(code, {
indent_size: 4,
preserve_newlines: true,
max_preserve_newlines: 2,
space_in_empty_paren: true,
jslint_happy: false,
brace_style: 'collapse'
});
console.log(`\n处理后大小: ${(code.length / 1024).toFixed(2)} KB`);
// 保存
ensureDir(path.dirname(outputPath));
fs.writeFileSync(outputPath, code);
console.log(`已保存: ${outputPath}`);
}
// 主函数
async function main() {
console.log('╔════════════════════════════════════════════════════╗');
console.log('║ 完整反混淆脚本 v3 ║');
console.log('║ 完整解码器执行 + 批量字符串替换 + AST清洗 ║');
console.log('╚════════════════════════════════════════════════════╝\n');
const files = [
{ input: 'D:/temp/破解/cursorpro-0.4.5/原版本/extension/out/webview/provider.js', output: 'webview/provider.js' },
{ input: 'D:/temp/破解/cursorpro-0.4.5/原版本/extension/out/extension.js', output: 'extension.js' },
{ input: 'D:/temp/破解/cursorpro-0.4.5/原版本/extension/out/utils/account.js', output: 'utils/account.js' },
{ input: 'D:/temp/破解/cursorpro-0.4.5/原版本/extension/out/utils/sqlite.js', output: 'utils/sqlite.js' },
{ input: 'D:/temp/破解/cursorpro-0.4.5/原版本/extension/out/api/client.js', output: 'api/client.js' },
];
for (const file of files) {
if (fs.existsSync(file.input)) {
await processFile(file.input, path.join(outputDir, file.output), file.output);
} else {
console.log(`\n跳过: ${file.input} (不存在)`);
}
}
console.log('\n╔════════════════════════════════════════════════════╗');
console.log('║ 完成! ║');
console.log('╚════════════════════════════════════════════════════╝');
console.log(`\n输出目录: ${outputDir}`);
}
main().catch(console.error);