吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2918|回复: 12
收起左侧

[Web逆向] Ast入门使用

[复制链接]
QingYi. 发表于 2022-5-20 11:24
本帖最后由 QingYi. 于 2022-5-20 11:42 编辑

前置条件:

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


环境:

1.node
2.Pycharm编译器

正文:

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

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

图片.png
方法二:
图片.png


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

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

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





来到这个网址

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

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

来编写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
3.png
执行之后
1-2.png
正常运行
1-3.png

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

astCode and result
2.3.png

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

进行base64转换
3.3.png

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

对其进行十六进制的混淆
3.5.png

标识符的混淆,也就是作用域有引用的,第五行就没有引用到
3.6.png
我们要找到代码的作用域
3.7.png
生成随机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[v]
        }).join('');
        Identifier.length < 6 ? (Identifier = ('OOOOOO' + Identifier).substr(-6)):
        Identifier[0] == '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[v]
    }).join('');
    Identifier.length < 6 ? (Identifier = ('OOOOOO' + Identifier).substr(-6)):
    Identifier[0] == '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[name] = binding) : (globalBindingObj[name] = 1);
        }
    });
    //替换
    for(let oldName in OwnBindingObj) {
        do {
            var newName = generatorIdentifier(i++);
        } while(globalBindingObj[newName]);
        OwnBindingObj[oldName].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'), [types.stringLiteral(base64Encode(path.node.value))]);
        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', [bigArr]);
ast.program.body.unshift(bigArr);

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

免费评分

参与人数 4吾爱币 +2 热心值 +4 收起 理由
HongHu106 + 1 热心回复!
笙若 + 1 + 1 谢谢@Thanks!
vonfly + 1 热心回复!
zgrm1000 + 1 + 1 谢谢@Thanks!

查看全部评分

本帖被以下淘专辑推荐:

  • · 好帖|主题: 540, 订阅: 84

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

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
这不是小肩膀的教程吗?
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 反编译很有用
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-27 13:11

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表