AST抽象语法树及如何转JS代码:
AST抽象语法树及如何转JS代码:
资料来源:
https://www.cnblogs.com/goloving/p/14078228.html
抽象语法树(Abstract Syntax Tree)也称为AST语法树,指的是源代码语法所对应的树状结构。也就是说,对于一种具体编程语言下的源代码,通过构建语法树的形式将源代码中的语句映射到树中的每一个节
点上。
在编译完成语法分析后生成。
作用是:
聊到AST
的用途,其应用非常广泛,下面我简单罗列了一些:
IDE
的错误提示、代码格式化、代码高亮、代码自动补全等JSLint
、JSHint
对代码错误或风格的检查等webpack
、rollup
进行代码打包等CoffeeScript
、TypeScript
、JSX
等转化为原生Javascript
其实它的用途,还不止这些,如果说你已经不满足于实现枯燥的业务功能,想写出类似react
、vue
这样的牛逼框架,或者想自己搞一套类似webpack
、rollup
这样的前端自动化打包工具,那你就必须弄懂AST
。
抽象语法树的作用非常的多,比如编译器、IDE、压缩优化代码等。在JavaScript中,虽然我们并不会常常与AST直接打交道,但却也会经常的涉及到它。例如使用UglifyJS来压缩代码,实际这背后就是在对JavaScript的抽象语法树进行操作。 在一些实际开发过程中,我们也会用到抽象语法树,下面通过一个小例子来看看怎么进行JavaScript的语法解析以及对节点的遍历与操纵。
AST转JS代码:
需要安装@babel/generator
npm install @babel/generator
npm install @babel/generator estree-to-babel
这样只能在安装文件夹里生效
符合ESTree AST规范的:
const { default: generate } = require('@babel/generator');
const estreeToBabel = require('estree-to-babel');
// 加载 ESTree 格式的 AST
const estreeAST = require('./2.json'); // 替换为你的 JSON 路径
// 转换 ESTree AST → Babel AST
const babelAST = estreeToBabel(estreeAST);
// 生成 JavaScript 代码
const { code } = generate(babelAST, {
quotes: 'single', // 统一使用单引号
decoratorsBeforeExport: true // 适配 ES6+ 语法
});
console.log(code);
符合babel规范的
const generate = require('@babel/generator').default;
// 从 JSON 加载 AST
const astJson = require('./ast.json');
// 转换为代码(自动处理缩进、分号等格式)
const { code } = generate(astJson, {
retainLines: false,
compact: false,
quotes: 'double'
});
console.log(code);
例题:
[SWPUCTF 2021 新生赛]astJS
{
"type": "Program",
"start": 0,
"end": 233,
"body": [
{
"type": "ExpressionStatement",
"start": 0,
"end": 233,
"expression": {
"type": "CallExpression",
"start": 0,
"end": 232,
"callee": {
"type": "FunctionExpression",
"start": 1,
"end": 229,
"id": null,
"expression": false,
"generator": false,
"async": false,
"params": [],
"body": {
"type": "BlockStatement",
"start": 13,
"end": 229,
"body": [
{
"type": "FunctionDeclaration",
"start": 18,
"end": 177,
"id": {
"type": "Identifier",
"start": 27,
"end": 29,
"name": "bE"
},
"expression": false,
"generator": false,
"async": false,
"params": [
{
"type": "Identifier",
"start": 30,
"end": 33,
"name": "str"
},
{
"type": "Identifier",
"start": 34,
"end": 37,
"name": "key"
}
],
"body": {
"type": "BlockStatement",
"start": 38,
"end": 177,
"body": [
{
"type": "VariableDeclaration",
"start": 46,
"end": 70,
"declarations": [
{
"type": "VariableDeclarator",
"start": 50,
"end": 69,
"id": {
"type": "Identifier",
"start": 50,
"end": 53,
"name": "arr"
},
"init": {
"type": "CallExpression",
"start": 56,
"end": 69,
"callee": {
"type": "MemberExpression",
"start": 56,
"end": 65,
"object": {
"type": "Identifier",
"start": 56,
"end": 59,
"name": "str"
},
"property": {
"type": "Identifier",
"start": 60,
"end": 65,
"name": "split"
},
"computed": false,
"optional": false
},
"arguments": [
{
"type": "Literal",
"start": 66,
"end": 68,
"value": "",
"raw": "''"
}
],
"optional": false
}
}
],
"kind": "var"
},
{
"type": "ReturnStatement",
"start": 77,
"end": 171,
"argument": {
"type": "CallExpression",
"start": 84,
"end": 171,
"callee": {
"type": "MemberExpression",
"start": 84,
"end": 167,
"object": {
"type": "CallExpression",
"start": 84,
"end": 162,
"callee": {
"type": "MemberExpression",
"start": 84,
"end": 91,
"object": {
"type": "Identifier",
"start": 84,
"end": 87,
"name": "arr"
},
"property": {
"type": "Identifier",
"start": 88,
"end": 91,
"name": "map"
},
"computed": false,
"optional": false
},
"arguments": [
{
"type": "ArrowFunctionExpression",
"start": 92,
"end": 161,
"id": null,
"expression": false,
"generator": false,
"async": false,
"params": [
{
"type": "Identifier",
"start": 93,
"end": 94,
"name": "i"
}
],
"body": {
"type": "BlockStatement",
"start": 97,
"end": 161,
"body": [
{
"type": "ReturnStatement",
"start": 107,
"end": 153,
"argument": {
"type": "CallExpression",
"start": 114,
"end": 153,
"callee": {
"type": "MemberExpression",
"start": 114,
"end": 133,
"object": {
"type": "Identifier",
"start": 114,
"end": 120,
"name": "String"
},
"property": {
"type": "Identifier",
"start": 121,
"end": 133,
"name": "fromCharCode"
},
"computed": false,
"optional": false
},
"arguments": [
{
"type": "BinaryExpression",
"start": 134,
"end": 152,
"left": {
"type": "CallExpression",
"start": 134,
"end": 148,
"callee": {
"type": "MemberExpression",
"start": 134,
"end": 146,
"object": {
"type": "Identifier",
"start": 134,
"end": 135,
"name": "i"
},
"property": {
"type": "Identifier",
"start": 136,
"end": 146,
"name": "charCodeAt"
},
"computed": false,
"optional": false
},
"arguments": [],
"optional": false
},
"operator": "^",
"right": {
"type": "Identifier",
"start": 149,
"end": 152,
"name": "key"
}
}
],
"optional": false
}
}
]
}
}
],
"optional": false
},
"property": {
"type": "Identifier",
"start": 163,
"end": 167,
"name": "join"
},
"computed": false,
"optional": false
},
"arguments": [
{
"type": "Literal",
"start": 168,
"end": 170,
"value": "",
"raw": "''"
}
],
"optional": false
}
}
]
}
},
{
"type": "ExpressionStatement",
"start": 181,
"end": 227,
"expression": {
"type": "CallExpression",
"start": 181,
"end": 227,
"callee": {
"type": "MemberExpression",
"start": 181,
"end": 192,
"object": {
"type": "Identifier",
"start": 181,
"end": 188,
"name": "console"
},
"property": {
"type": "Identifier",
"start": 189,
"end": 192,
"name": "log"
},
"computed": false,
"optional": false
},
"arguments": [
{
"type": "CallExpression",
"start": 193,
"end": 226,
"callee": {
"type": "Identifier",
"start": 193,
"end": 195,
"name": "bE"
},
"arguments": [
{
"type": "Literal",
"start": 196,
"end": 222,
"value": "EXXH_MpjxBxYnjggrM~eerv",
"raw": "'EXXH_MpjxBxYnjggrM~eerv'"
},
{
"type": "Literal",
"start": 223,
"end": 225,
"value": 11,
"raw": "11"
}
],
"optional": false
}
],
"optional": false
}
}
]
}
},
"arguments": [],
"optional": false
}
}
],
"sourceType": "module"
}
WP:
exp:
const { default: generate } = require('@babel/generator');
const estreeToBabel = require('estree-to-babel');
// 加载 ESTree 格式的 AST
const estreeAST = require('./2.json'); // 替换为你的 JSON 路径
// 转换 ESTree AST → Babel AST
const babelAST = estreeToBabel(estreeAST);
// 生成 JavaScript 代码
const { code } = generate(babelAST, {
quotes: 'single', // 统一使用单引号
decoratorsBeforeExport: true // 适配 ES6+ 语法
});
console.log(code);
输出:
(function () {
function bE(str, key) {
var arr = str.split("");
return arr.map(i => {
return String.fromCharCode(i.charCodeAt() ^ key);
}).join("");
}
console.log(bE("EXXH_Mpjx\x7FBxYnjggrM~eerv", 11));
})();
直接运行即可得到flag:
NSSCTF{astIsReallyFunny}
本文来自博客园,作者:漫宿骄盛,转载请注明原文链接:https://www.cnblogs.com/msjs/p/18784746
都是顺手发的,写的时候可能有错误,如果发现了,望各位指出。