AST反混淆实战-默认难度

Ast实战:反混淆解析默认难度

ob混淆网站
https://obfuscator.io/

一、混淆demo生成
在这里插入图片描述
二、混淆demo说明
在这里插入图片描述
三、混淆demo整理
在这里插入图片描述

demo.js
//TODO  这里对混淆demo进行了手动调整顺序操作,为了便于阅读,进行了格式化处理操作

function _0x339e() {
    var _0x42f2a4 = ['8Dxtvnv', '1912401YitxVl', '552360Kaxbyo', '14223690TRfrhE', '604168XFvLfg', 'log', '600492mDDIrH', '1069859jMGkRp', '1452912JKNnaK', '4RKPdfB', '1cFEKdm'];
    _0x339e = function () {
        return _0x42f2a4;
    };
    return _0x339e();
}
(function (_0x471552, _0xc9a4c4) {
    var _0x3dbfaa = _0x367b, _0x191317 = _0x471552();
    while (!![]) {
        try {
            var _0x48b06f = parseInt(_0x3dbfaa(0x87)) / 0x1 * (-parseInt(_0x3dbfaa(0x8c)) / 0x2) + parseInt(_0x3dbfaa(0x83)) / 0x3 * (-parseInt(_0x3dbfaa(0x86)) / 0x4) + -parseInt(_0x3dbfaa(0x8a)) / 0x5 + -parseInt(_0x3dbfaa(0x85)) / 0x6 + -parseInt(_0x3dbfaa(0x84)) / 0x7 * (parseInt(_0x3dbfaa(0x88)) / 0x8) + -parseInt(_0x3dbfaa(0x89)) / 0x9 + parseInt(_0x3dbfaa(0x8b)) / 0xa;
            if (_0x48b06f === _0xc9a4c4) break; else _0x191317['push'](_0x191317['shift']());
        } catch (_0x3bfc6f) {
            _0x191317['push'](_0x191317['shift']());
        }
    }
}(_0x339e, 0x315bb));
function _0x367b(_0x153ad6, _0x5252f0) {
    var _0x339e10 = _0x339e();
    return _0x367b = function (_0x367bc3, _0x44cdb0) {
        _0x367bc3 = _0x367bc3 - 0x83;
        var _0x45def4 = _0x339e10[_0x367bc3];
        return _0x45def4;
    }, _0x367b(_0x153ad6, _0x5252f0);
}
function hi() {
    var _0x31ae77 = _0x367b;
    console[_0x31ae77(0x8d)]('Hello\x20World!');
}
hi();

四、存在难点
在这里插入图片描述

难点解决:
AST反混淆进阶-标识符重复赋值
https://jia666666.blog.csdn.net/article/details/120352005

在这里插入图片描述

难点解决:
AST反混淆进阶-大数组解密
https://jia666666.blog.csdn.net/article/details/120304802
注意:由于这里demo不同于大数组解密样例,需要进行部分改写,才能使用大数组解密模块

五、解混淆

dec_main.js

const fs = require("fs");//文件读写
const parse = require("@babel/parser"); //解析为ast
const traverse = require('@babel/traverse').default;//遍历节点
const t = require('@babel/types');//类型
const generator = require('@babel/generator').default;//ast解析为代码


//读取js文件
const jscode = fs.readFileSync(
    './demo.js', {
        encoding: 'utf-8'
    }
);
let ast = parse.parse(jscode);//js转ast

try {
    //TODO 1 标识符-重复赋值
    traverse(ast, {VariableDeclarator: {exit: [ReIdent]},});
    console.log('第一步:标识符-重复赋值已完成')

    //TODO 2 大数组解密
    ast = decrypt_arr(ast)//大数组还原
    console.log('第二步:大数组解密已完成')

    //TODO  拆分对象合并
    //TODO  对象表达式字符串合并
    //TODO  花指令函数处理
    //TODO  反控制流平坦化
    //TODO  自执行实参替换形参
    //TODO  替换空参数的自执行方法为顺序语句-慎用!可能涉及到作用域的问题。
    //TODO  删减定时器
    //TODO  return函数简化
    //TODO  数组函数简化
    //TODO  常量计算
    //TODO  未修改常量替换
    //TODO  删除if语句块中假的部分-依赖常量计算
    //TODO  删减console禁用部分
    //TODO  正则检测替换
    //TODO  删减未引用的标识符
    //TODO  内存爆破检测

} catch (e) {
    console.log(e);
} finally {
    //TODO Finally ast还原js
    code = generator(ast, opts = {jsescOption: {"minimal": true}}).code// 处理中文Unicode
//文件保存
    fs.writeFile('./demoNew.js', code, (err) => {
    });
}


function decrypt_arr(ast) {
    //TODO 1 解密三部分的代码执行
    let end = 3;//切片需要处理的代码块
    let newAst = parse.parse('');//新建ast
    let decrypt_code = ast.program.body.slice(0, end);//切片
    newAst.program.body = decrypt_code// 将前3个节点替换进新建ast
    let stringDecryptFunc = generator(newAst, {compact: true},).code;//转为js,由于存在格式化检测,需要指定选项,来压缩代码// 自动转义
    eval(stringDecryptFunc);//执行三部分的代码


    //TODO 2 准备工作及对解密三部分节点删除
    let stringDecryptFuncAst = ast.program.body[end - 1];// 拿到解密函数所在的节点

    let DecryptFuncName = stringDecryptFuncAst.id.name;//拿到解密函数的名字
    var rest_code = ast.program.body.slice(end); // 剩下的节点
    ast.program.body = rest_code;//剩下的节点替换


    //TODO 3 加密数组还原
    traverse(ast, {
        CallExpression(path) {//回调表达式匹配--替换加密数组为对应的值
            if (t.isIdentifier(path.node.callee, {name: DecryptFuncName})) {       //当变量名与解密函数名相同时,就执行相应操作
                path.replaceWith(t.valueToNode(eval(path.toString())));      // 值替换节点
            }
        },
    });
    return ast;

}


function ReIdent(path) {
    // 标识符简化
    let node = path.node;//获取路径节点
    if (!t.isIdentifier(node.id) || !t.isIdentifier(node.init)) return;

    let leftName = node.id.name;//函数名称
    let rightName = node.init.name;//函数名称

    let scope = path.scope;//获取路径的作用域
    let binding = scope.getBinding(leftName);//获取绑定
    if (!binding || binding.constantViolations.length > 0) {//检查该变量的值是否被修改--一致性检测
        return;
    }
    let paths = binding.referencePaths;//绑定引用的路径
    let paths_sums = 0;
    paths.map(function (refer_path) {
        refer_path.node.name = rightName;//标识符重命名
        paths_sums += 1;//路径+1
    });
    if (paths_sums == paths.length) {//若绑定的每个路径都已处理 ,则移除当前路径
        path.remove();//删除路径
    }
}

六、解混淆完成

demoNew.js

function hi() {
  console["log"]('Hello\x20World!');
}

hi();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jia666666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值