AST入门与实战(一):基于babel库的js反混淆通用模板

news2024/11/27 22:27:12

AST入门与实战(一):基于babel库的js反混淆通用模板

首发地址:http://zhuoyue360.com/jsnx/106.html

1. 模板代码

通用模板来源自菜老板的知识星球.

const fs = require('fs');
const types = require("@babel/types");
const parser = require("@babel/parser");
const template = require("@babel/template").default;
const traverse = require("@babel/traverse").default;
const generator = require("@babel/generator").default;


//js混淆代码读取
process.argv.length > 2 ? encodeFile = process.argv[2] : encodeFile = "./encode.js";  //默认的js文件
process.argv.length > 3 ? decodeFile = process.argv[3] : decodeFile = encodeFile.slice(0, encodeFile.length - 3) + "_ok.js";

//将源代码解析为AST
let sourceCode = fs.readFileSync(encodeFile, { encoding: "utf-8" });
let ast = parser.parse(sourceCode);
console.time("处理完毕,耗时");






const visit =
{
	// TODO write your code here!
}

traverse(ast, visit);





const simplifyLiteral = {
	NumericLiteral({ node }) {
		if (node.extra && /^0[obx]/i.test(node.extra.raw)) {
			node.extra = undefined;
		}
	},
	StringLiteral({ node }) {
		if (node.extra && /\\[ux]/gi.test(node.extra.raw)) {
			node.extra = undefined;
		}
	},
}


traverse(ast, simplifyLiteral);


console.timeEnd("处理完毕,耗时");
let { code } = generator(ast, opts = { 
	"compact"     : false,  // 是否压缩代码
  "comments"    : false,  // 是否保留注释
	"jsescOption" : { "minimal": true },  //Unicode转义
});

fs.writeFile(decodeFile, code, (err) => { });

2. 插件编写

1. 准备工作

我们已经拿到了最基础的使用模板以后,此时我们的ast反混淆已经成了一个填空题. 我们只需要把我们写好的网站反混淆插件填入即可,非常的简单. 接下来,我们找个简单的小案例来试试.

混淆代码均来自于:https://obfuscator.io/ 网站生成.

源代码:


function hi() {
  console.log("Hello,zhuoyue360.com");
}
function h3i() {
  console.log("Hello,zhuoyue360.com");
}function h2i() {
  console.log("Hello,zhuoyue360.com");
}function h44444i() {
  console.log("Hello,zhuoyue360.com");
}
hi();

混淆后的代码:(格式化后)

(function(_0x42555b, _0x288c31) {
    var _0x2e2c7a = _0x4f09
      , _0x264ee4 = _0x42555b();
    while (!![]) {
        try {
            var _0x54167b = parseInt(_0x2e2c7a(0x106)) / 0x1 * (-parseInt(_0x2e2c7a(0x10a)) / 0x2) + -parseInt(_0x2e2c7a(0x109)) / 0x3 * (parseInt(_0x2e2c7a(0x10b)) / 0x4) + -parseInt(_0x2e2c7a(0x10e)) / 0x5 * (parseInt(_0x2e2c7a(0x111)) / 0x6) + -parseInt(_0x2e2c7a(0x110)) / 0x7 + parseInt(_0x2e2c7a(0x10c)) / 0x8 + parseInt(_0x2e2c7a(0x10d)) / 0x9 * (parseInt(_0x2e2c7a(0x10f)) / 0xa) + parseInt(_0x2e2c7a(0x108)) / 0xb;
            if (_0x54167b === _0x288c31)
                break;
            else
                _0x264ee4['push'](_0x264ee4['shift']());
        } catch (_0x1b893f) {
            _0x264ee4['push'](_0x264ee4['shift']());
        }
    }
}(_0x49be, 0xbbf5c));
function hi() {
    console['log']('Hello,zhuoyue360.com');
}
function _0x4f09(_0xd05c9f, _0x352733) {
    var _0x49beab = _0x49be();
    return _0x4f09 = function(_0x4f0967, _0x3191e8) {
        _0x4f0967 = _0x4f0967 - 0x105;
        var _0x4f9c38 = _0x49beab[_0x4f0967];
        return _0x4f9c38;
    }
    ,
    _0x4f09(_0xd05c9f, _0x352733);
}
function _0x49be() {
    var _0x13bd5d = ['12032256MLzLfN', '1251zScKBQ', '25cNqVzl', '270jbEuTF', '5872188ZkfPRj', '1062282TyhTBn', 'Hello,zhuoyue360.com', '1kakbhL', 'log', '11816574EYEQFr', '66741ytXvQy', '42550jdDgVb', '12QEFacN'];
    _0x49be = function() {
        return _0x13bd5d;
    }
    ;
    return _0x49be();
}
function h3i() {
    var _0x2b1dcb = _0x4f09;
    console[_0x2b1dcb(0x107)](_0x2b1dcb(0x105));
}
function h2i() {
    var _0xa95bed = _0x4f09;
    console[_0xa95bed(0x107)](_0xa95bed(0x105));
}
function h44444i() {
    var _0xb505a4 = _0x4f09;
    console[_0xb505a4(0x107)](_0xb505a4(0x105));
}
hi();

