最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
怎样通过静态分析 AST 手动实现一个简单的 JavaScript 关键词混淆工具
时间:2026-07-27 09:56:54 编辑:袖梨 来源:一聚教程网
直接替换变量名会出错,因正则无法区分作用域和语义,而AST能精准识别Identifier节点并仅混淆局部变量和参数,跳过属性名、内置方法、全局变量等。
为什么直接替换变量名会出错
手动遍历字符串做正则替换,var a = 1; console.log(a); 中的 a 会被替换成新名字,但 console.log 里的 log 也可能被误伤——因为正则不区分作用域和语义。AST 能精准识别 Identifier 节点,并判断它是否为可混淆的局部变量或函数参数,跳过属性名、内置方法、全局变量等。
用 @babel/parser 解析并遍历 AST 的关键步骤
不用写词法分析器,Babel 提供了稳定、兼容性好的解析能力。重点不是“怎么生成 AST”,而是“怎么安全标记和替换”:
- 只处理
VariableDeclarator(如let x = 1中的x)和FunctionDeclaration/ArrowFunctionExpression的参数节点 - 跳过
MemberExpression中的property(如obj.name的name),否则会破坏对象访问 - 用
scope.bindings判断标识符是否为局部绑定(Babel 的scope对象在遍历时自动可用) - 避免混淆
this、arguments、super等上下文关键字,它们不是普通Identifier
示例节选(Babel 插件写法):
export default function({ types: t }) { return { visitor: { Identifier(path) { const { node, scope } = path; if (node.name === 'this' || node.name === 'arguments') return; if (!scope.hasBinding(node.name)) return; // 不是当前作用域声明的,不碰 if (scope.getBinding(node.name).kind !== 'let' && scope.getBinding(node.name).kind !== 'const' && scope.getBinding(node.name).kind !== 'var') return; // 此处生成新名字,如 'a' → '_0x1a2b' path.replaceWith(t.identifier('_0x1a2b')); } } };}
scope.hasBinding() 和 scope.getBinding() 的实际差异
前者只是快速判断名字是否存在绑定,后者返回完整绑定对象,含 kind(var/let/const/param)、referencePaths(所有引用位置)、path(声明节点)。混淆时必须用 getBinding(),否则无法区分 let x 和 obj.x ——两者都通过 hasBinding('x') 返回 false,但后者根本不在作用域中。
立即学习“Java免费学习笔记(深入)”;
-
scope.hasBinding('x')在function f(x) { let x = 2; }中对第一个x(参数)返回true,对第二个也返回true,但它们属于不同绑定 - 真正要替换的是绑定对象本身,所以必须用
scope.getBinding('x')获取其声明路径,再决定是否重命名 - 注意:参数绑定的
kind是'param',不是'let',漏判会导致函数参数没被混淆
混淆后代码执行失败的三个高频原因
不是 AST 没走通,而是语义被破坏:
- 把
class A { method() {} }中的method当作可混淆标识符——其实它是MethodDefinition的key,不是Identifier节点;需额外处理ObjectMethod和ClassMethod的key属性,且仅当key.type === 'Identifier'且非计算属性时才考虑 - 混淆了
import { foo } from './x'中的foo,导致模块导入失效——ESM 的导入绑定是只读的,不能重命名;应跳过所有ImportSpecifier和ExportSpecifier中的local和exported - 用固定映射表(如
{x: '_a', y: '_b'})混淆,但没做作用域隔离,导致嵌套函数内同名变量被统一替换,破坏闭包逻辑;必须为每个Scope实例维护独立的映射缓存
最易被忽略的是 this 绑定上下文:箭头函数里写的 this 不是标识符,但若混淆了外层函数名,可能让调试时的调用栈完全不可读——混淆工具不该动函数名,除非明确支持 functionName 选项并默认关闭。
相关文章
- 斑马英语APP课程购买记录怎么管理 07-27
- 豆包图片如何生成 07-27
- HMCL启动器怎样用微软登录 07-27
- 高性价比旅行app哪个好用 便宜旅行app有哪些 07-27
- 十大优质买房平台app排行榜 好用的买房平台app大全 07-27
- 便宜的卖房app十大排行榜盘点 性价比高的卖房app十大排行榜有哪些 07-27