AST入门与实战(二):删除垃圾代码

本文介绍了如何使用Babel库进行JavaScript代码的反混淆,特别是针对未使用的变量Declarator进行删除,以简化代码并提高可读性。作者提到手动删除解密函数,因为只是为了学习,并非实际需求。

原文地址:https://zhuoyue360.com/jsnx/109.html

AST入门与实战(一):基于babel库的js反混淆模板的实践 : https://www.zhuoyue360.com/jsnx/106.html

还记的上一篇AST的文章,我们把函数调用简单的给替换了一下,但是其最终的效果并不完美.

哪里不完美呢? 有如下几点:

  1. 开头的匿名函数 ,_0x4f09 ,_0x49be 函数已经没用,我们应该删除它 (我认为手动删除就好了)
  2. 在代码中,存在不少的无效代码,例如var _0x49beab = _0x49be(); 我也也应该删除它.
(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();

所以,我们理想状态下的代码应该是:

function hi() {
  console['log']('Hello,zhuoyue360.com');
}
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();

我们可以通过枚举VariableDeclarator 来实现.

image-20230811161026476

思路如下:

  1. 枚举VariableDeclarator
  2. 通过scope.getBinding来获取调用的次数
  3. 如果次数为0,删除它的父节点(也就是那一整行代码)VariableDeclaration

实现代码如下:

const deleteUnUseVar = {
    VariableDeclarator(path){
        let {node,scope} = path;
        // 我们拿到变量名称, 寻找其binding的次数. 如果binding的长度为0的话,证明没用过,删除即可.
        const {id,init} = node;
        console.log(id.name)
        const bindings = scope.getBinding(id.name);
        if (!bindings || bindings.constantViolations.length > 0){
            // 这个变量被用了.
            return;
        }
        // 这个变量没任何引用.
        path.parentPath.remove();

    }
}
traverse(ast, deleteUnUseVar);

最终的展示效果如下:

解密函数我手动删除了, 感觉好像没多大必要写自动的. 毕竟只是学习~


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();
抽象语法树(AST)是一种以树状形式表示源代码抽象语法结构的数据结构,在编译器、代码分析工具和程序优化等领域有重要应用,在现代 JavaScript 开发中也备受关注 [^1][^3]。以下是关于 AST入门知识和实战经验介绍: ### 入门知识 #### 定义概念 AST 以树状形式呈现源代码的抽象语法结构,它忽略了源代码中的一些细节,如空格、换行符等,只关注代码的语法结构。例如,对于 `let a = 1;` 这样的代码AST 会将其解析为表示变量声明的节点结构,清晰展现代码的逻辑组成 [^1]。 #### 工作流程 以 JavaScript 编译器 Babel 为例,其运行代码分三个阶段: - **解析(parsing)**:将代码字符串转换成 AST 抽象语法树。例如,输入一段 JavaScript 代码,解析器会将其处理成对应的 AST 结构。 - **转译(transforming)**:对抽象语法树进行变换操作。比如可以修改 AST 中的节点,实现代码的功能增强或修改。 - **生成(generation)**:根据变换后的抽象语法树生成新的代码字符串 [^2]。 ### 实战经验 #### 安装工具 在 JavaScript 开发中,常用 Babel 相关工具来处理 AST。可以使用 npm 进行安装: ```bash npm install --save-dev @babel/core @babel/cli @babel/preset-env ``` #### 简单示例 以下是一个简单的 Babel 插件示例,用于将代码中的 `console.log` 移除: ```javascript const babel = require('@babel/core'); const removeConsolePlugin = { visitor: { CallExpression(path) { const calleeName = path.get('callee').toString(); if (calleeName === 'console.log') { path.remove(); } } } }; const code = 'console.log("Hello, World!"); let a = 1;'; const result = babel.transformSync(code, { plugins: [removeConsolePlugin] }); console.log(result.code); ``` 在这个示例中,定义了一个 Babel 插件,通过访问 `CallExpression` 节点,判断是否为 `console.log` 调用,如果是则移除该节点,最后生成新的代码
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值