AST使用(二)

    //在此之前,先了解下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的时候就能的得到想要的代码

AST使用(二)_第1张图片

还原过程: 

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)

你可能感兴趣的:(java,开发语言)