备份: 完整开发状态(含反混淆脚本和临时文件)
This commit is contained in:
250
simplify_control_flow.js
Normal file
250
simplify_control_flow.js
Normal file
@@ -0,0 +1,250 @@
|
||||
/**
|
||||
* 控制流简化工具
|
||||
* 移除对象包装的简单操作
|
||||
*/
|
||||
const fs = require('fs');
|
||||
|
||||
// 尝试使用 babel
|
||||
let babel, traverse, generate, t;
|
||||
try {
|
||||
babel = require('@babel/core');
|
||||
traverse = require('@babel/traverse').default;
|
||||
generate = require('@babel/generator').default;
|
||||
t = require('@babel/types');
|
||||
} catch (e) {
|
||||
console.log('需要安装 babel 依赖...');
|
||||
require('child_process').execSync('npm install @babel/core @babel/traverse @babel/generator @babel/types --save-dev', {
|
||||
stdio: 'inherit',
|
||||
cwd: 'D:/temp/破解/cursorpro-0.4.5'
|
||||
});
|
||||
babel = require('@babel/core');
|
||||
traverse = require('@babel/traverse').default;
|
||||
generate = require('@babel/generator').default;
|
||||
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_simplified.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] 收集对象定义...');
|
||||
|
||||
// 存储对象属性的映射
|
||||
const objectMappings = new Map();
|
||||
|
||||
// 第一遍:收集所有 const varX = { 'key': function... } 形式的定义
|
||||
traverse(ast, {
|
||||
VariableDeclarator(path) {
|
||||
if (!t.isIdentifier(path.node.id)) return;
|
||||
if (!t.isObjectExpression(path.node.init)) return;
|
||||
|
||||
const varName = path.node.id.name;
|
||||
const props = {};
|
||||
let isSimpleObject = true;
|
||||
|
||||
for (const prop of path.node.init.properties) {
|
||||
if (!t.isObjectProperty(prop)) {
|
||||
isSimpleObject = false;
|
||||
break;
|
||||
}
|
||||
|
||||
let key;
|
||||
if (t.isStringLiteral(prop.key)) {
|
||||
key = prop.key.value;
|
||||
} else if (t.isIdentifier(prop.key)) {
|
||||
key = prop.key.name;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查是否是简单的函数包装器
|
||||
if (t.isFunctionExpression(prop.value)) {
|
||||
const func = prop.value;
|
||||
if (func.body.body.length === 1 && t.isReturnStatement(func.body.body[0])) {
|
||||
const ret = func.body.body[0].argument;
|
||||
|
||||
// 二元操作: return a === b
|
||||
if (t.isBinaryExpression(ret) && func.params.length === 2) {
|
||||
const [p1, p2] = func.params;
|
||||
if (t.isIdentifier(ret.left) && t.isIdentifier(ret.right) &&
|
||||
ret.left.name === p1.name && ret.right.name === p2.name) {
|
||||
props[key] = { type: 'binary', operator: ret.operator };
|
||||
}
|
||||
}
|
||||
// 逻辑操作: return a && b
|
||||
else if (t.isLogicalExpression(ret) && func.params.length === 2) {
|
||||
const [p1, p2] = func.params;
|
||||
if (t.isIdentifier(ret.left) && t.isIdentifier(ret.right) &&
|
||||
ret.left.name === p1.name && ret.right.name === p2.name) {
|
||||
props[key] = { type: 'logical', operator: ret.operator };
|
||||
}
|
||||
}
|
||||
// 函数调用: return a(b) 或 return a(b, c)
|
||||
else if (t.isCallExpression(ret)) {
|
||||
if (t.isIdentifier(ret.callee) && ret.callee.name === func.params[0]?.name) {
|
||||
props[key] = { type: 'call', argCount: ret.arguments.length };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 字符串字面量
|
||||
else if (t.isStringLiteral(prop.value)) {
|
||||
props[key] = { type: 'string', value: prop.value.value };
|
||||
}
|
||||
// 数字字面量
|
||||
else if (t.isNumericLiteral(prop.value)) {
|
||||
props[key] = { type: 'number', value: prop.value.value };
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(props).length > 0) {
|
||||
objectMappings.set(varName, props);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`找到 ${objectMappings.size} 个可简化的对象定义`);
|
||||
|
||||
console.log('\n[3] 简化调用...');
|
||||
let simplifiedCount = 0;
|
||||
|
||||
traverse(ast, {
|
||||
// 简化 obj.key(a, b) 或 obj['key'](a, b) 调用
|
||||
CallExpression(path) {
|
||||
const callee = path.node.callee;
|
||||
|
||||
if (!t.isMemberExpression(callee)) return;
|
||||
if (!t.isIdentifier(callee.object)) return;
|
||||
|
||||
const objName = callee.object.name;
|
||||
const mapping = objectMappings.get(objName);
|
||||
if (!mapping) return;
|
||||
|
||||
let propName;
|
||||
if (t.isStringLiteral(callee.property)) {
|
||||
propName = callee.property.value;
|
||||
} else if (t.isIdentifier(callee.property) && !callee.computed) {
|
||||
propName = callee.property.name;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
const propInfo = mapping[propName];
|
||||
if (!propInfo) return;
|
||||
|
||||
const args = path.node.arguments;
|
||||
|
||||
// 二元操作
|
||||
if (propInfo.type === 'binary' && args.length === 2) {
|
||||
path.replaceWith(t.binaryExpression(propInfo.operator, args[0], args[1]));
|
||||
simplifiedCount++;
|
||||
}
|
||||
// 逻辑操作
|
||||
else if (propInfo.type === 'logical' && args.length === 2) {
|
||||
path.replaceWith(t.logicalExpression(propInfo.operator, args[0], args[1]));
|
||||
simplifiedCount++;
|
||||
}
|
||||
// 函数调用
|
||||
else if (propInfo.type === 'call' && args.length >= 1) {
|
||||
const fn = args[0];
|
||||
const fnArgs = args.slice(1);
|
||||
path.replaceWith(t.callExpression(fn, fnArgs));
|
||||
simplifiedCount++;
|
||||
}
|
||||
},
|
||||
|
||||
// 简化 obj.key 或 obj['key'] 属性访问(字符串/数字)
|
||||
MemberExpression(path) {
|
||||
if (path.parent && t.isCallExpression(path.parent) && path.parent.callee === path.node) {
|
||||
return; // 已在 CallExpression 中处理
|
||||
}
|
||||
|
||||
if (!t.isIdentifier(path.node.object)) return;
|
||||
|
||||
const objName = path.node.object.name;
|
||||
const mapping = objectMappings.get(objName);
|
||||
if (!mapping) return;
|
||||
|
||||
let propName;
|
||||
if (t.isStringLiteral(path.node.property)) {
|
||||
propName = path.node.property.value;
|
||||
} else if (t.isIdentifier(path.node.property) && !path.node.computed) {
|
||||
propName = path.node.property.name;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
const propInfo = mapping[propName];
|
||||
if (!propInfo) return;
|
||||
|
||||
if (propInfo.type === 'string') {
|
||||
path.replaceWith(t.stringLiteral(propInfo.value));
|
||||
simplifiedCount++;
|
||||
} else if (propInfo.type === 'number') {
|
||||
path.replaceWith(t.numericLiteral(propInfo.value));
|
||||
simplifiedCount++;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`简化了 ${simplifiedCount} 处调用`);
|
||||
|
||||
console.log('\n[4] 移除未使用的对象定义...');
|
||||
let removedCount = 0;
|
||||
|
||||
// 收集所有标识符使用情况
|
||||
const usedIdentifiers = new Set();
|
||||
traverse(ast, {
|
||||
Identifier(path) {
|
||||
if (!path.isReferencedIdentifier()) return;
|
||||
usedIdentifiers.add(path.node.name);
|
||||
}
|
||||
});
|
||||
|
||||
// 移除未使用的变量声明
|
||||
traverse(ast, {
|
||||
VariableDeclarator(path) {
|
||||
if (!t.isIdentifier(path.node.id)) return;
|
||||
const name = path.node.id.name;
|
||||
|
||||
if (objectMappings.has(name) && !usedIdentifiers.has(name)) {
|
||||
path.remove();
|
||||
removedCount++;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`移除了 ${removedCount} 个未使用的对象`);
|
||||
|
||||
console.log('\n[5] 生成代码...');
|
||||
const output = generate(ast, {
|
||||
comments: false,
|
||||
compact: false,
|
||||
concise: false
|
||||
}, code);
|
||||
|
||||
console.log('\n[6] 保存文件...');
|
||||
fs.writeFileSync(outputPath, output.code);
|
||||
console.log(`保存到: ${outputPath}`);
|
||||
console.log(`新文件大小: ${(output.code.length / 1024).toFixed(2)} KB`);
|
||||
|
||||
console.log('\n✅ 完成!');
|
||||
Reference in New Issue
Block a user