我们要尽可能的把混淆后的代码转换成源代码 .此时,我们就需要借助另外一个网站:

https://astexplorer.net/

配置如下, 具体的大家自行在网络上查看相关资料.

image-20230811101411566

好了,目前我们所有的工作已经准备完成,我们就开始看如何还原代码了.

1. 函数调用计算

在下面这个案例中, 我们知道函数调用的真正方法是 _0x4f09 , 然后再使用_0x4f09 的每个函数的第一行都是var xxxxx= _0x4f09; 类似的赋值操作

function _0x4f09(_0xd05c9f, _0x352733) {
    var _0x49beab = _0x49be();
    return _0x4f09 = function(_0x4f0967, _0x3191e8) {
        _0x4f0967 = _0x4f0967 - 0x105;
        var _0x4f9c38 = _0x49beab[_0x4f0967];
        return _0x4f9c38;
    }
    ,
    _0x4f09(_0xd05c9f, _0x352733);
}

function h3i() {
    var _0x2b1dcb = _0x4f09;
    console[_0x2b1dcb(0x107)](_0x2b1dcb(0x105));
}
function h2i() {
    var _0xa95bed = _0x4f09;
    console[_0xa95bed(0x107)](_0xa95bed(0x105));
}
function h44444i() {
    var _0xb505a4 = _0x4f09;
    console[_0xb505a4(0x107)](_0xb505a4(0x105));
}

所以,我们的脚本可以按照下面的思路进行编写

  1. 可以先枚举所有函数.
  2. 函数的第一行代码是不是类似于var xxxxx= _0x4f09;
  3. 找到使用xxxxx的函数调用,进行替换

那么让我们来编写第一个脚本.funcCallReplace

1. 枚举所有函数

根据工具提示,该节点是FunctionDeclaration

image-20230811103028168

所以,我们初步的代码为:

const funcCallReplace = {
    FunctionDeclaration(path){
        let {node} = path;
        console.log(node.id.name)
    }
}

traverse(ast, funcCallReplace);

为了验证,我把返回枚举到的函数名称都给列举出来了.

node .\main.js
hi
_0x4f09
_0x49be
h3i
h2i
h44444i
处理完毕,耗时: 10.56ms

2. 函数的第一行代码是不是类似于var xxxxx= _0x4f09;

我们可以看到,目标函数的body的第一行,都是VariableDeclaration

image-20230811103543234

同时,VariableDeclaratorinit 节点的calleename 的内容为_0x49be

image-20230811103711391

过滤条件搞清楚了,我们就来继续更新我们上面写的代码吧~

通过下面代码,我们已经可以把关键的函数过滤出来了~

const funcCallReplace = {
    FunctionDeclaration(path){
        let {node} = path;
        // 1. 拿到body
        let body = node.body.body;
        // 2. 判断body的第一条是否为VariableDeclaration
        if (body.length == 0 || body[0].type != 'VariableDeclaration' || body[0].declarations.length ==0) return 
        let declaration = body[0].declarations[0];
        if (declaration.init == undefined || declaration.init.name != '_0x4f09') return
        let varName = declaration.id.name
        console.log(node.id.name)
        console.log(varName)
    }   
}

traverse(ast, funcCallReplace);

执行后的结果:

h3i
main.js:33
_0x2b1dcb
main.js:34
h2i
main.js:33
_0xa95bed
main.js:34
h44444i
main.js:33
_0xb505a4
main.js:34
处理完毕,耗时: 3834.485107421875ms
main.js:61
处理完毕,耗时: 3.835s

然后,我们就需要看看谁用了varName, 然后我们把它给替换掉即可.

