AST使用(二)

news2024/11/25 20:11:51
    //在此之前,先了解下path和node
    /*
    path指的是路径  其常用的方法
    当前路径所对应的源代码 : path.toString
    判断path是什么type,使用path.isXXX 这个方法  : if(path.isStringLiteral()){}
    获取path的上一级路径 : let parent = path.parentPath;
    获取path的子路径 : path.get('test');
    删除path : path.remove()
    替换path(一个节点) : path.replaceWith({type:"NumericLiteral",value:3});
    替换path(多个节点) : path.replaceWithMultiple([{type:"NumericLiteral",value:3}]);
    插入path : path.insertAfter({type:"NumericLiteral",value:3}); 
    
    node指的是节点  是path的一个属性 可以通过path.node来获取node  本质是一个json结果的数据
    获取原码 :
        const generator = require("@babel/generator").default;
        let {code} = generator(node);
    删除节点 : path.node.init = undefined;
    访问子节点的值(init节点的value属性) : console.log(path.node.init.value);
    节点的类型判断 : 先引入types  if(types.isBlockStatement(path.node)){}

    path和node关系: node是path的一个属性
    举例: path.node.test === path.get("test").node  结果是True
     */

1.表达式还原

 js文件内容:

const a = !![]
const b = "abc" == "dsa";
const c = (1 << 2) | 2;
const d = parseInt("5" + "0")

还原代码:

import { parse } from "@babel/parser";
import traverse from "@babel/traverse";
import generate from "@babel/generator";
import * as types from "@babel/types";
import fs from "fs";
const code = fs.readFileSync("code/表达式还原.js","utf-8");
let ast = parse(code);
traverse(ast,{
    //下面对应的是一元表达式、二元表达式、条件表达式、调用表达式
    "UnaryExpression|BinaryExpression|ConditionalExpression|CallExpression" : (
        path
    ) => {
        //执行path对应的语句,并将结果中的value属性赋值给value变量,将confident属性赋值给confident变量
        //confident 是可信度  value是计算结果
        const { confident , value } = path.evaluate();
        //如果表达式计算的结果是正负无穷大,则return不做任何处理
        if (value == Infinity || value == -Infinity)return
        if (confident){
            //如果结果可信,将结果转换为节点替换当前节点
            path.replaceWith(types.valueToNode(value));
        }
    }
});
const{ code: output } = generate(ast);
console.log(output)

2.字符串还原

const strings = ["\x68\x65\x6c\x6c\x6f","\x77\x6f\x72\x6c\x64"]

将这段js代码解混淆如下,可以看出如果我们将raw的值变为正常,那么还原ast的时候就能的得到想要的代码

还原过程: 

import { parse } from "@babel/parser";
import traverse from "@babel/traverse";
import generate from "@babel/generator";
import * as types from "@babel/types";
import fs from "fs";
const code = fs.readFileSync("code/表达式还原.js","utf-8");
let ast = parse(code);
traverse(ast,{
    //此处的{ node } 写法就等价于 { node } = path  等价于 node = path.node
    StringLiteral({ node }){
        //    /正则内容/gi.test(要匹配的字符串)    这个写法是JS中正则的写法,返回值是布尔值  详情可见https://www.runoob.com/jsref/jsref-obj-regexp.html
        if (node.extra && /\\[ux]/gi.test(node.extra.raw)){
            node.extra.raw = node.extra.rawValue;
        }
    },
});
const{ code: output } = generate(ast);
console.log(output)

3.无用代码剔除(僵尸代码)

如下代码,第一个条件结果永远是true,第二个条件结果永远是false,所以可以通过判断IfStatement节点下的test节点的计算结果,来显示代码,其中if 下的条件对应的是consequent,else内的代码对应的是alternate

const _0x16c18d = function(){
    if(!![[]]){
        console.log("hello,world")
    }else{
        console.log("1111")
        console.log("2222")
        console.log("3333")
        console.log("4444")
    }
};
const _0x1f7292 = function (){
    if ("dhsanhdu7dsa8".charAt(4) !== String.fromCharCode(110)){
        console.log("this")
        console.log("is")
        console.log("dead")
        console.log("code")
    }else {
        console.log("nice to meet you")
    }
};
_0x16c18d();
_0x1f7292();
import { parse } from "@babel/parser";
import traverse from "@babel/traverse";
import generate from "@babel/generator";
import * as types from "@babel/types";
import fs from "fs";
const code = fs.readFileSync("code/表达式还原.js","utf-8");
let ast = parse(code);
traverse(ast,{
    IfStatement(path){
        let result = path.get("test").evaluateTruthy(); //计算test路径下代码的结果是否为真  返回布尔值
        let consequent = path.get("consequent")
        let alternate = path.get("alternate")
        if (result === true){
            if (consequent.isBlockStatement()){
                path.replaceWith(consequent.node)
            }
        }else if(result === false){
            if (alternate.isBlockStatement()){
                path.replaceWith(alternate.node)
            }
        }else{
            path.remove()
        }
    }
});
const{ code: output } = generate(ast);
console.log(output)

