QingYi. 发表于 2022-5-20 11:24

Ast入门使用

本帖最后由 QingYi. 于 2022-5-20 11:42 编辑

前置条件:

1.一台可以用的电脑
2.双手和大脑
3.JavaScript语法基础


环境:

1.node
2.Pycharm编译器

正文:

1.改变对象属性的访问方式

编写一个简单的加法
方法一:


方法二:



可以看到两种方法都是可以的.

```
function add(a,b){
let res = a + b;
return res;

}
console['log'](add(5,6));
```




来到这个网址

我们可以看到点出来的log的两个属性分别是Identifier 和 false


再来看[]形式的,注意看黄色部分


来编写ast转换代码,以获取当前时间为例


```
Date.prototype.format = function (formatStr) {
    var str = formatStr;
    var Week = ['日', '一', '二', '三', '四', '五', '六'];
    str = str.replace(/yyyy|YYYY/, this.getFullYear());
    str = str.replace(/MM/, (this.getMonth() + 1) > 9 ? (this.getMonth() + 1).toString() : '0' + (this.getMonth() + 1));
    str = str.replace(/dd|DD/, this.getDate() > 9 ? this.getDate().toString() : '0' + this.getDate());
    return str;
}
console.log(new Date().format('yyyy-MM-dd'));
```

astcode

执行之后

正常运行


2.JS内置对象的处理
例如这个window可以处理一下



astCode and result


3.常量与标识符的混淆
一个简单的位运算,不懂的看console

result


进行base64转换


也可以把这些常量放到一个数组里面提取出来


对其进行十六进制的混淆


标识符的混淆,也就是作用域有引用的,第五行就没有引用到

我们要找到代码的作用域

生成随机o0O代码



```
function generatorIdentifier(decNum){
      let flag = ['O', 'o', '0'];
      let retval = [];
      while(decNum > 0){
                retval.push(decNum % 3);
                decNum = parseInt(decNum / 3);
      }
      let Identifier = retval.reverse().map(function(v){
                return flag
      }).join('');
      Identifier.length < 6 ? (Identifier = ('OOOOOO' + Identifier).substr(-6)):
      Identifier == '0' && (Identifier = 'O' + Identifier);
      return Identifier;
}
```

