【无标题】

AST逆向还原(一)字符串递归解密

相关链接
AST详解与运用 - 知乎 (zhihu.com)
Babel 是什么? · Babel 中文文档 | Babel中文网 (babeljs.cn)

本文以及后续推文如无特殊说明,默认都是在babel的环境编译的,本文仅限相关从业爱好者学习使用。

话不多说,直接还原逆向实践,原站点:

aHR0cHM6Ly93d3cuc3VwZXJiZWQuY24v

拿其中一段代码分析:

;function changeUserState(_0x5d5847) {
    var _0x46c769 = _0x551a
        , _0x43508c = {
        'FPUIO': function(_0x296d3e, _0x32d69f) {
            return _0x296d3e(_0x32d69f);
        },
        'mzIBk': _0x46c769(0x22a, 'XRe['),
        'RysRT': function(_0x3eb3cd, _0x3b1ace) {
            return _0x3eb3cd(_0x3b1ace);
        },
        'YBOFo': 'layui-hide',
        'cBrCl': _0x46c769(0x429, '7awU'),
        'FQNWn': _0x46c769(0x42d, 'Q)Me')
    };
    _0x43508c[_0x46c769(0x1ef, '7awU')]($, _0x43508c[_0x46c769(0x1c9, 'z0@N')])['removeClass'](_0x46c769(0x124, 'hZwl')),
        _0x43508c[_0x46c769(0x21c, 'z0@N')]($, _0x46c769(0x3b1, '1jc1'))['addClass'](_0x43508c[_0x46c769(0x1cc, 'fK(%')]),
        _0x43508c[_0x46c769(0x433, 'hZwl')]($, _0x43508c[_0x46c769(0x35c, 'bQ0(')])[_0x46c769(0xfc, 'u8pZ')](_0x5d5847[_0x46c769(0x388, 'dSI1')] || _0x5d5847['nickName']),
    _0x5d5847[_0x46c769(0x108, 'dSI1')] && _0x43508c[_0x46c769(0x487, '2Ku!')]($, _0x43508c[_0x46c769(0x398, 'u8pZ')])['removeClass'](_0x43508c[_0x46c769(0x59a, '@iK5')]);
}

通过AST explorer可以发现,只要我们把拿到的stringLiteral替换callExpression即可

20231109114318.png (1865×916) (gitee.com)

还原的ast代码

const fs = require('fs');
const parser = require('@babel/parser');
const {default: traverse} = require('@babel/traverse');
const types = require("@babel/types");
const {default: generator} = require("@babel/generator");

let jsCode = fs.readFileSync('decodeDemo.js', {
    encoding: 'utf-8'
})
let ast = parser.parse(jsCode);

// 加密数组
let bigArr = [
    ...
]
// 解密函数 
function _0x551a(_0x2e7fdc, _0x351414) {
	...
}

function decryptStr(path) {
    // 获取binding
    let bindings = path.scope.getBinding(path.node.id.name);
    // 获取引用的path
    let refPaths = bindings && bindings.referencePaths;
    if (refPaths) {
		// 遍历
        for (let i = 0; i < refPaths.length; i++) {
            // 获取父级Path
            let parentPath = refPaths[i].parentPath;
            if (parentPath.isCallExpression()) {
                let argu = parentPath.node.arguments;
                if (argu && argu.length == 2 && types.isNumericLiteral(argu[0]) && types.isStringLiteral(argu[1])) {
                    // 用stringLiteral替换callExpression调用
                    let codeStr = _0x551a(argu[0].value, argu[1].value);
                    parentPath.replaceWith(types.stringLiteral(codeStr));
                }
            } else {
                // 二次或多次赋值递归
                decryptStr(parentPath)
            }
        }
    }
}


traverse(ast, {
    // 捕获VariableDeclarator,通过替换把具体字符串替换_0x46c769(0x1ef, '7awU')的方式解密
    VariableDeclarator(path) {
        if (types.isIdentifier(path.node.init, {name: '_0x551a'})) {
            decryptStr(path);
        }
    }
})

还原的效果如下:

function changeUserState(_0x5d5847) {
  var _0x46c769 = _0x551a,
    _0x43508c = {
      'FPUIO': function (_0x296d3e, _0x32d69f) {
        return _0x296d3e(_0x32d69f);
      },
      'mzIBk': ".logout",
      'RysRT': function (_0x3eb3cd, _0x3b1ace) {
        return _0x3eb3cd(_0x3b1ace);
      },
      'YBOFo': 'layui-hide',
      'cBrCl': ".username",
      'FQNWn': ".user-admin"
    };
  _0x43508c["FPUIO"]($, _0x43508c["mzIBk"])['removeClass']("layui-hide"), _0x43508c["RysRT"]($, ".login")['addClass'](_0x43508c["YBOFo"]), _0x43508c["RysRT"]($, _0x43508c["cBrCl"])["text"](_0x5d5847["username"] || _0x5d5847['nickName']), _0x5d5847["admin"] && _0x43508c["FPUIO"]($, _0x43508c["FQNWn"])['removeClass'](_0x43508c["YBOFo"]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值