141 lines
4.3 KiB
JavaScript
141 lines
4.3 KiB
JavaScript
/**
|
|
* 最终清理
|
|
* 移除未使用的变量和无意义的表达式
|
|
*/
|
|
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_final.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 removedExpr = 0;
|
|
|
|
traverse(ast, {
|
|
ExpressionStatement(path) {
|
|
const expr = path.node.expression;
|
|
|
|
// 移除纯数字表达式 (如 0x0;)
|
|
if (t.isNumericLiteral(expr)) {
|
|
path.remove();
|
|
removedExpr++;
|
|
return;
|
|
}
|
|
|
|
// 移除纯字符串表达式 (非 'use strict')
|
|
if (t.isStringLiteral(expr) && expr.value !== 'use strict') {
|
|
path.remove();
|
|
removedExpr++;
|
|
return;
|
|
}
|
|
}
|
|
});
|
|
|
|
console.log(`移除了 ${removedExpr} 个无意义表达式`);
|
|
|
|
console.log('\n[3] 移除未使用的变量...');
|
|
let removedVars = 0;
|
|
|
|
// 多次遍历以处理嵌套引用
|
|
for (let pass = 0; pass < 3; pass++) {
|
|
traverse(ast, {
|
|
VariableDeclarator(path) {
|
|
if (!t.isIdentifier(path.node.id)) return;
|
|
const name = path.node.id.name;
|
|
|
|
const binding = path.scope.getBinding(name);
|
|
if (binding && binding.references === 0) {
|
|
// 不移除以 __ 开头的模块辅助函数
|
|
if (name.startsWith('__')) return;
|
|
|
|
path.remove();
|
|
removedVars++;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
console.log(`移除了 ${removedVars} 个未使用变量`);
|
|
|
|
console.log('\n[4] 移除空的变量声明...');
|
|
let removedEmpty = 0;
|
|
|
|
traverse(ast, {
|
|
VariableDeclaration(path) {
|
|
if (path.node.declarations.length === 0) {
|
|
path.remove();
|
|
removedEmpty++;
|
|
}
|
|
}
|
|
});
|
|
|
|
console.log(`移除了 ${removedEmpty} 个空声明`);
|
|
|
|
console.log('\n[5] 简化十六进制数字...');
|
|
let convertedNums = 0;
|
|
|
|
traverse(ast, {
|
|
NumericLiteral(path) {
|
|
// 将 0x0 转为 0
|
|
if (path.node.extra && path.node.extra.raw && path.node.extra.raw.startsWith('0x')) {
|
|
delete path.node.extra;
|
|
convertedNums++;
|
|
}
|
|
}
|
|
});
|
|
|
|
console.log(`转换了 ${convertedNums} 个十六进制数字`);
|
|
|
|
console.log('\n[6] 生成代码...');
|
|
const output = generate(ast, {
|
|
comments: false,
|
|
compact: false,
|
|
concise: false
|
|
}, code);
|
|
|
|
// 后处理:清理双引号属性
|
|
let finalCode = output.code;
|
|
|
|
// 清理 obj["prop"] -> obj.prop (对于有效标识符)
|
|
finalCode = finalCode.replace(/\["([a-zA-Z_$][a-zA-Z0-9_$]*)"\]/g, '.$1');
|
|
|
|
// 清理对象字面量中的引号 'key': -> key:
|
|
finalCode = finalCode.replace(/'(enumerable|value|get|writable|configurable)':/g, '$1:');
|
|
|
|
console.log('\n[7] 保存文件...');
|
|
fs.writeFileSync(outputPath, finalCode);
|
|
console.log(`保存到: ${outputPath}`);
|
|
console.log(`新文件大小: ${(finalCode.length / 1024).toFixed(2)} KB`);
|
|
|
|
// 统计
|
|
console.log('\n=== 最终统计 ===');
|
|
const remaining0x = (finalCode.match(/_0x[a-f0-9]+/gi) || []).length;
|
|
const remainingSwitch = (finalCode.match(/switch\s*\([^)]*\[/g) || []).length;
|
|
console.log(`剩余 _0x 模式: ${remaining0x}`);
|
|
console.log(`剩余数组 switch: ${remainingSwitch}`);
|
|
|
|
console.log('\n✅ 完成!');
|