全部代码
```
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const types = require("@babel/types");
const generator = require("@babel/generator").default;
const fs = require('fs');

function base64Encode(e) {
        var r, a, c, h, o, types, base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
        for (c = e.length, a = 0, r = ''; a < c;) {
                if (h = 255 & e.charCodeAt(a++), a == c) {
                        r += base64EncodeChars.charAt(h >> 2),
                        r += base64EncodeChars.charAt((3 & h) << 4),
                        r += '==';
                        break
                }
                if (o = e.charCodeAt(a++), a == c) {
                        r += base64EncodeChars.charAt(h >> 2),
                        r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),
                        r += base64EncodeChars.charAt((15 & o) << 2),
                        r += '=';
                        break
                }
                types = e.charCodeAt(a++),
                r += base64EncodeChars.charAt(h >> 2),
                r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),
                r += base64EncodeChars.charAt((15 & o) << 2 | (192 & types) >> 6),
                r += base64EncodeChars.charAt(63 & types)
        }
        return r
}
function hexEnc(code) {
    for (var hexStr = [], i = 0, s; i < code.length; i++) {
      s = code.charCodeAt(i).toString(16);
      hexStr += "\\x" + s;
      hexStr +=s;
    }
    return hexStr
}

const jscode = fs.readFileSync("./demo.js", {
      encoding: "utf-8"
    });
// 解析为 babel
let ast = parser.parse(jscode);
let bigArr = [];
console.log("start...");


// traverse(ast,{
//         MemberExpression(path){
//                 if(types.isIdentifier(path.node.property)){
//                         let name = path.node.property.name;
//                         path.node.property = types.stringLiteral(hexEnc(name));
//                 }
//                 path.node.computed = true;
//         }
// });


function generatorIdentifier(decNum){
        let flag = ['O', 'o', '0'];
        let retval = [];
        while(decNum > 0){
                retval.push(decNum % 3);
                decNum = parseInt(decNum / 3);
        }
        let Identifier = retval.reverse().map(function(v){
                return flag
        }).join('');
        Identifier.length < 6 ? (Identifier = ('OOOOOO' + Identifier).substr(-6)):
        Identifier == '0' && (Identifier = 'O' + Identifier);
        return Identifier;
}

function renameOwnBinding(path) {
        // 自己的对象和全局的对象
    let OwnBindingObj = {}, globalBindingObj = {}, i = 0;
    path.traverse({
      Identifier(p){
            let name = p.node.name;
                        //作用域
            let binding = p.scope.getOwnBinding(name);
                        //三元表达式
            binding && generator(binding.scope.block).code == path + '' ?
            (OwnBindingObj = binding) : (globalBindingObj = 1);
      }
    });
        //替换
    for(let oldName in OwnBindingObj) {
      do {
            var newName = generatorIdentifier(i++);
      } while(globalBindingObj);
      OwnBindingObj.scope.rename(oldName, newName);
    }
}


// 遍历
traverse(ast, {
    MemberExpression(path) {
      let name = path.node.property.name;
      if (types.isIdentifier(path.node.property)) {
            // . to []
            path.node.property = types.stringLiteral(name);
      }
      path.node.computed = true;

    },
   Identifier(path){
                let name = path.node.name;
      // 内置
                if('eval|parseInt|encodeURIComponent|Object|Function|Boolean|Number|Math|Date|String|RegExp|Array'.indexOf(name) != -1){
                        path.replaceWith(types.memberExpression(types.identifier('window'), types.stringLiteral(name), true));
                }
        },
   NumericLiteral(path){
      // value=>1000 key==>666 cipherNum===>370
                let value = path.node.value;
                let key = parseInt(Math.random() * (999999 - 100000) + 100000, 10);
                let cipherNum = value ^ key;
                path.replaceWith(types.binaryExpression('^', types.numericLiteral(cipherNum), types.numericLiteral(key)));
                //替换后的节点里也有numericLiteral节点,会造成死循环,因此需要加入path.skip()
      path.skip();
        },

    StringLiteral(path){

                let encStr = types.callExpression(
                             types.identifier('atob'), );
                path.replaceWith(encStr);
                path.skip();
    },
        StringLiteral(path){
                let cipherText = base64Encode(path.node.value);
                // 检查是否数组里面已经存在
                let bigArrIndex = bigArr.indexOf(cipherText);
                let index = bigArrIndex;
                if(bigArrIndex == -1){
                        let length = bigArr.push(cipherText);
                        index = length -1;
                }
                let encStr = types.callExpression(
                                        types.identifier('atob'),
                                        [types.memberExpression(types.identifier('arr'),
                                                                       types.numericLiteral(index), true)]);
                path.replaceWith(encStr);
        },
        'Program|FunctionExpression|FunctionDeclaration'(path) {
      renameOwnBinding(path);
    },
});

bigArr = bigArr.map(function(v){
    return types.stringLiteral(v);
});
//声明arr 并且加入到最前面
bigArr = types.variableDeclarator(types.identifier('arr'), types.arrayExpression(bigArr));
bigArr = types.variableDeclaration('var', );
ast.program.body.unshift(bigArr);


let oneCode = generator(ast).code;
fs.writeFile('./AfterAstCode.js', oneCode, (err)=>{});
console.log("end...");
```

Jormungand911 发表于 2022-5-23 10:44

AST不是需要解析Token,再调用Parser么,略读了下,没有涉及到呢,这个跟我了解的AST不是同一个东西么

zgrm1000 发表于 2022-5-20 12:21

学习到了,感谢感谢

qqxiazhitmac 发表于 2022-5-20 13:28

ligxi 发表于 2022-5-20 13:58

这不是小肩膀的教程吗?
{:301_1008:}

taxuewuhen 发表于 2022-5-20 18:01

谢谢楼主分享

keyyan 发表于 2022-5-20 18:42

小葵花课堂开课了,感谢up主分享好的教程

xjf12345 发表于 2022-5-20 18:53

谢谢楼主分享

citrus 发表于 2022-5-21 02:10

谢谢分享

WX2886 发表于 2022-5-22 20:32

感谢大佬分享教程

happyBread 发表于 2022-5-22 23:32

感谢教程, 对js 反编译很有用
页: [1] 2
查看完整版本: Ast入门使用