文章总结: 本文详细介绍了AST语法树中template模板的高级用法,重点讲解标识符占位和语法占位(%%)两种方法在代码反混淆中的应用。通过具体代码示例展示了模板如何简化节点构造过程,并提醒注意Babel版本兼容性问题。文章还介绍了template.ast、template.statement等扩展用法,为JavaScript代码分析和安全研究提供实用技术参考。 综合评分: 85 文章分类: 代码审计,WEB安全,安全工具,安全开发,逆向分析
AST 技巧:模版(template)的高级用法
原创
LLLibra146 LLLibra146
LLLibra146
2025年5月26日 08:03 北京
在小说阅读器读本章
去阅读
大家好,今天分享一下 AST 语法树中模版(template)的高级用法。
模版的作用
模版,就是 template,一般用来快速构造节点。例如要反混淆逻辑表达式,看一个简单的示例:
const template = require("@babel/template").default;
const generator = require("@babel/generator").default;
const types = require("@babel/types");
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
ast = parser.parse('a + b && (c = d) ;');
const buildRequire = template(`
if(A){B;};
console.log(111)
`);
traverse(ast, {
LogicalExpression(path) {
let {node} = path;
path.replaceWithMultiple(buildRequire({'A': node.left, 'B': node.right}));
}
})
console.log(generator(ast).code);
运行结果:
image-20250525211058953
如果要自己构造节点的话,图中的 IfStatement 节点以及它的多个属性都要正确的构造,不仅繁琐而且很容易出错,代码可读性也很差,使用模版就很方便了。
image-20250525211332408
模版的使用
标识符占位
模版的使用有两种方法,一般情况下使用上文中的方法就足够了,使用一个标识符来占位,例如文中的 A 和 B,标识符会在构造节点的时候被替换成具体的代码。
例如:
const buildRequire = template(`
var IMPORT_NAME = require(SOURCE);
`);
const ast = buildRequire({
IMPORT_NAME: t.identifier("myModule"),
SOURCE: t.stringLiteral("my-module"),
});
//const myModule = require("my-module");
但是最近在做猿人学 2024 新春题目的时候,发现如果使用标识符占位的话,有的时候需要打印某个大写的变量,模版也会尝试替换这个变量,这样的话会报错,这个时候可以使用模版的另一种不太常见的方法。
报错例子:
ast = parser.parse('a + b && (c = d) ;');
let ddd='ddd';
const buildRequire = template(`
console.log(new URL(),A)
`);
traverse(ast, {
LogicalExpression(path) {
let {node} = path;
path.replaceWithMultiple(buildRequire({'A': node.left, 'B': node.right}));
}
})
console.log(generator(ast).code);
image-20250525230100256
语法占位
语法占位符就是使用 %% 将需要占位的字符标识出来,可以防止与其他的大写字符冲突,可以在标识符可能出现问题的地方使用。
举个例子:
const buildRequire = template(`
var %%importName%% = require(%%source%%+new URL());
`);
const ast = buildRequire({
importName: t.identifier("myModule"),
source: t.stringLiteral("my-module"),
});
console.log(generator(ast).code);
//var myModule = require("my-module" + new URL());
可以看到即使有大写字符,但是还是可以正常解析并且完成相应的功能。上面的代码仅作为示例,实际可能无法运行。
注:请注意,语法占位符是在 Babel 7.4.0 中引入的,如果使用低于此版本的 babel 可能会导致错误。
其他用法
模版还可以将组装好的代码直接解析为 AST 语法树,方便在反混淆的时候进行替换或者覆盖操作。
const name = "my-module";
const mod = "myModule";
const ast = template.ast`
var ${mod} = require("${name}");
`;
console.log(ast)
// {
// type: 'VariableDeclaration',
// kind: 'var',
// declarations: [
// {
// type: 'VariableDeclarator',
// id: [Object],
// init: [Object],
// loc: undefined
// }
// ],
// loc: undefined
// }
注:在使用 template 的时候别忘了 template 的返回值是一个函数,在进行节点替换的时候要执行函数传入可选参数才可以正常使用。
const source = "my-module";
const fn = template`
var IMPORT_NAME = require('${source}');
`;
console.log(fn)
console.log(typeof fn)
//[Function (anonymous)]
//function
template
默认情况下,根据解析的结果返回单个语句或语句数组。
template.statement
返回单个节点,如果传入的参数不是单个节点,则抛出异常。
template.statements
返回节点数组。
template.expression
返回表达式节点。
template.program
返回 Program 节点。
更多用法大家可以参考 babel 官网[1]。
总结
模版在 AST 反混淆中用的还算是比较多的,一般在可能遇到报错的地方使用语法占位符解决即可,但是切记两种方法不能混合使用,在使用的时候要注意自己使用的 babel 的版本,防止语法占位符不被支持。
参考资料
[1]
官网: https://babeljs.io/docs/babel-template
最近一直有小伙伴问我有没有交流群,为了能让大家更好的交流,我组建了一个逆向交流群,想要进群的小伙伴可以在后台点击“联系我”菜单或者扫码,添加微信并且备注“交流群”,我会拉你进群。
推荐阅读:
如何在浏览器中使用 AST 实时反混淆?(附AST模版可直接使用)
AST 使用技巧:如何快速分析混淆代码结构
在 JS逆向时如何 hook 属性?
如何 “正确” hook JS方法
无需登录,满血版DeepSeek R1,很强!
一日一技:反爬虫的极致手段,几行代码直接炸了爬虫服务器
JS调试技巧:如何让时间和随机数“听你指挥”?
【Windows版】tcpdump + wireshark 联动 frida,实现APP无感抓取HTTPS数据包
AST 技巧:还在手动扣代码?AST技术帮你自动扣代码
AST 技巧:打印控制流混淆执行路径
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:LLLibra146 LLLibra146 LLLibra146《AST 技巧:模版(template)的高级用法》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。







评论