4.反控制流平坦化

原代码:

const s = "3|1|2".split("|");
let x = 0;
while (true){
    switch (s[x++]){
        case "1":
            const a = 1;
            continue;
        case "2":
            const b = 3;
            continue;
        case "3":
            const c = 0;
            continue;
    }
    break;
}
import { parse } from "@babel/parser";
import traverse from "@babel/traverse";
import generate from "@babel/generator";
import * as types from "@babel/types";
import fs from "fs";
const code = fs.readFileSync("code/表达式还原.js","utf-8");
let ast = parse(code);
traverse(ast,{

    //反控制流平坦化
    WhileStatement(path){
      const { node,scope } = path;
      const { test,body } = node;
      let switchNode = body.body[0];
      let { discriminant,cases } = switchNode;
      let { object,property } = discriminant;
      let arrName = object.name;
      let binding = scope.getBinding(arrName);
      let { init } = binding.path.node;

      object = init.callee.object;
      property = init.callee.property;
      let argument = init.arguments[0].value;
      let arrayFlow = object.value[property.name](argument);

        // console.log(object.value[property.name])
        // console.log(argument)
        // console.log(arrayFlow)
      let resultBody = [];
      arrayFlow.forEach((index)=> {
          let switchCase = cases.filter((c) => c.test.value == index)[0];
          let caseBody = switchCase.consequent;
          if (types.isContinueStatement(caseBody[caseBody.length - 1])) {
              caseBody.pop();
          }
          resultBody = resultBody.concat(caseBody);
      });
      path.replaceWithMultiple(resultBody);
    },

});
const{ code: output } = generate(ast);
console.log(output)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/647421.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

nginx的安装及代理和负载均衡设置

一、通过yum方式进行安装 官网参考地址&#xff1a;https://nginx.org/en/linux_packages.html#RHEL 1.1 安装好依赖 执行下面的命令安装 sudo yum install yum-utils1.2、 先配置好yum源 新建文件/etc/yum.repos.d/nginx.repo&#xff0c;文件内容&#xff1a; [nginx-s…

一个成熟的软件测试工程师应该具备那些“技能”

1、良好的沟通 相信大家都在网上看到过各种吐槽程序员不解风情的段子&#xff0c;开怀大笑之余深思&#xff0c;作为一个测试工程师又何尝不是如此&#xff1f;通常沟通技能成为横亘在测试工程师与其他合作部门之间的万丈鸿沟&#xff0c;也成为测试工程师成长的最大瓶颈。下面…

Vector-常用CAN工具 - 以太网报文收发方向

目录 Rx 和 Tx 标记 Example&#xff1a;从 CANoe 向 ECU 发送以太网数据包 用例 2&#xff1a;从 ECU 接收以太网数据包 如何仅显示物理或虚拟通信 如何仅显示 Rx 或 Tx 以太网数据包 VN5000以太网包过滤 1、什么是硬件过滤&#xff1f; 2、什么时候使用硬件过滤&…

useEffect,useLayoutEffect的基础知识和底层机制

useEffect 是 React 中一个重要的 Hook&#xff0c;用来处理组件的副作用操作。它的基础知识包括两个方面&#xff1a;执行时机和参数。 执行时机&#xff1a; useEff ect 的执行时机包括两种情况&#xff1a; 组件挂载时&#xff0c;即第一次渲染之后。组件更新时&#xff…

智能垃圾分类小程序,流量主变现,外卖cps权益变现,uniCloud云开发无需购买服务器和域名,助力每一位创业者。

技术优势 基于 uniapp uniCloud 研发&#xff0c;无需购买服务器和域名&#xff0c;uniCloud 是 DCloud 联合阿里云、腾讯云 serverless 构建。从此不用关心服务器运维、弹性扩容、大并发承载、防DDoS攻击等&#xff0c;轻松应对高并发应用&#xff0c; 传统小程序开通流量主…

Qt 多语言实现

简介 Qt Linguist 提供了一套加速应用程序翻译和国际化的工具。Qt 使用单一的源码树和单一的应用程序二进制包就可同时支持多个语言和书写系统。 使用 QTranslator 来加载生成的 qm 文件&#xff0c;就可以让程序显示指定的语言。 // 国际化翻译 QString language "CH…

项目Es、kafka、mysql容量评估方案和服务器资源预估方案

目录 1、Es 评估计划 一个接口jmeter压测qps 1万, logstash 读取日志文件写入es Logstash配置 Es容量变化前后差值/1万 * 1.67 * &#xff08;1副本数&#xff09; ~ 次接口es 容量 &#xff08;日志数据30kb&#xff09; 影响es存储的主要原因 通过 kibana 查看 堆栈》索…

管理类联考——英语——技巧篇——阅读理解

