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

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. 拿到bodylet body = node.body.body;// 2. 判断body的第一条是否为VariableDeclarationif (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') returnlet varName = declaration.id.nameconsole.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. 拿到bodylet body = node.body.body;// 2. 判断body的第一条是否为VariableDeclarationif (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') returnlet varName = declaration.id.nameconsole.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.rhkb.cn/news/84949.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【css】css中使用变量var

CSS 变量可以有全局或局部作用域。 全局变量可以在整个文档中进行访问/使用,而局部变量只能在声明它的选择器内部使用。 如需创建具有全局作用域的变量,请在 :root 选择器中声明它。 :root 选择器匹配文档的根元素。 如需创建具有局部作用域的变量&am…

【ARM 调试】如何从 crash 信息找出问题原因

一、问题背景 粉丝在进行 ARM-A 系列软件编程时遇到以下问题,串口打印这段日志后就重启了,粉丝求助问是什么原因? Unhandled Exception in EL3. x30 0x0000000000b99b84 x0 0x00000000179a25b0 x1 …

【笔记】树状数组

【笔记】树状数组 目录 简介引入1. 直接暴力2. 维护前缀和数组总结 定义前置知识: lowbit ⁡ \operatorname{lowbit} lowbit 操作区间的表示方法操作单点修改前缀和查询任意区间查询 例题1: 单点修改,区间查询例题2: 区间修改,单点查询例题3:…

苏州OV泛域名RSA加密算法https

RSA加密算法是一种非对称加密算法,它被广泛应用于信息安全领域。与对称加密算法不同,RSA加密算法使用了两个密钥,一个公钥和一个私钥。公钥可以公开,任何人都可以使用它加密信息,但只有私钥的持有者才能解密信息。RSA加…

探索美颜SDK技术:实现精准人脸美化的算法与挑战

在现代社交媒体和直播平台的兴起中,美颜技术已成为一种不可或缺的元素,让用户能够在镜头前展现出最佳的自己。这种技术的背后有着复杂而精密的算法,由美颜SDK驱动,以实现精准人脸美化。本文将探讨这些算法的核心原理、应用领域以及…

Multimap用法详解

Multimap Multimap 是 Google 的 Guava 库为 Java 引入的一种新集合类型&#xff0c;它允许将多个值存储在单个键下。它被设计为一种替代 Map<K, List> 或 Map<K, Set>&#xff08;JDK 标准集合框架&#xff09;的方案。 Multimap<K, V> 扩展了 AbstractMul…

【金融量化】Python实现根据收益率计算累计收益率并可视化

1 理论 理财产品&#xff08;本金100元&#xff09; 第1天&#xff1a;3% &#xff1a;&#xff08;13%&#xff09; ✖ 100 103 第2天&#xff1a;2% &#xff1a;&#xff08;12%&#xff09;✖ 以上 103 2.06 第3天&#xff1a;5% : &#xff08;15%&#xff09;✖ 以上…

SpringBoot中间件使用之EventBus、Metric、CommandLineRunner

1、EventBus 使用EventBus 事件总线的方式可以实现消息的发布/订阅功能&#xff0c;EventBus是一个轻量级的消息服务组件&#xff0c;适用于Android和Java。 // 1.注册事件通过 EventBus.getDefault().register(); // 2.发布事件 EventBus.getDefault().post(“事件内容”); …

【Linux】带你深入了解多路转接

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《学会Linux》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录 &#x1f449;多路转接…

竞赛项目 深度学习花卉识别 - python 机器视觉 opencv

文章目录 0 前言1 项目背景2 花卉识别的基本原理3 算法实现3.1 预处理3.2 特征提取和选择3.3 分类器设计和决策3.4 卷积神经网络基本原理 4 算法实现4.1 花卉图像数据4.2 模块组成 5 项目执行结果6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &a…

Maven 生成(打包)带有依赖的可以直接执行的一个 jar 包

