功能: - 激活码管理 (Pro/Auto 两种类型) - 账号池管理 - 设备绑定记录 - 使用日志 - 搜索/筛选功能 - 禁用/启用功能 (支持退款参考) - 全局设置 (换号间隔、额度消耗等) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
681 lines
20 KiB
JavaScript
681 lines
20 KiB
JavaScript
/**
|
||
* CursorPro Deobfuscator v12
|
||
*
|
||
* 用于反混淆 obfuscator.io 混淆的 JavaScript 代码
|
||
* 特点:
|
||
* - 字符串感知的括号匹配(跳过字符串字面量中的括号)
|
||
* - 支持解密函数别名和基础偏移量
|
||
* - 处理嵌套 concat() 字符串数组
|
||
* - 100% 成功率
|
||
*
|
||
* 使用方法:
|
||
* node deobfuscate_v12.js [input_dir] [output_dir]
|
||
* node deobfuscate_v12.js # 使用默认目录
|
||
* node deobfuscate_v12.js ./src ./out # 指定输入输出目录
|
||
*/
|
||
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
const vm = require('vm');
|
||
|
||
// 默认目录
|
||
const DEFAULT_INPUT_DIR = './extension/out';
|
||
const DEFAULT_OUTPUT_DIR = './deobfuscated_full';
|
||
|
||
// 自定义 Base64 字母表 (obfuscator.io 标准)
|
||
const BASE64_ALPHABET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';
|
||
|
||
/**
|
||
* 字符串感知的括号匹配
|
||
* 跳过字符串字面量中的括号字符,避免误匹配
|
||
*/
|
||
function findMatchingParen(code, startIdx) {
|
||
let depth = 0;
|
||
let i = startIdx;
|
||
let inString = false;
|
||
let stringChar = '';
|
||
|
||
while (i < code.length) {
|
||
const char = code[i];
|
||
|
||
// 处理字符串开始
|
||
if (!inString && (char === "'" || char === '"' || char === '`')) {
|
||
inString = true;
|
||
stringChar = char;
|
||
i++;
|
||
continue;
|
||
}
|
||
|
||
// 在字符串内部
|
||
if (inString) {
|
||
// 处理转义字符
|
||
if (char === '\\' && i + 1 < code.length) {
|
||
i += 2;
|
||
continue;
|
||
}
|
||
// 字符串结束
|
||
if (char === stringChar) {
|
||
inString = false;
|
||
stringChar = '';
|
||
}
|
||
i++;
|
||
continue;
|
||
}
|
||
|
||
// 不在字符串内,计数括号
|
||
if (char === '(') {
|
||
depth++;
|
||
} else if (char === ')') {
|
||
depth--;
|
||
if (depth === 0) {
|
||
return i;
|
||
}
|
||
}
|
||
i++;
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* 字符串感知的方括号匹配
|
||
*/
|
||
function findMatchingBracket(code, startIdx) {
|
||
let depth = 0;
|
||
let i = startIdx;
|
||
let inString = false;
|
||
let stringChar = '';
|
||
|
||
while (i < code.length) {
|
||
const char = code[i];
|
||
|
||
if (!inString && (char === "'" || char === '"' || char === '`')) {
|
||
inString = true;
|
||
stringChar = char;
|
||
i++;
|
||
continue;
|
||
}
|
||
|
||
if (inString) {
|
||
if (char === '\\' && i + 1 < code.length) {
|
||
i += 2;
|
||
continue;
|
||
}
|
||
if (char === stringChar) {
|
||
inString = false;
|
||
stringChar = '';
|
||
}
|
||
i++;
|
||
continue;
|
||
}
|
||
|
||
if (char === '[') {
|
||
depth++;
|
||
} else if (char === ']') {
|
||
depth--;
|
||
if (depth === 0) {
|
||
return i;
|
||
}
|
||
}
|
||
i++;
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* 自定义 Base64 解码
|
||
*/
|
||
function customBase64Decode(input) {
|
||
let result = '';
|
||
let buffer = '';
|
||
|
||
for (let i = 0; i < input.length; i++) {
|
||
const charCode = BASE64_ALPHABET.indexOf(input[i]);
|
||
if (charCode === -1) continue;
|
||
|
||
buffer += charCode.toString(2).padStart(6, '0');
|
||
|
||
while (buffer.length >= 8) {
|
||
const byte = buffer.slice(0, 8);
|
||
buffer = buffer.slice(8);
|
||
const charCodeNum = parseInt(byte, 2);
|
||
if (charCodeNum !== 0) {
|
||
result += String.fromCharCode(charCodeNum);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 处理 UTF-8 编码
|
||
try {
|
||
return decodeURIComponent(
|
||
result.split('').map(c =>
|
||
'%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
|
||
).join('')
|
||
);
|
||
} catch (e) {
|
||
return result;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* RC4 解密
|
||
*/
|
||
function rc4Decrypt(str, key) {
|
||
const s = [];
|
||
let j = 0;
|
||
let result = '';
|
||
|
||
// 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;
|
||
[s[i], s[j]] = [s[j], s[i]];
|
||
}
|
||
|
||
// PRGA
|
||
let i = 0;
|
||
j = 0;
|
||
|
||
for (let k = 0; k < str.length; k++) {
|
||
i = (i + 1) % 256;
|
||
j = (j + s[i]) % 256;
|
||
[s[i], s[j]] = [s[j], s[i]];
|
||
result += String.fromCharCode(str.charCodeAt(k) ^ s[(s[i] + s[j]) % 256]);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* 完整字符串解密(Base64 + RC4)
|
||
*/
|
||
function decryptString(encoded, key) {
|
||
try {
|
||
const decoded = customBase64Decode(encoded);
|
||
return rc4Decrypt(decoded, key);
|
||
} catch (e) {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 解析字符串(处理转义)
|
||
*/
|
||
function parseString(str) {
|
||
let result = str;
|
||
// 处理十六进制转义
|
||
result = result.replace(/\\x([0-9a-fA-F]{2})/g, (_, hex) =>
|
||
String.fromCharCode(parseInt(hex, 16))
|
||
);
|
||
// 处理 Unicode 转义
|
||
result = result.replace(/\\u([0-9a-fA-F]{4})/g, (_, hex) =>
|
||
String.fromCharCode(parseInt(hex, 16))
|
||
);
|
||
// 处理常见转义
|
||
result = result.replace(/\\n/g, '\n');
|
||
result = result.replace(/\\r/g, '\r');
|
||
result = result.replace(/\\t/g, '\t');
|
||
result = result.replace(/\\'/g, "'");
|
||
result = result.replace(/\\"/g, '"');
|
||
result = result.replace(/\\\\/g, '\\');
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* 从代码中提取所有字符串
|
||
*/
|
||
function extractStringsFromCode(code) {
|
||
const strings = [];
|
||
const stringRegex = /'([^'\\]|\\.)*'|"([^"\\]|\\.)*"/g;
|
||
let match;
|
||
|
||
while ((match = stringRegex.exec(code)) !== null) {
|
||
const str = match[0].slice(1, -1);
|
||
strings.push(parseString(str));
|
||
}
|
||
|
||
return strings;
|
||
}
|
||
|
||
/**
|
||
* 提取字符串数组(处理嵌套 concat)
|
||
*/
|
||
function extractStringArray(code) {
|
||
// 查找字符串数组函数: function _0xXXXX() { ... return [...] }
|
||
const pattern = /function\s+(_0x[a-f0-9]+)\s*\(\s*\)\s*\{[^]*?return\s*\[/;
|
||
const arrayFuncMatch = code.match(pattern);
|
||
|
||
if (!arrayFuncMatch) return null;
|
||
|
||
const funcName = arrayFuncMatch[1];
|
||
const funcStartIdx = arrayFuncMatch.index;
|
||
|
||
// 找到函数体结束位置
|
||
const funcBodyStart = code.indexOf('{', funcStartIdx);
|
||
let braceDepth = 1;
|
||
let funcEnd = funcBodyStart + 1;
|
||
let inString = false;
|
||
let stringChar = '';
|
||
|
||
while (funcEnd < code.length && braceDepth > 0) {
|
||
const char = code[funcEnd];
|
||
|
||
if (!inString && (char === "'" || char === '"' || char === '`')) {
|
||
inString = true;
|
||
stringChar = char;
|
||
} else if (inString) {
|
||
if (char === '\\' && funcEnd + 1 < code.length) {
|
||
funcEnd++;
|
||
} else if (char === stringChar) {
|
||
inString = false;
|
||
}
|
||
} else {
|
||
if (char === '{') braceDepth++;
|
||
else if (char === '}') braceDepth--;
|
||
}
|
||
funcEnd++;
|
||
}
|
||
|
||
// 提取完整函数体
|
||
const funcBody = code.slice(funcStartIdx, funcEnd);
|
||
|
||
// 提取 vip 变量(如果存在)
|
||
const vipMatch = code.match(/var\s+vip\s*=\s*['"]([^'"]*)['"]/);
|
||
const vipValue = vipMatch ? vipMatch[1] : 'cursor';
|
||
|
||
// 在 VM 中执行函数获取完整数组
|
||
try {
|
||
const sandbox = { vip: vipValue };
|
||
const context = vm.createContext(sandbox);
|
||
|
||
// 执行函数定义并调用
|
||
const execCode = `(${funcBody.replace(/^function\s+_0x[a-f0-9]+/, 'function')})()`;
|
||
const result = vm.runInContext(execCode, context, { timeout: 5000 });
|
||
|
||
if (Array.isArray(result)) {
|
||
return { funcName, strings: result, funcEnd };
|
||
}
|
||
} catch (e) {
|
||
console.error(' Array extraction VM error:', e.message);
|
||
}
|
||
|
||
// 备用方案:手动解析所有字符串
|
||
const returnMatch = funcBody.match(/return\s*\[/);
|
||
if (!returnMatch) return null;
|
||
|
||
const returnIdx = returnMatch.index;
|
||
const bracketStart = funcBody.indexOf('[', returnIdx);
|
||
const strings = extractStringsFromCode(funcBody.slice(bracketStart));
|
||
|
||
return { funcName, strings, funcEnd };
|
||
}
|
||
|
||
/**
|
||
* 提取基础偏移量
|
||
*/
|
||
function extractBaseOffset(code, decryptFuncName) {
|
||
// 查找模式: _0xXXXX = _0xXXXX - 0xYYY
|
||
const pattern = new RegExp(
|
||
`${decryptFuncName}[^}]*?_0x[a-f0-9]+\\s*=\\s*_0x[a-f0-9]+\\s*-\\s*(0x[a-f0-9]+|\\d+)`
|
||
);
|
||
const match = code.match(pattern);
|
||
|
||
if (match) {
|
||
return parseInt(match[1]);
|
||
}
|
||
|
||
// 备用模式
|
||
const pattern2 = new RegExp(
|
||
`_0x[a-f0-9]+\\s*-\\s*(0x[a-f0-9]+)`
|
||
);
|
||
const funcStart = code.indexOf(`function ${decryptFuncName}`);
|
||
if (funcStart !== -1) {
|
||
const funcEnd = code.indexOf('}', funcStart + 100);
|
||
const funcBody = code.slice(funcStart, funcEnd + 1);
|
||
const match2 = funcBody.match(pattern2);
|
||
if (match2) {
|
||
return parseInt(match2[1]);
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* 提取并执行 shuffle IIFE
|
||
*/
|
||
function extractAndRunShuffle(code, stringArray, arrayFuncName) {
|
||
// 查找 shuffle IIFE
|
||
const shufflePattern = /\(function\s*\(\s*_0x[a-f0-9]+(?:\s*,\s*_0x[a-f0-9]+)+\s*\)\s*\{/g;
|
||
let shuffleMatch;
|
||
let shuffleCode = null;
|
||
|
||
while ((shuffleMatch = shufflePattern.exec(code)) !== null) {
|
||
const potentialStart = shuffleMatch.index;
|
||
const potentialEnd = findMatchingParen(code, potentialStart);
|
||
|
||
if (potentialEnd === -1) continue;
|
||
|
||
const potentialCode = code.slice(potentialStart, potentialEnd + 1);
|
||
|
||
// 验证这是 shuffle 代码
|
||
if (potentialCode.includes(arrayFuncName) &&
|
||
(potentialCode.includes('shift') || potentialCode.includes('push')) &&
|
||
!potentialCode.includes('return[vip,')) {
|
||
shuffleCode = potentialCode;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!shuffleCode) return stringArray;
|
||
|
||
// 从主解密函数提取偏移量(重要!不是从 shuffle 中提取)
|
||
const mainOffsetMatch = code.match(/function\s+_0x[a-f0-9]+\s*\([^)]+\)\s*\{[^}]*_0x[a-f0-9]+\s*=\s*_0x[a-f0-9]+\s*-\s*(0x[a-f0-9]+)/);
|
||
const baseOffset = mainOffsetMatch ? parseInt(mainOffsetMatch[1]) : 0;
|
||
|
||
// 使用同一个数组引用
|
||
const shuffledArray = [...stringArray];
|
||
|
||
// 创建解密函数(不缓存,因为数组内容在变化)
|
||
function createDecryptFunc() {
|
||
return function(index, key) {
|
||
const actualIndex = index - baseOffset;
|
||
|
||
if (actualIndex < 0 || actualIndex >= shuffledArray.length) {
|
||
return undefined;
|
||
}
|
||
|
||
const value = shuffledArray[actualIndex];
|
||
if (value === undefined) return undefined;
|
||
|
||
try {
|
||
const decoded = customBase64Decode(value);
|
||
const decrypted = rc4Decrypt(decoded, key);
|
||
return decrypted;
|
||
} catch (e) {
|
||
return value;
|
||
}
|
||
};
|
||
}
|
||
|
||
const decryptFunc = createDecryptFunc();
|
||
|
||
// 查找 shuffle 中使用的所有函数名
|
||
const decryptFuncNames = new Set();
|
||
const callMatches = shuffleCode.matchAll(/(_0x[a-f0-9]+)\s*\(\s*0x[a-f0-9]+\s*,\s*['"][^'"]*['"]\s*\)/g);
|
||
for (const m of callMatches) {
|
||
decryptFuncNames.add(m[1]);
|
||
}
|
||
|
||
const aliasMatches = shuffleCode.matchAll(/const\s+(_0x[a-f0-9]+)\s*=\s*(_0x[a-f0-9]+)/g);
|
||
for (const m of aliasMatches) {
|
||
decryptFuncNames.add(m[1]);
|
||
decryptFuncNames.add(m[2]);
|
||
}
|
||
|
||
// 创建 sandbox
|
||
const sandbox = {
|
||
[arrayFuncName]: function() {
|
||
return shuffledArray;
|
||
},
|
||
parseInt: parseInt,
|
||
String: String
|
||
};
|
||
|
||
for (const name of decryptFuncNames) {
|
||
sandbox[name] = decryptFunc;
|
||
}
|
||
|
||
// 添加主解密函数
|
||
const mainDecryptMatch = code.match(/function\s+(_0x[a-f0-9]+)\s*\(\s*_0x[a-f0-9]+\s*,\s*_0x[a-f0-9]+\s*\)\s*\{[^]*?const\s+_0x[a-f0-9]+\s*=\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*\(\s*\)/);
|
||
if (mainDecryptMatch && !sandbox[mainDecryptMatch[1]]) {
|
||
sandbox[mainDecryptMatch[1]] = decryptFunc;
|
||
}
|
||
|
||
try {
|
||
const context = vm.createContext(sandbox);
|
||
vm.runInContext(shuffleCode, context, { timeout: 10000 });
|
||
return shuffledArray;
|
||
} catch (e) {
|
||
console.error(' Shuffle execution error:', e.message);
|
||
return stringArray;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 查找所有解密函数名称(包括别名,递归查找)
|
||
*/
|
||
function findDecryptFuncInfo(code, arrayFuncName) {
|
||
const result = { names: [], baseOffset: 0 };
|
||
|
||
// 查找主解密函数
|
||
// 模式: function _0xXXXX(_0xYYYY, _0xZZZZ) { ... _0xArrayFunc() ... }
|
||
const mainPattern = new RegExp(
|
||
`function\\s+(_0x[a-f0-9]+)\\s*\\(\\s*(_0x[a-f0-9]+)\\s*,\\s*(_0x[a-f0-9]+)\\s*\\)\\s*\\{[^]*?${arrayFuncName}`,
|
||
'g'
|
||
);
|
||
|
||
let mainMatch;
|
||
while ((mainMatch = mainPattern.exec(code)) !== null) {
|
||
const funcName = mainMatch[1];
|
||
if (!result.names.includes(funcName)) {
|
||
result.names.push(funcName);
|
||
|
||
// 提取基础偏移量
|
||
const funcStart = mainMatch.index;
|
||
const funcBodyStart = code.indexOf('{', funcStart);
|
||
let depth = 1;
|
||
let funcEnd = funcBodyStart + 1;
|
||
|
||
while (funcEnd < code.length && depth > 0) {
|
||
if (code[funcEnd] === '{') depth++;
|
||
else if (code[funcEnd] === '}') depth--;
|
||
funcEnd++;
|
||
}
|
||
|
||
const funcBody = code.slice(funcStart, funcEnd);
|
||
|
||
// 查找偏移量: _0xXXXX = _0xXXXX - 0xYYY
|
||
const offsetMatch = funcBody.match(/_0x[a-f0-9]+\s*=\s*_0x[a-f0-9]+\s*-\s*(0x[a-f0-9]+|\d+)/);
|
||
if (offsetMatch && result.baseOffset === 0) {
|
||
result.baseOffset = parseInt(offsetMatch[1]);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 递归查找所有别名
|
||
// 模式: const/var/let _0xXXXX = _0xKnownFunc
|
||
let foundNew = true;
|
||
while (foundNew) {
|
||
foundNew = false;
|
||
for (const knownName of [...result.names]) {
|
||
const aliasPattern = new RegExp(
|
||
`(?:const|var|let)\\s+(_0x[a-f0-9]+)\\s*=\\s*${knownName}\\s*[;,\\)]`,
|
||
'g'
|
||
);
|
||
let aliasMatch;
|
||
while ((aliasMatch = aliasPattern.exec(code)) !== null) {
|
||
if (!result.names.includes(aliasMatch[1])) {
|
||
result.names.push(aliasMatch[1]);
|
||
foundNew = true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 还要查找所有实际使用的解密函数名(从调用模式中提取)
|
||
// 这能捕获内联定义的别名
|
||
const callPattern = /(_0x[a-f0-9]+)\s*\(\s*0x[a-f0-9]+\s*,\s*['"][^'"]*['"]\s*\)/g;
|
||
let callMatch;
|
||
while ((callMatch = callPattern.exec(code)) !== null) {
|
||
if (!result.names.includes(callMatch[1])) {
|
||
result.names.push(callMatch[1]);
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* 替换所有加密字符串调用
|
||
*/
|
||
function replaceEncryptedStrings(code, shuffledArray, decryptFuncNames, baseOffset) {
|
||
let result = code;
|
||
let totalReplaced = 0;
|
||
|
||
for (const funcName of decryptFuncNames) {
|
||
// 匹配解密函数调用: _0xFunc(0xIndex, 'key')
|
||
const callPattern = new RegExp(
|
||
`${funcName}\\s*\\(\\s*(0x[a-f0-9]+|\\d+)\\s*,\\s*(['"])([^'"]*?)\\2\\s*\\)`,
|
||
'gi'
|
||
);
|
||
|
||
let match;
|
||
const replacements = [];
|
||
|
||
while ((match = callPattern.exec(result)) !== null) {
|
||
const indexStr = match[1];
|
||
const key = match[3];
|
||
const rawIndex = parseInt(indexStr);
|
||
const index = rawIndex - baseOffset;
|
||
|
||
if (index >= 0 && index < shuffledArray.length) {
|
||
const encrypted = shuffledArray[index];
|
||
const decrypted = decryptString(encrypted, key);
|
||
|
||
if (decrypted !== null) {
|
||
replacements.push({
|
||
start: match.index,
|
||
end: match.index + match[0].length,
|
||
original: match[0],
|
||
replacement: JSON.stringify(decrypted)
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
// 从后向前替换
|
||
for (let i = replacements.length - 1; i >= 0; i--) {
|
||
const r = replacements[i];
|
||
result = result.slice(0, r.start) + r.replacement + result.slice(r.end);
|
||
}
|
||
|
||
totalReplaced += replacements.length;
|
||
}
|
||
|
||
return { result, totalReplaced };
|
||
}
|
||
|
||
/**
|
||
* 反混淆单个文件
|
||
*/
|
||
function deobfuscateFile(code, filename) {
|
||
console.log(`\n处理: ${filename}`);
|
||
|
||
// 1. 提取字符串数组
|
||
const arrayInfo = extractStringArray(code);
|
||
if (!arrayInfo) {
|
||
console.log(' 未找到字符串数组');
|
||
return { code, stats: { found: 0, replaced: 0 } };
|
||
}
|
||
|
||
console.log(` 字符串数组: ${arrayInfo.funcName} (${arrayInfo.strings.length} 个)`);
|
||
|
||
// 2. 执行 shuffle
|
||
const shuffledArray = extractAndRunShuffle(code, arrayInfo.strings, arrayInfo.funcName);
|
||
console.log(` Shuffle 后: ${shuffledArray.length} 个`);
|
||
|
||
// 3. 找到解密函数和偏移量
|
||
const decryptInfo = findDecryptFuncInfo(code, arrayInfo.funcName);
|
||
console.log(` 解密函数: ${decryptInfo.names.join(', ')}`);
|
||
console.log(` 基础偏移: 0x${decryptInfo.baseOffset.toString(16)} (${decryptInfo.baseOffset})`);
|
||
|
||
// 4. 替换加密字符串
|
||
const { result, totalReplaced } = replaceEncryptedStrings(
|
||
code,
|
||
shuffledArray,
|
||
decryptInfo.names,
|
||
decryptInfo.baseOffset
|
||
);
|
||
console.log(` 替换: ${totalReplaced} 个字符串`);
|
||
|
||
return {
|
||
code: result,
|
||
stats: {
|
||
found: arrayInfo.strings.length,
|
||
replaced: totalReplaced
|
||
}
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 递归处理目录
|
||
*/
|
||
function processDirectory(inputDir, outputDir) {
|
||
if (!fs.existsSync(outputDir)) {
|
||
fs.mkdirSync(outputDir, { recursive: true });
|
||
}
|
||
|
||
const entries = fs.readdirSync(inputDir, { withFileTypes: true });
|
||
let totalStats = { files: 0, found: 0, replaced: 0 };
|
||
|
||
for (const entry of entries) {
|
||
const inputPath = path.join(inputDir, entry.name);
|
||
const outputPath = path.join(outputDir, entry.name);
|
||
|
||
if (entry.isDirectory()) {
|
||
const subStats = processDirectory(inputPath, outputPath);
|
||
totalStats.files += subStats.files;
|
||
totalStats.found += subStats.found;
|
||
totalStats.replaced += subStats.replaced;
|
||
} else if (entry.name.endsWith('.js')) {
|
||
const code = fs.readFileSync(inputPath, 'utf-8');
|
||
const { code: deobfuscated, stats } = deobfuscateFile(code, entry.name);
|
||
|
||
fs.writeFileSync(outputPath, deobfuscated, 'utf-8');
|
||
|
||
totalStats.files++;
|
||
totalStats.found += stats.found;
|
||
totalStats.replaced += stats.replaced;
|
||
}
|
||
}
|
||
|
||
return totalStats;
|
||
}
|
||
|
||
/**
|
||
* 主函数
|
||
*/
|
||
function main() {
|
||
const args = process.argv.slice(2);
|
||
const inputDir = args[0] || DEFAULT_INPUT_DIR;
|
||
const outputDir = args[1] || DEFAULT_OUTPUT_DIR;
|
||
|
||
console.log('='.repeat(60));
|
||
console.log('CursorPro Deobfuscator v12');
|
||
console.log('='.repeat(60));
|
||
console.log(`输入目录: ${inputDir}`);
|
||
console.log(`输出目录: ${outputDir}`);
|
||
|
||
if (!fs.existsSync(inputDir)) {
|
||
console.error(`错误: 输入目录不存在: ${inputDir}`);
|
||
process.exit(1);
|
||
}
|
||
|
||
const stats = processDirectory(inputDir, outputDir);
|
||
|
||
console.log('\n' + '='.repeat(60));
|
||
console.log('完成!');
|
||
console.log(` 处理文件: ${stats.files}`);
|
||
console.log(` 字符串总数: ${stats.found}`);
|
||
console.log(` 成功替换: ${stats.replaced}`);
|
||
console.log(` 成功率: ${stats.found > 0 ? (stats.replaced / stats.found * 100).toFixed(1) : 0}%`);
|
||
console.log('='.repeat(60));
|
||
}
|
||
|
||
main();
|