AST的基本使用 以及 babel使用

Ast 的基本使用

AST在线网站: https://astexplorer.net/ ,可以将正常代码通过AST在线网站进行转换为AST语法树:
在这里插入图片描述

Ast部分节点解释
  • program: 包含整个源代码,不包含注释节点。

  • type: 表示当前节点的类型

  • start:表示当前节点的起始位置

  • end:表示当前节点的末尾

  • loc:表示当前节点所在的行列位置

    • loc中的start,表示节点所在起始的行列位置

    • loc中的end,表示节点所在末尾的行列位置

  • sourceType:表示节点的源代码类型(js,python等),module表示为模块类型

  • body:表示代码块的主体部分。通过解析Ast中的body节点,可以提取出代码块的主体部分,并进行相应的处理或分析。这对于理解代码逻辑、调试和维护代码非常有用。

    • body节点通常会包含一个type的子节点,该子节点表示body代码块中包含的节点类型,常用的节点类型有:
      • ExpressionStatement:表示一个表达式语句,用于执行某些操作或计算
      • IfStatement:表示一个条件语句,根据条件执行不同的代码块。
      • ReturnStatement:表示一个return语句,用于从函数中返回一个值。
      • Identifier:表示被遍历节点的标识符
  • comments:用于存储存储源代码中的注释信息

babel介绍

在反混淆中,Babel可以通过抽象语法树(AST)来解析和转换js代码。在这个过程中,Babel首先会将源代码解析成AST,然后对AST的节点进行转换,最后将转换后的AST生成为目标代码。具体过程如下:
  1. 解析(Parsing):在这个阶段,Babel使用@babel/parser将源代码解析成AST。这一步涉及到词法分析和语法分析,最终将代码转换成AST形式。
  2. 转换(Transformation):在转换阶段,Babel对AST的节点进行遍历,并根据需要应用一系列转换操作。这些操作可以是Babel内置的,也可以是来自插件的。转换过程中可能会对节点进行添加、删除或修改等操作。
  3. 生成(Code Generation):这是Babel处理流程的最后一步,使用@babel/generator将修改后的AST转换回源代码。这个阶段生成的代码是经过转换后的版本,可以在不同的运行环境中兼容执行。

babel 环境安装

注意:配置babel时必须要有 nodejs运行环境

## 设置国内镜像

npm config set registry https://mirrors.cloud.tencent.com/npm

## 模块安装
` //Babel 编译器本身,提供了 babel 的编译 API`
npm i @babel/core --save-dev
`//判断节点类型,构建新的AST节点等`
npm i @babel/types 
`//将Javascript代码解析成AST语法树`
npm i @babel/parser 
`//遍历,修改AST语法树的各个节点`
npm i @babel/traverse 
` //将AST还原成Javascript代码`
npm i @babel/generator

Ast反混淆代码架构

//AST核心组件的导入/加载

// fs模块 用于操作文件的读写
const fs = require("fs");
// @babel/parser 用于将JavaScript代码转换为ast树
const parser = require("@babel/parser");
// @babel/traverse 用于遍历各个节点的函数
const traverse = require("@babel/traverse").default;
// @babel/types 节点的类型判断及构造等操作
const types = require("@babel/types");
// @babel/generator 将处理完毕的AST转换成JavaScript源代码
const generator = require("@babel/generator").default;
 
// 混淆的js代码文件
const encode_file = "./encode.js"
// 反混淆的js代码文件
const decode_file = "./decode.js"
 
// 读取混淆的js文件
let jsCode = fs.readFileSync(encode_file, {encoding: "utf-8"});
// 将javascript代码转换为ast树
let ast = parser.parse(jsCode)
 
// todo 编写ast插件
const visitor = {
 
}
 
// 调用插件,处理混淆的代码
traverse(ast,visitor)
 
// 将处理后的ast转换为js代码(反混淆后的代码)
let {code} = generator(ast);
// 保存代码
fs.writeFile('decode.js', code, (err)=>{});

主要需要使用的是 编写 插件,插件示例:

const visitor = {
    ExpressionStatement(path){
        console.log("ast反混淆ing......");
        console.log('当前节点对象:',path.node);
        console.log('节点对象类型:',path.type);
        console.log('节点源码:',path.toString());
    }
}

enter与exit 的 作用:
在遍历节点的过程中,实际上有两次机会来访问节点,enter表示进入节点时,exit表示退出节点时。可以在代码中编写遍历时进入要做的操作和退出时要做的操作。

const visitor = {
    ExpressionStatement:{
        enter(path,state){
            console.log('开始学习ast')
        },
        exit(){
            console.log('结束学习ast')
        }
    }
}

一个函数同时处理两个节点 : 可以把方法名用 **|** 连接起来组合成字符串的形式,这样就把同一个函数应用到多个节点

const visitor = {
    "ExpressionStatement|VariableDeclaration":{
        enter(path,state){
            console.log('开始学习ast')
        },
        exit(){
            console.log('结束学习ast')
        }
    }
}

多个函数处理一个节点:把多个函数应用于同一个节点。把函数赋值给enter或exit,将enter改为接收一个函数数组就行

//encode.js
var a = 10;
function func(){
    console.log('i am function!');
}
function f1(){
    console.log('i am f1 of function')
}
function f2(){
    console.log('i am f2 of function')
}
const visitor = {
    "FunctionDeclaration":{
        enter:[f1,f2]
    }
}
traverse(ast,visitor)

types组件

types组件,主要用于判断节点类型 ,示例如下:

//encode.js

//忽略语法错误,重点测试ast功能
var a = 10;
function a(a,num2){
    return a + num2;
};
console.log(a());
const visitor = {
    enter(path){
        //在js代码中定位到所有标识符为a(变量名为a、函数名为a等)的节点,将其名字改为b
        if(types.isIdentifier(path.node,{"name":"a"})){
            path.node.name = "b";
        }
    }
}
// 调用插件,处理js代码
traverse(ast,visitor)

替换节点属性值

示例:

通过types组件将节点中的属性值替换为指定的属性值
示例:将当前VariableDeclarator节点下的init下的value属性的属性值替换为 123123

在这里插入图片描述

// todo 编写ast插件
const visitor = {
    VariableDeclarator(path){
        //修改为数字类型
        path.node.init = types.numericLiteral(123123)
    }
}

替换节点

replaceWith:该方法是节点替换节点。例如:将所有数字型变量值全部修改为123321

数字变量的节点类型NumericLiteral。
在这里插入图片描述

// todo 编写ast插件
const visitor = {
    NumericLiteral(path){
        //修改为字符串类型	
        path.replaceWith(types.valueToNode("123321"))
    }
}
/*
* 替换后的代码:
    var a = "123321";
    var b = "123321";
* */
traverse(ast,visitor)

replaceWithSourceString:该方法是用字符串源码替换节点。例如:将123替换为一个函数
在这里插入图片描述

// todo 编写ast插件
const visitor = {
    NumericLiteral(path){
        path.replaceWithSourceString(`function add(a,b){return a + b}`)
    }
}
traverse(ast,visitor)
/*
* 替换结果:
var a = function add(a, b) {
  return a + b;
};
* */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值