备份: 完整开发状态(含反混淆脚本和临时文件)
This commit is contained in:
182
generate_decode_maps.js
Normal file
182
generate_decode_maps.js
Normal file
@@ -0,0 +1,182 @@
|
||||
/**
|
||||
* 批量生成解码映射 - 为每个混淆文件生成 decoded_map.json
|
||||
*/
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const vm = require('vm');
|
||||
|
||||
const baseDir = 'D:/temp/破解/cursorpro-0.4.5';
|
||||
|
||||
/**
|
||||
* 从代码中提取解码器并生成映射
|
||||
*/
|
||||
function generateDecodeMap(code, filename) {
|
||||
console.log(`\n处理: ${filename}`);
|
||||
console.log('='.repeat(40));
|
||||
|
||||
// 查找字符串数组函数
|
||||
const arrayFuncMatch = code.match(/function\s+(_0x[a-f0-9]+)\s*\(\)\s*\{/);
|
||||
if (!arrayFuncMatch) {
|
||||
console.log(' 未找到字符串数组函数');
|
||||
return null;
|
||||
}
|
||||
const arrayFuncName = arrayFuncMatch[1];
|
||||
|
||||
// 查找解码函数
|
||||
const decoderMatch = code.match(/function\s+(_0x[a-f0-9]+)\s*\(\s*_0x[a-f0-9]+\s*,\s*_0x[a-f0-9]+\s*\)\s*\{/);
|
||||
if (!decoderMatch) {
|
||||
console.log(' 未找到解码函数');
|
||||
return null;
|
||||
}
|
||||
const decoderFuncName = decoderMatch[1];
|
||||
|
||||
console.log(` 数组函数: ${arrayFuncName}`);
|
||||
console.log(` 解码函数: ${decoderFuncName}`);
|
||||
|
||||
// 提取所有解码器调用模式
|
||||
const callPatterns = [
|
||||
/_0x[a-f0-9]+\s*\(\s*(0x[a-f0-9]+)\s*,\s*'([^']*)'\s*\)/g,
|
||||
/_0x[a-f0-9]+\s*\(\s*(0x[a-f0-9]+)\s*,\s*"([^"]*)"\s*\)/g
|
||||
];
|
||||
|
||||
const calls = new Set();
|
||||
for (const pattern of callPatterns) {
|
||||
let match;
|
||||
while ((match = pattern.exec(code)) !== null) {
|
||||
calls.add(match[0]);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(` 找到 ${calls.size} 个唯一调用`);
|
||||
|
||||
// 尝试设置沙盒执行解码器
|
||||
// 提取从开头到第一个 exports 之前的所有代码
|
||||
let exportIndex = code.indexOf('Object.defineProperty(exports');
|
||||
if (exportIndex === -1) {
|
||||
exportIndex = code.indexOf('exports.');
|
||||
}
|
||||
if (exportIndex === -1) {
|
||||
exportIndex = code.length;
|
||||
}
|
||||
|
||||
// 找到解码函数结束位置
|
||||
const decoderStart = code.indexOf(`function ${decoderFuncName}(`);
|
||||
let braceCount = 0, decoderEnd = decoderStart, 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 提取设置代码
|
||||
const setupCode = code.substring(0, Math.min(decoderEnd + 500, exportIndex));
|
||||
|
||||
// 在沙盒中执行
|
||||
const sandbox = {
|
||||
console: { log: () => {}, warn: () => {}, error: () => {} },
|
||||
parseInt,
|
||||
String,
|
||||
decodeURIComponent,
|
||||
vip: 'cursor'
|
||||
};
|
||||
|
||||
try {
|
||||
vm.runInNewContext(setupCode, sandbox);
|
||||
|
||||
// 测试解码器
|
||||
const testResult = vm.runInNewContext(`typeof ${decoderFuncName}`, sandbox);
|
||||
if (testResult !== 'function') {
|
||||
console.log(` 解码器不可用: ${testResult}`);
|
||||
return null;
|
||||
}
|
||||
console.log(` 解码器设置成功`);
|
||||
|
||||
// 解码所有调用
|
||||
const decodeMap = {};
|
||||
let successCount = 0;
|
||||
let failCount = 0;
|
||||
|
||||
for (const call of calls) {
|
||||
// 提取参数
|
||||
const paramMatch = call.match(/_0x[a-f0-9]+\s*\(\s*(0x[a-f0-9]+)\s*,\s*['"]([^'"]*)['"]\s*\)/);
|
||||
if (!paramMatch) continue;
|
||||
|
||||
const num = paramMatch[1];
|
||||
const key = paramMatch[2];
|
||||
|
||||
try {
|
||||
const decoded = vm.runInNewContext(
|
||||
`${decoderFuncName}(${num},'${key.replace(/'/g, "\\'")}')`,
|
||||
sandbox
|
||||
);
|
||||
if (typeof decoded === 'string') {
|
||||
decodeMap[call] = decoded;
|
||||
successCount++;
|
||||
} else {
|
||||
failCount++;
|
||||
}
|
||||
} catch (e) {
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(` 成功解码: ${successCount}`);
|
||||
console.log(` 解码失败: ${failCount}`);
|
||||
|
||||
return decodeMap;
|
||||
} catch (e) {
|
||||
console.log(` 沙盒执行失败: ${e.message}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 主函数
|
||||
function main() {
|
||||
console.log('╔════════════════════════════════════════╗');
|
||||
console.log('║ 批量生成解码映射 ║');
|
||||
console.log('╚════════════════════════════════════════╝');
|
||||
|
||||
const files = [
|
||||
{ input: '原版本/extension/out/webview/provider.js', output: 'provider_decoded_map.json' },
|
||||
{ input: '原版本/extension/out/extension.js', output: 'extension_decoded_map.json' },
|
||||
{ input: '原版本/extension/out/utils/account.js', output: 'account_decoded_map.json' },
|
||||
{ input: '原版本/extension/out/utils/sqlite.js', output: 'sqlite_decoded_map.json' },
|
||||
{ input: '原版本/extension/out/api/client.js', output: 'client_decoded_map.json' }
|
||||
];
|
||||
|
||||
for (const file of files) {
|
||||
const inputPath = path.join(baseDir, file.input);
|
||||
const outputPath = path.join(baseDir, file.output);
|
||||
|
||||
// 检查是否已存在
|
||||
if (fs.existsSync(outputPath)) {
|
||||
const existing = JSON.parse(fs.readFileSync(outputPath, 'utf8'));
|
||||
console.log(`\n${file.output}: 已存在 (${Object.keys(existing).length} 条)`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!fs.existsSync(inputPath)) {
|
||||
console.log(`\n跳过: ${file.input} (不存在)`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const code = fs.readFileSync(inputPath, 'utf8');
|
||||
const decodeMap = generateDecodeMap(code, file.input);
|
||||
|
||||
if (decodeMap && Object.keys(decodeMap).length > 0) {
|
||||
fs.writeFileSync(outputPath, JSON.stringify(decodeMap, null, 2));
|
||||
console.log(` 已保存: ${outputPath}`);
|
||||
} else {
|
||||
console.log(` 无法生成映射`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n完成!');
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user