首先我们得知道为什么要了解AST
大家都知道反爬虫中JS
是最难的,要想破解JS
逆向,就必须要掌握AST
语法,目前常用的一些前端插件或者工具 比如:javascript
转译,代码压缩,css
预处理器,elint,pretiier
等功能的实现都是简历在AST
的基础之上。
javascript 的编译执行流程
js执行的第一步是读取js
文件中的字符流,然后通过词法分析生成token
,之后再通过语法分析生成 AST(Abstract Syntax Tree)
,最后生成机器码执行。
语法分析
语法分析同时也称之为扫描(scanner)
,简单的来说就是调用next()
方法,一个一个字母的来读取字符,然后和定义好的的Javascript
关键字符做比较生成对应的Token
。不可分割的最小单元,例如 var
这三个字符,它只能作为一个整体,语义上不能再被分解,因此它是一个 Token
。词法分析器里,每个关键字是一个Token
,每个标识符是一个Token
,每个操作符是一个 Token
,每个标点符号也都是一个 Token
。除此之外,还会过滤掉源程序中的注释和空白字符(换行符、空格、制表符等)。
最终,整个代码将被分割进一个tokens
列表(或者说一维数组)。
n * n;
[
{
type: {
... }, value: "n", loc: {
... } },
{
type: {
... }, value: "*", loc: {
... } },
{
type: {
... }, value: "n", loc: {
... } },
...
]
每一个type
有一组属性来描述该令牌:
{
type: {
label: 'name',
keyword: undefined,
beforeExpr: false,
startsExpr: true,
rightAssociative: false,
isLoop: false,
isAssign: false,
prefix: false,
postfix: false,
binop: null,
updateContext: null
},
...
}
语法分析
语法分析会将词法分析出来的 Token
转化成有语法含义的抽象语法树结构。同时,验证语法,语法如果有错的话,抛出语法错误。
什么是AST(抽象语法树)
抽象语法树(Abstract Syntax Tree,AST)
,或简称语法树(Syntax tree)
,是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。
function square(n) {
return n * n;
}
上面这个代码就可以形成一棵树:
FunctionDeclaration:
id:
Identifier:
name: square
params [1]
Identifier
name: n
body:
BlockStatement
body [1]
ReturnStatement
argument
BinaryExpression
operator: *
left
Identifier
name: n
right
Identifier
name: n
或是如下所示的 JavaScript Object
(对象):
{
type: "FunctionDeclaration",
id: {
type: "Identifier",
name: "square"
},
params: [{
type: "Identifier",
name: "n"
}],
body: {
type: "BlockStatement",
body: [{
type: "ReturnStatement",
argument: {
type: "BinaryExpression",
operator: "*",
left: {
type: "Identifier",
name: "n"
},
right: {
type: "Identifier",
name: "n"
}
}
}]
}
}
你会留意到 AST
的每一层都拥有相同的结构:
{
type: "FunctionDeclaration",
id: {
...},
params: [...],
body: {
...}
}
{
type: "Identifier",
name: ...
}
{
type: "BinaryExpression",
operator: ...,
left: {
...},
right: {
...}