备份: 完整开发状态(含反混淆脚本和临时文件)
This commit is contained in:
224
final_rename2.js
Normal file
224
final_rename2.js
Normal file
@@ -0,0 +1,224 @@
|
||||
/**
|
||||
* 第二轮变量重命名 - 处理 API 调用结果和常见模式
|
||||
*/
|
||||
const fs = require('fs');
|
||||
const babel = require('@babel/core');
|
||||
const traverse = require('@babel/traverse').default;
|
||||
const generate = require('@babel/generator').default;
|
||||
const t = require('@babel/types');
|
||||
|
||||
const inputPath = 'D:/temp/破解/cursorpro-0.4.5/deobfuscated_full/extension/out/webview/provider.js';
|
||||
const outputPath = 'D:/temp/破解/cursorpro-0.4.5/deobfuscated_full/extension/out/webview/provider.js';
|
||||
|
||||
console.log('╔════════════════════════════════════════════════════╗');
|
||||
console.log('║ 第二轮变量重命名 ║');
|
||||
console.log('╚════════════════════════════════════════════════════╝');
|
||||
|
||||
const code = fs.readFileSync(inputPath, 'utf8');
|
||||
console.log(`读取文件: ${(code.length / 1024).toFixed(2)} KB`);
|
||||
|
||||
console.log('\n[1] 解析 AST...');
|
||||
let ast;
|
||||
try {
|
||||
ast = babel.parseSync(code, {
|
||||
sourceType: 'script',
|
||||
plugins: []
|
||||
});
|
||||
console.log('AST 解析成功');
|
||||
} catch (e) {
|
||||
console.error('AST 解析失败:', e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('\n[2] 智能变量重命名...');
|
||||
let renamedCount = 0;
|
||||
|
||||
const usedNamesPerScope = new Map();
|
||||
|
||||
function getScopeUsedNames(scope) {
|
||||
if (!usedNamesPerScope.has(scope.uid)) {
|
||||
usedNamesPerScope.set(scope.uid, new Set());
|
||||
}
|
||||
return usedNamesPerScope.get(scope.uid);
|
||||
}
|
||||
|
||||
function isNameUsedInScope(scope, name) {
|
||||
if (scope.hasBinding(name)) return true;
|
||||
let s = scope;
|
||||
while (s) {
|
||||
if (getScopeUsedNames(s).has(name)) return true;
|
||||
s = s.parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function renameBinding(path, varName, newName) {
|
||||
const scope = path.scope;
|
||||
let finalName = newName;
|
||||
let counter = 1;
|
||||
while (isNameUsedInScope(scope, finalName)) {
|
||||
finalName = newName + counter++;
|
||||
}
|
||||
|
||||
getScopeUsedNames(scope).add(finalName);
|
||||
|
||||
const binding = scope.getBinding(varName);
|
||||
if (binding) {
|
||||
path.node.id.name = finalName;
|
||||
binding.referencePaths.forEach(ref => {
|
||||
ref.node.name = finalName;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// API 调用模式匹配
|
||||
const apiPatterns = {
|
||||
'verifyKey': 'verifyResult',
|
||||
'switchSeamlessToken': 'switchResult',
|
||||
'getAccount': 'accountResult',
|
||||
'getUsage': 'usageResult',
|
||||
'getAnnouncement': 'announcement',
|
||||
'checkVersion': 'versionResult',
|
||||
'getProxyStatus': 'proxyStatus',
|
||||
'getSeamlessStatus': 'seamlessStatus',
|
||||
};
|
||||
|
||||
traverse(ast, {
|
||||
VariableDeclarator(path) {
|
||||
if (!t.isIdentifier(path.node.id)) return;
|
||||
const varName = path.node.id.name;
|
||||
|
||||
if (!/^var\d+$/.test(varName)) return;
|
||||
|
||||
const init = path.node.init;
|
||||
let newName = null;
|
||||
|
||||
// await client_1.xxx() -> xxxResult
|
||||
if (t.isAwaitExpression(init)) {
|
||||
const arg = init.argument;
|
||||
if (t.isCallExpression(arg)) {
|
||||
const callee = arg.callee;
|
||||
if (t.isMemberExpression(callee)) {
|
||||
const objName = callee.object.name || '';
|
||||
const methodName = callee.property.name || '';
|
||||
|
||||
// client_1.xxx
|
||||
if (objName === 'client_1' && apiPatterns[methodName]) {
|
||||
newName = apiPatterns[methodName];
|
||||
}
|
||||
// this._xxx
|
||||
else if (t.isThisExpression(callee.object)) {
|
||||
if (methodName.startsWith('_get')) {
|
||||
const base = methodName.slice(4);
|
||||
newName = base.charAt(0).toLowerCase() + base.slice(1);
|
||||
} else if (methodName.startsWith('_check')) {
|
||||
newName = 'checkResult';
|
||||
}
|
||||
}
|
||||
// xxx.exec()
|
||||
else if (methodName === 'exec') {
|
||||
newName = 'execResult';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 字符串方法调用结果
|
||||
if (t.isCallExpression(init)) {
|
||||
const callee = init.callee;
|
||||
if (t.isMemberExpression(callee)) {
|
||||
const methodName = callee.property.name || '';
|
||||
|
||||
if (methodName === 'replace') newName = 'replaced';
|
||||
else if (methodName === 'trim') newName = 'trimmed';
|
||||
else if (methodName === 'toLowerCase') newName = 'lowerStr';
|
||||
else if (methodName === 'toUpperCase') newName = 'upperStr';
|
||||
else if (methodName === 'slice') newName = 'sliced';
|
||||
else if (methodName === 'substring') newName = 'substr';
|
||||
else if (methodName === 'concat') newName = 'concatenated';
|
||||
else if (methodName === 'normalize') newName = 'normalized';
|
||||
}
|
||||
}
|
||||
|
||||
if (newName && renameBinding(path, varName, newName)) {
|
||||
renamedCount++;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`重命名了 ${renamedCount} 个变量`);
|
||||
|
||||
console.log('\n[3] 处理方法参数...');
|
||||
let paramCount = 0;
|
||||
|
||||
// 收集方法名和参数的映射
|
||||
const methodParamNames = {
|
||||
'constructor': ['extensionUri', 'context'],
|
||||
'_handleActivate': ['key'],
|
||||
'_handleSwitch': [],
|
||||
'_handleReset': [],
|
||||
'_handleDisable': [],
|
||||
'_writeAccountToLocal': ['accountData'],
|
||||
'_writeHostsFile': ['content'],
|
||||
'_handleToggleProxy': ['enabled', 'silent'],
|
||||
'_handleToggleSeamless': ['enabled'],
|
||||
'_handleGetAccountUsage': ['forceRefresh'],
|
||||
'_handleCheckUsageBeforeSwitch': ['silent'],
|
||||
'_postMessage': ['message'],
|
||||
'_grantHostsWritePermission': [],
|
||||
'resolveWebviewView': ['webviewView', 'context', 'token'],
|
||||
'_handleInjectSeamless': [],
|
||||
'_handleRestoreSeamless': [],
|
||||
'_handleManualSeamlessSwitch': [],
|
||||
};
|
||||
|
||||
traverse(ast, {
|
||||
ClassMethod(path) {
|
||||
const methodName = path.node.key.name || '';
|
||||
const expectedParams = methodParamNames[methodName];
|
||||
|
||||
if (!expectedParams) return;
|
||||
|
||||
const params = path.node.params;
|
||||
for (let i = 0; i < params.length && i < expectedParams.length; i++) {
|
||||
const param = params[i];
|
||||
const newName = expectedParams[i];
|
||||
if (!newName) continue; // 跳过空名称
|
||||
if (t.isIdentifier(param) && /^arg\d+$/.test(param.name)) {
|
||||
const binding = path.scope.getBinding(param.name);
|
||||
if (binding) {
|
||||
param.name = newName;
|
||||
binding.referencePaths.forEach(ref => {
|
||||
ref.node.name = newName;
|
||||
});
|
||||
paramCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`重命名了 ${paramCount} 个参数`);
|
||||
|
||||
console.log('\n[4] 生成代码...');
|
||||
const output = generate(ast, {
|
||||
comments: false,
|
||||
compact: false,
|
||||
concise: false
|
||||
}, code);
|
||||
|
||||
let finalCode = output.code;
|
||||
finalCode = finalCode.replace(/\["([a-zA-Z_$][a-zA-Z0-9_$]*)"\]/g, '.$1');
|
||||
|
||||
console.log('\n[5] 保存文件...');
|
||||
fs.writeFileSync(outputPath, finalCode);
|
||||
console.log(`保存到: ${outputPath}`);
|
||||
console.log(`新文件大小: ${(finalCode.length / 1024).toFixed(2)} KB`);
|
||||
|
||||
const remaining = (finalCode.match(/\b(var|arg)\d+\b/g) || []);
|
||||
const unique = [...new Set(remaining)];
|
||||
console.log(`\n剩余通用变量名: ${unique.length} 个唯一名称`);
|
||||
|
||||
console.log('\n✅ 完成!');
|
||||
Reference in New Issue
Block a user