// 取自蔡老板星球脚本的代码.
function getAllBindingInfo(name,scope){
    let pathList = [];
    // 查看引用
    const bindings = scope.getBinding(name);
    if (!bindings ){
        return pathList;
    }
    for(let referPath of bindings.referencePaths){
        // 获取父节点
        let parentPath = referPath.parentPath
        // 判断类型.
        if (parentPath.isVariableDeclarator()){
            // 获取变量名称
            let {node,scope} = parentPath;
            let varName = node.id.name;
            pathList = [].concat(pathList,getAllBindingInfo(varName,scope));
            // 删除掉这些节点.
            parentPath.remove()
        }else{
            pathList.push(parentPath)

        }

    }
    // console.log(name,pathList)
    return pathList;


}


(function(_0x42555b, _0x288c31) {
    var _0x2e2c7a = _0x4f09
      , _0x264ee4 = _0x42555b();
    while (!![]) {
        try {
            var _0x54167b = parseInt(_0x2e2c7a(0x106)) / 0x1 * (-parseInt(_0x2e2c7a(0x10a)) / 0x2) + -parseInt(_0x2e2c7a(0x109)) / 0x3 * (parseInt(_0x2e2c7a(0x10b)) / 0x4) + -parseInt(_0x2e2c7a(0x10e)) / 0x5 * (parseInt(_0x2e2c7a(0x111)) / 0x6) + -parseInt(_0x2e2c7a(0x110)) / 0x7 + parseInt(_0x2e2c7a(0x10c)) / 0x8 + parseInt(_0x2e2c7a(0x10d)) / 0x9 * (parseInt(_0x2e2c7a(0x10f)) / 0xa) + parseInt(_0x2e2c7a(0x108)) / 0xb;
            if (_0x54167b === _0x288c31)
                break;
            else
                _0x264ee4['push'](_0x264ee4['shift']());
        } catch (_0x1b893f) {
            _0x264ee4['push'](_0x264ee4['shift']());
        }
    }
}(_0x49be, 0xbbf5c));
function _0x4f09(_0xd05c9f, _0x352733) {
    var _0x49beab = _0x49be();
    return _0x4f09 = function(_0x4f0967, _0x3191e8) {
        _0x4f0967 = _0x4f0967 - 0x105;
        var _0x4f9c38 = _0x49beab[_0x4f0967];
        return _0x4f9c38;
    }
    ,
    _0x4f09(_0xd05c9f, _0x352733);
}
function _0x49be() {
    var _0x13bd5d = ['12032256MLzLfN', '1251zScKBQ', '25cNqVzl', '270jbEuTF', '5872188ZkfPRj', '1062282TyhTBn', 'Hello,zhuoyue360.com', '1kakbhL', 'log', '11816574EYEQFr', '66741ytXvQy', '42550jdDgVb', '12QEFacN'];
    _0x49be = function() {
        return _0x13bd5d;
    }
    ;
    return _0x49be();
}
const funcCallReplace = {
    FunctionDeclaration(path){
        let {node,scope} = path;
        // 1. 拿到body
        let body = node.body.body;
        // 2. 判断body的第一条是否为VariableDeclaration
        if (body.length == 0 || body[0].type != 'VariableDeclaration' || body[0].declarations.length ==0) return 
        let declaration = body[0].declarations[0];
        if (declaration.init == undefined || declaration.init.name != '_0x4f09') return
        let varName = declaration.id.name
        console.log(node.id.name)
        console.log(varName)
        // 3. 获取所有引用
        let bindingPathList = getAllBindingInfo(varName,scope);
        console.log(bindingPathList)
        for (let referPath of bindingPathList) {
            // 获取参数,执行函数,替换内容
            let args = referPath.node.arguments;
            if (args == undefined ||args.length != 1){
                continue
            }
            let argValue = referPath.node.arguments[0].extra.raw;
            console.log(argValue)
            referPath.replaceWith(types.valueToNode(_0x4f09(argValue)))
        }
    }   
}

traverse(ast, funcCallReplace);

还原后得代码:

可以看到h3i ,h2ih44444i 的内容都清晰课件了.