一、阅读理解A节选项的点 1.正确答案的五大特征 (1)“主题为王”原则&#xff1a;即正确答案通常与文章的中心思想、主旨大意有关。 (2)正确答案的特点&#xff1a;语言简化、反话正说、正话反说、关键词替换。 (3)正确答案要选相对的&#xff0c;不选绝对的。正确答案通常含有…

编译原理期末速成-LL(1)文法、FIRST集、FOLLOW集

文章目录 LL(1)文法的条件LL(1)分析法构造FIRST(α)构造FOLLOW(A)习题强化 LL(1)文法的条件 文法不含左递归 对于文法中每一个非终结符A的各个产生式的候选首符集两两不相交。即若 对于文法中的每个非终结符A&#xff0c;若它存在某个候选首符集包含ε&#xff0c;则 这里&am…

面试被问到:测试计划和测试方案有什么区别?

面试的时候&#xff0c;很多小伙伴都被面试官问过这个问题 “测试计划和测试方案有什么区别”&#xff1f; 到底有什么区别呢&#xff1f;我们先好好了解下这两个文档。 一、测试计划 1、测试计划是什么&#xff1f; 测试计划是组织管理层面的文件&#xff0c;从组织管理的…

Jetpack Compose 中使用 CameraX 拍照和录制视频

在 Android 开发的历史中&#xff0c;Camera 的 API 是一直受人诟病的&#xff0c;使用过的人都知道&#xff0c;直观的感觉就是配置复杂、臃肿、难用、不易理解&#xff0c;从官方关于 Camera 的 API 迭代路线可以看出官方也在尝试着不断改进开发者关于Camera的使用体验&#…

ChatGPT编程

ChatGPT问答 问题一&#xff1a;如何合理分配时间问题二&#xff1a;以下是提高工作效率的建议&#xff1a;问题三&#xff1a;如何培养兴趣问题四&#xff1a;软件和硬件谁重要问题五: 设计模式如何熟练运用问题六:C语言编程冒泡排序 问题一&#xff1a;如何合理分配时间 这里…

Java实训第八天——2023.6.14

文章目录 一、vue的环境搭建&#xff1a;二、文本数据绑定三、属性数据绑定四、事件绑定五、案例1——全选/全不选六、案例2——切换图片主要内容&#xff1a; v-if 、v-show指令 七、表单数据绑定八、综合练习总结步骤&#xff1a; 一、vue的环境搭建&#xff1a; 官方文档&a…

Mysql数据库中的约束、用户管理与授权

文章目录 一、Mysql中常见的约束总结 二、数据表高级操作2.1克隆表&#xff0c;将数据表的数据记录生成到新的表中2.2清空表&#xff0c;删除表内的所有数据2.3创建临时表2.4创建外键约束&#xff0c;保证数据的完整性和一致性。 三、数据库用户管理3.1新建用户3.2查看用户信息…

《设计模式》之适配器模式

文章目录 1、定义2、动机3、应用场景4、类结构5、优缺点6、总结7、代码实现(C) 1、定义 把一个类的接口转换成客户端所期待的另一种接口&#xff0c;从而使原接口不匹配而无法再一起工作的两个类能在一起工作。 2、动机 在软件系统中&#xff0c;由于应用环境的变化&#xf…

Spring源码解密--事务篇

文章目录 一、事务的实现方式1、JDBC2、Spring基于xml配置编程式事务声明式事务 二、源码设计1、TransactionManager1&#xff09;TransactionManager2&#xff09;PlatformTransactionManager3&#xff09;ReactiveTransactionManager 2、TransactionDefinition3、Transaction…

压缩感知入门——基于总体最小二乘的扰动压缩感知

压缩感知系列博客&#xff1a;压缩感知入门①从零开始压缩感知压缩感知入门②信号的稀疏表示和约束等距性压缩感知入门③基于ADMM的全变分正则化的压缩感知重构算法 文章目录 1. Problem2. 仿真结果3. MATLAB算法4. 源码地址参考文献 1. Problem 一个经典的压缩感知重构问题可以…

Git的原理与使用

背景知识&#xff1a; 我们在编写各种文档时&#xff0c;为了防止文档丢失&#xff0c;更改失误&#xff0c;失误后能恢复到原来的版本&#xff0c;不得不复制出一个副本。每个版本有各自的内容&#xff0c;但最终会只有一份报告需要被我们使用 。但在此之前的工作都需要这些不…

day10_类中成员之变量

通过以前的学习&#xff0c;我们知道了成员变量是类的重要组成部分。对象的属性以变量形式存在&#xff0c;下面我们就来详解的学习一下类中的变量 成员变量 成员变量的分类 实例变量&#xff1a;没有static修饰&#xff0c;也叫对象属性&#xff0c;属于某个对象的&#xf…

9k字长文理解Transformer: Attention Is All You Need

作者&#xff1a;猛码Memmat 目录 Abstract1 Introduction2 Background3 Model Architecture3.1 Encoder and Decoder Stacks3.2 Attention3.2.1 Scaled Dot-Product Attention3.2.2 Multi-Head Attention3.2.3 Applications of Attention in our Model 3.3 Position-wise Feed…