在pom中增加如下内容 <build><plugins><plugin><artifactId>maven-assembly-plugin</artifactId><configuration><archive><manifest><mainClass>com.example.xxx.YourClass</mainClass></manifest></…

Windows和Linux系统上的矢量运算:指令级并行计算SIMD(SSE/AVX)应用细节以及相关跨平台的源码解释

注&#xff1a;本文的SIMD&#xff0c;指的是CPU(base intel x86 architecture)指令架构中的相关概念。不涉及GPU端的算力机制。下面的代码在Win10和Linux上均可用。 基本概念 SSE: Streaming SIMD Extensions, x86 architecture AVX: Advanced Vector Extensions SIMD&#…

Springboot 多数据源 dynamic-datasource动态添加移除数据源

0.前言 上一篇文章我们讲了如何通过多数据源组件&#xff0c;在Spring boot Druid 连接池项目中配置多数据源&#xff0c;并且通过DS注解的方式切换数据源&#xff0c;《Spring Boot 配置多数据源【最简单的方式】》。但是在多租户的业务场景中&#xff0c;我们通常需要手动的…

RabbitMQ 消息队列

文章目录 &#x1f370;有几个原因可以解释为什么要选择 RabbitMQ&#xff1a;&#x1f969;mq之间的对比&#x1f33d;RabbitMQ vs Apache Kafka&#x1f33d;RabbitMQ vs ActiveMQ&#x1f33d;RabbitMQ vs RocketMQ&#x1f33d;RabbitMQ vs Redis &#x1f969;linux docke…

C语言案例 球落地反弹-10

题目&#xff1a;一球从100米高度自由落下&#xff0c;每次落地后反跳回原高度的一半;再落下&#xff0c;求它在第10次落地时&#xff0c;共经过多少米第10次反弹多高&#xff1f; 程序分析 球在落地后会反弹为原高度的一半&#xff0c;若设高度为h&#xff0c;那么每次落地的…

MATLAB程序初始化OpenFOAM颗粒位置

问题引入 在OpenFOAM的颗粒两相流求解器中&#xff0c;我们可以采用manualInjection的方式进行自定义颗粒的初始位置&#xff0c;这个命令十分方便&#xff0c;在CFDEM中也有类似的命令&#xff0c;不过CFDEM中的命令更加强大&#xff0c;我们不仅可以定义颗粒的初始位置&…

【我的2023秋招记录】溯流

我的2023秋招记录 开篇&#xff08;2023-08-11&#xff09; 2023已经过去大半年了&#xff0c;久违地打开CSDN&#xff0c;发现上一篇博客还停留在2022年的10月。那时候正值疫情严重&#xff0c;研究所回不去&#xff0c;整天呆在家里面摆烂摸鱼&#xff0c;也时常忧虑之后的…

pikachu中RCE出现乱码的解决的方案

exec “ping” 输入127.0.0.1 这种乱码的解决办法就是在pikachu/vul/rce/rce_ping.php目录里面的第18行代码 header("Content-type:text/html; charsetgbk");的注释打开即可。 BUT但是吧&#xff01;又出现了其他的乱码&#xff01;但是搞完这个再把它给注释掉就行了…

mac ssh连接另一台window虚拟机vm

vmware配置端口映射 编辑(E) > 虚拟网络编辑器(N)... > NAT设置(S)... window防火墙&#xff0c;入站规则添加5555端口 控制面板 > 系统和安全 > Windows 防火墙>高级设置>入站规则>新建规则... tips windows查看端口命令&#xff1a;netstat -ano | f…

vscode的ros拓展(插件)无法渲染urdf

文章目录 事件背景资料调查解决方案 事件背景 之前在vscode中一直用得好好的urdf预览功能&#xff0c;突然在某一天&#xff0c;不行了。 执行 URDF Preview之后&#xff0c;虽然弹出了一个URDF Preview的窗口&#xff0c;但是这个窗口里面啥都没有。没有网格、没有模型。 一开…