(function (_0x42555b, _0x288c31) {
  var _0x2e2c7a = _0x4f09,
    _0x264ee4 = _0x42555b();
  while (!![]) {
    try {
      var _0x54167b = parseInt(_0x2e2c7a(262)) / 1 * (-parseInt(_0x2e2c7a(266)) / 2) + -parseInt(_0x2e2c7a(265)) / 3 * (parseInt(_0x2e2c7a(267)) / 4) + -parseInt(_0x2e2c7a(270)) / 5 * (parseInt(_0x2e2c7a(273)) / 6) + -parseInt(_0x2e2c7a(272)) / 7 + parseInt(_0x2e2c7a(268)) / 8 + parseInt(_0x2e2c7a(269)) / 9 * (parseInt(_0x2e2c7a(271)) / 10) + parseInt(_0x2e2c7a(264)) / 11;
      if (_0x54167b === _0x288c31) break;else _0x264ee4['push'](_0x264ee4['shift']());
    } catch (_0x1b893f) {
      _0x264ee4['push'](_0x264ee4['shift']());
    }
  }
})(_0x49be, 769884);
function hi() {
  console['log']('Hello,zhuoyue360.com');
}
function _0x4f09(_0xd05c9f, _0x352733) {
  var _0x49beab = _0x49be();
  return _0x4f09 = function (_0x4f0967, _0x3191e8) {
    _0x4f0967 = _0x4f0967 - 261;
    var _0x4f9c38 = _0x49beab[_0x4f0967];
    return _0x4f9c38;
  }, _0x4f09(_0xd05c9f, _0x352733);
}
function _0x49be() {
  var _0x13bd5d = ['12032256MLzLfN', '1251zScKBQ', '25cNqVzl', '270jbEuTF', '5872188ZkfPRj', '1062282TyhTBn', 'Hello,zhuoyue360.com', '1kakbhL', 'log', '11816574EYEQFr', '66741ytXvQy', '42550jdDgVb', '12QEFacN'];
  _0x49be = function () {
    return _0x13bd5d;
  };
  return _0x49be();
}
function h3i() {
  var _0x2b1dcb = _0x4f09;
  console["log"]("Hello,zhuoyue360.com");
}
function h2i() {
  var _0xa95bed = _0x4f09;
  console["log"]("Hello,zhuoyue360.com");
}
function h44444i() {
  var _0xb505a4 = _0x4f09;
  console["log"]("Hello,zhuoyue360.com");
}
hi();

接下来,就是垃圾代码删除的功能了. 这点留在下一篇文章中!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/866943.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

为什么 Mixin 被认为是有害的

为什么 Mixin 被认为是有害的 Mixin 是在 Vue 2 中引入的,作为组件之间共享代码的解决方案,这种方式成为许多代码库不可或缺的一部分。然而,随着时间的推移,它们的使用开始出现问题。尽管 mixins 最初很有吸引力,但现…

今天我花了一个通宵的时间安装Windows11系统居然失败,忍不住哭了!

🚀 个人主页 极客小俊 ✍🏻 作者简介:web开发者、设计师、技术分享博主 🐋 希望大家多多支持一下, 我们一起进步!😄 🏅 如果文章对你有帮助的话,欢迎评论 💬点赞&#x1…

Python爬虫:抓取表情包的下载链接

Python爬虫:抓取表情包的下载链接 1. 前言2. 具体实现3. 实现代码 1. 前言 最近发现了一个提供表情包的网址,觉得上面的内容不错,于是就考虑用Python爬虫获取上面表情包的下载链接。整体而言,实现这个挺简单的,就是找到提供表情包…

Kubernetes pod调度约束[亲和性 污点] 生命阶段 排障手段

调度约束 Kubernetes 是通过 List-Watch 的机制进行每个组件的协作,保持数据同步的,每个组件之间的设计实现了解耦。 用户是通过 kubectl 根据配置文件,向 APIServer 发送命令,在 Node 节点上面建立 Pod 和 Container。 APIServer…

如何学习大数据

文章目录 每日一句正能量前言一、什么是大数据二、大数据的应用领域三、社会对大数据的人才需求四、大数据的学习路线后记 每日一句正能量 多数人认为,一旦达到某个目标,人们就会感到身心舒畅。但问题是你可能永远达不到目标。把快乐建立在还不曾拥有的事…

B057-spring增强 依赖注入 AOP 代理模式 创建Bean

目录 AOP概念代理模式引出AOP实现方式xml方式实现注解方式实现 AOP 概念 事务管理:比如可以抽取try catch的重复代码 日志监控:比如业务逻辑前后打印关于当前订单数量的日志,了解业务做了什么 性能监控:比如业务前后打印时间&…

《最强大模型平台上线,被很多行业“盯”上了》

千帆大模型 1、国内最多的模型2、国内最全的Prompt模板3、总结 千帆大模型平台是面向企业开发者的一站式大模型开发及服务运行平台,也是百度智能云推出的全球首个一站式企业级大模型平台。在提供全套文心大模型服务的基础上,还支持第三方开源大模型、各种…

记录更换若依框架的用户和部门两种表的过程

背景: 公司使用若依框架快速构建项目,客户那边原有的数据要同步过来,且要求字段与原先的字段一致,可以让数据丝滑无畅导入。用户表和部门表是基础在代码出现的地方比较多,该如何考虑去过度去更换) 如何快速…

