Files
cursornew2026/direct_decode.js

291 lines
9.0 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.

/**
* 直接解码脚本 - 使用 RC4 + 非标准 Base64 算法
* 不依赖沙盒执行,直接实现解码逻辑
*/
const fs = require('fs');
const path = require('path');
const baseDir = 'D:/temp/破解/cursorpro-0.4.5';
// 非标准 Base64 字母表 (小写在前)
const BASE64_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';
/**
* 非标准 Base64 解码
*/
function base64Decode(str) {
let result = '';
let buffer = 0;
let bufferLen = 0;
for (let i = 0; i < str.length; i++) {
const char = str[i];
const charIndex = BASE64_CHARS.indexOf(char);
if (charIndex === -1) continue;
if (charIndex === 64) continue; // '=' padding
buffer = (buffer << 6) | charIndex;
bufferLen += 6;
if (bufferLen >= 8) {
bufferLen -= 8;
result += String.fromCharCode((buffer >> bufferLen) & 0xFF);
}
}
return result;
}
/**
* RC4 解密
*/
function rc4Decrypt(data, key) {
// 初始化 S-box
const s = [];
for (let i = 0; i < 256; i++) {
s[i] = i;
}
let j = 0;
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 result = '';
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]];
result += String.fromCharCode(data.charCodeAt(k) ^ s[(s[i] + s[j]) % 256]);
}
return result;
}
/**
* 解码单个字符串
*/
function decodeString(encodedStr, key) {
try {
const base64Decoded = base64Decode(encodedStr);
const decrypted = rc4Decrypt(base64Decoded, key);
return decrypted;
} catch (e) {
return null;
}
}
/**
* 提取字符串数组
*/
function extractStringArray(code) {
// 查找字符串数组 - 这是一个大的嵌套数组
const arrayMatch = code.match(/return\s*\[([^\]]*(?:\]\.concat\(function\s*\(\)\s*\{\s*return\s*\[[^\]]*\][^\}]*\}\(\)\))*[^\]]*)\]/s);
if (!arrayMatch) return null;
// 提取所有字符串
const strMatch = code.match(/return\s*\['([^']*)'(?:,'([^']*)')*\]/g);
if (!strMatch) return null;
const strings = [];
const allStrings = code.match(/'[^']*'/g) || [];
// 找到字符串数组的开始位置
const arrayStart = code.indexOf("const _0x") || code.indexOf("function _0x");
const arrayEnd = code.indexOf("Object.defineProperty(exports");
if (arrayStart !== -1 && arrayEnd !== -1) {
const arraySection = code.substring(arrayStart, arrayEnd);
// 提取这个区域内所有带引号的字符串
const stringMatches = arraySection.match(/'([^'\\]*(\\.[^'\\]*)*)'/g) || [];
for (const match of stringMatches) {
const str = match.slice(1, -1); // 移除引号
if (str.length > 3 && /^[a-zA-Z0-9+/=]+$/.test(str)) {
strings.push(str);
}
}
}
console.log(` 提取了 ${strings.length} 个候选编码字符串`);
return strings;
}
/**
* 为文件生成解码映射
*/
function generateDecodeMapForFile(code, filename) {
console.log(`\n处理: ${filename}`);
console.log('='.repeat(50));
// 找到所有解码函数调用
const callPattern = /(_0x[a-f0-9]+)\s*\(\s*(0x[a-f0-9]+)\s*,\s*'([^']*)'\s*\)/g;
const calls = new Map();
let match;
while ((match = callPattern.exec(code)) !== null) {
const fullMatch = match[0];
const funcName = match[1];
const numHex = match[2];
const key = match[3];
calls.set(fullMatch, { funcName, numHex, key, num: parseInt(numHex, 16) });
}
console.log(` 找到 ${calls.size} 个唯一调用`);
// 提取字符串数组
// 找到类似这样的模式:
// return [vip, 'encodedStr1', 'encodedStr2', ...]
const stringArrayMatch = code.match(/return\s*\[\s*vip\s*,\s*('[^']*'(?:\s*,\s*'[^']*')*)\s*\]/);
let stringArray = ['cursor']; // vip = 'cursor'
if (stringArrayMatch) {
const stringsSection = stringArrayMatch[1];
const strings = stringsSection.match(/'([^']*)'/g);
if (strings) {
for (const s of strings) {
stringArray.push(s.slice(1, -1));
}
}
console.log(` 提取了 ${stringArray.length} 个数组元素`);
} else {
// 尝试另一种模式 - concat 嵌套数组
const concatPattern = /return\s*\[([^\]]*)\]\.concat/g;
const allArrays = [];
let cm;
while ((cm = concatPattern.exec(code)) !== null) {
const content = cm[1];
const strings = content.match(/'([^']*)'/g);
if (strings) {
for (const s of strings) {
allArrays.push(s.slice(1, -1));
}
}
}
if (allArrays.length > 0) {
stringArray = ['cursor', ...allArrays];
console.log(` 通过 concat 提取了 ${stringArray.length} 个数组元素`);
}
}
// 如果无法提取数组,返回空
if (stringArray.length < 10) {
console.log(' 无法提取足够的字符串数组');
return null;
}
// 尝试解码
const decodeMap = {};
let successCount = 0;
for (const [fullMatch, info] of calls) {
const { num, key } = info;
// 计算实际索引(减去偏移量)
// 不同文件的偏移量不同,需要尝试
for (let offset = 0; offset <= 0x200; offset += 0x10) {
const adjustedIndex = num - offset;
if (adjustedIndex >= 0 && adjustedIndex < stringArray.length) {
const encodedStr = stringArray[adjustedIndex];
const decoded = decodeString(encodedStr, key);
if (decoded && decoded.length > 0 && /^[\x20-\x7E\u4e00-\u9fff]+$/.test(decoded)) {
decodeMap[fullMatch] = decoded;
successCount++;
break;
}
}
}
}
console.log(` 成功解码: ${successCount}/${calls.size}`);
return decodeMap;
}
/**
* 使用已有的解码器脚本为每个文件生成映射
*/
async function generateWithExistingDecoder(inputPath, outputPath, filename) {
console.log(`\n处理: ${filename}`);
console.log('='.repeat(50));
if (fs.existsSync(outputPath)) {
const existing = JSON.parse(fs.readFileSync(outputPath, 'utf8'));
console.log(` 已存在: ${Object.keys(existing).length} 条映射`);
return existing;
}
// 读取代码
const code = fs.readFileSync(inputPath, 'utf8');
// 查找解码器函数名
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(` 解码函数: ${decoderFuncName}`);
// 收集所有调用
const callPattern = new RegExp(
`(_0x[a-f0-9]+)\\s*\\(\\s*(0x[a-f0-9]+)\\s*,\\s*'([^']*)'\\s*\\)`,
'g'
);
const calls = new Set();
let match;
while ((match = callPattern.exec(code)) !== null) {
calls.add(match[0]);
}
console.log(` 找到 ${calls.size} 个调用`);
// 对于没有映射的文件,我们需要用不同的方法
// 使用之前成功的解码器代码片段
return { size: calls.size, decoder: decoderFuncName };
}
// 主函数
async function main() {
console.log('╔════════════════════════════════════════════════════╗');
console.log('║ 直接解码映射生成器 ║');
console.log('║ 使用 RC4 + 非标准 Base64 ║');
console.log('╚════════════════════════════════════════════════════╝');
const files = [
{ 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(inputPath)) {
console.log(`\n跳过: ${file.input} (不存在)`);
continue;
}
const code = fs.readFileSync(inputPath, 'utf8');
const decodeMap = generateDecodeMapForFile(code, file.input);
if (decodeMap && Object.keys(decodeMap).length > 0) {
fs.writeFileSync(outputPath, JSON.stringify(decodeMap, null, 2));
console.log(` 已保存: ${outputPath}`);
}
}
console.log('\n完成');
}
main().catch(console.error);