虹科案例 | 建筑物邻近挖掘工地的结构健康监测

一、 前言 工程与建筑 行业<<<< 工程与建筑——建筑结构健康监测 摘要<<<< 在现代城市环境中&#xff0c;重型建筑施工常常必须在毗邻的邻近建筑和结构附近进行&#xff0c;而这些建筑和结构在挖掘和施工期间必须保持开放以供商业或居住使用。 传…

ModaHub魔搭社区——Milvus 、Qdrant、Waeviate、Pinecone、ElasticSearch矢量数据库对比

资本市场上,2022年也是风起云涌的一年的,各大向量数据库公司纷纷完成了千万美元级别新一轮的融资。可以预见,2023年将会是向量数据库继续快速发展的一年,也会是这一新兴技术由发展走向成熟的一年。这里针对Milvus 、Qdrant、Waeviate、Pinecone、ElasticSearch这五个流行的…

掌握Python的X篇_27_Python中标准库文档查阅方法介绍

前面的博文介绍了python的基本语法、模块及其导入方法。前人将各种方法封装成模块、库、函数供我们使用&#xff0c;如何去使用前人做好的东西&#xff0c;那就需要去查阅文档。今天就介绍python中官方文档的查阅方式。对于初学者而言&#xff0c;python自带的文档就已经足够好…

SQL-每日一题【1484. 按日期分组销售产品】

题目 表 Activities&#xff1a; 编写解决方案找出每个日期、销售的不同产品的数量及其名称。 每个日期的销售产品名称应按词典序排列。 返回按 sell_date 排序的结果表。 结果表结果格式如下例所示。 示例 1: 解题思路 前置知识 group_concat函数的功能   将group by产生的…

6.2.0在线编辑:GrapeCity Documents for Word (GcWord) Crack

GrapeCity Word 文档 (GcWord) 支持 Office Math 函数以及转换为 MathML GcWord 现在支持在 Word 文档中创建和编辑 Office Math 内容。GcWord 中的 OMath 支持包括完整的 API&#xff0c;可处理科学、数学和通用 Word 文档中广泛使用的数学符号、公式和方程。以下是通过 OMa…

92. 反转链表 II

92. 反转链表 II 题目-中等难度示例1. 获取头 反转中间 获取尾 -> 拼接2. 链表转换列表 -> 计算 -> 转换回链表 题目-中等难度 给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节点…

生信豆芽菜-山峦图分析使用说明

网站&#xff1a;http://www.sxdyc.com/visualsRidges 一、山峦图简介 山峦图&#xff08;Ridgeline plots&#xff09;&#xff0c;本质上是多个核密度曲线图的相互重叠组合&#xff0c;也可以看作是只有半个“小提琴”的横向小提琴图&#xff0c;主要用于展示和比较数据&…

Typecho建站:腾讯云轻量应用服务器搭建网站博客方法

腾讯云轻量应用服务器自带Typecho应用模板镜像&#xff0c;腾讯云提供的Typecho模板镜像是基于CentOS 7.6 64位操作系统&#xff0c;并已预置Nginx、PHP、MariaDB软件程序&#xff0c;使用Typecho应用模板可以快速搭建博客、企业官网、电商及论坛等各类网站。腾讯云服务器网分享…

爱立信网管工具使用-Tools for Export Import(TEI)

1、TEI使用 2、数据导出 打开 OSS Common Explorer&#xff0c;如下图&#xff0c;右键“ONRM_ROOT_MO_R”,选择“Export” MO type filter:为了避免生产的 BULK CM export 文件太大&#xff08;可能会达到几个 G&#xff0c;TEI 转换时&#xff0c;对输入的 BULK CM expor…

多线程与并发编程面试题总结

多线程与并发编程 多线程 线程和进程的区别&#xff1f; 从操作系统层面上来讲&#xff1a;进程(process)在计算机里有单独的地址空间&#xff0c;而线程只有单独的堆栈和局部内存空间&#xff0c;线程之间是共享地址空间的&#xff0c;正是由于这个特性&#xff0c;对于同…

使用Python和pymupdf创建简单的PDF阅读器

使用Python和wxPython编写一个简单的PDF阅读器&#xff0c;并展示了PDF文件的内容。 介绍&#xff1a; 在日常工作和学习中&#xff0c;我们经常需要查看和阅读PDF文件。本文将介绍如何使用Python编程语言和wxPython库创建一个简单的PDF阅读器&#xff0c;让我们能够打开文件夹…

【雕爷学编程】Arduino动手做(54)---大按键微动按钮模块3

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…