当前位置: 首页 > news >正文

AST 技术进行 JavaScript 反混淆实战

一、AST 技术核心原理

抽象语法树(AST) 是代码的“骨架”,它把代码拆解成一个个节点,就像把一棵大树拆成树枝、树叶一样。通过分析和修改这些节点,我们可以精准地还原代码的逻辑。

二、实战案例 1:还原字符串编码

混淆代码特征

混淆代码会把字符串拆成数组,然后通过索引访问,比如:

const _0x5c0d = ["Hello", "World", "log", "split", "join"];
console[_0x5c0d[2]](_0x5c0d[0][_0x5c0d[3]]("")[_0x5c0d[4]]("-"));
// 输出 "H-e-l-l-o"
反混淆步骤
  1. 安装依赖

    npm install @babel/parser @babel/traverse @babel/generator
  2. 解析和还原代码

    • 用 Babel 把代码解析成 AST。

    • 遍历 AST,找到字符串数组的定义。

    • 替换所有数组索引访问为实际的字符串值。

const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const generator = require("@babel/generator").default;

const code = `
const _0x5c0d = ["Hello", "World", "log", "split", "join"];
console[_0x5c0d[2]](_0x5c0d[0][_0x5c0d[3]]("")[_0x5c0d[4]]("-"));
`;

// 解析为 AST
const ast = parser.parse(code);

// 遍历 AST 节点
traverse(ast, {
  VariableDeclarator(path) {
    // 找到字符串数组
    if (path.node.id.name === "_0x5c0d") {
      const stringArray = path.node.init.elements.map(e => e.value);
      
      // 替换所有数组引用
      path.scope.traverse(path.scope.block, {
        MemberExpression(subPath) {
          const node = subPath.node;
          if (node.object.name === "_0x5c0d" && node.property.type === "NumericLiteral") {
            const value = stringArray[node.property.value];
            subPath.replaceWith({ type: "StringLiteral", value });
          }
        }
      });
    }
  }
});

// 生成还原后的代码
const output = generator(ast).code;
console.log(output);

输出结果

console["log"]("Hello"["split"]("")["join"]("-"));
// 进一步简化为:console.log("H-e-l-l-o");

三、实战案例 2:修复控制流扁平化

混淆代码特征

混淆代码会把逻辑打乱成一个状态机,比如:

function getSum(n) {
  let state = 0, total = 0, i = 0;
  while (true) {
    switch (state) {
      case 0: state = 1; break;
      case 1: if (i < n) state = 2; else state = 3; break;
      case 2: total += i; i++; state = 1; break;
      case 3: return total;
    }
  }
}
反混淆步骤
  1. 识别状态机模式

    • 找到 switch-case 结构。

    • 分析 state 变量的跳转逻辑。

  2. 重构逻辑

    • 把状态机逻辑还原成正常的循环结构。

const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");

const code = `...上述控制流代码...`;
const ast = parser.parse(code);

traverse(ast, {
  FunctionDeclaration(path) {
    const body = path.get("body.body");
    const switchStmt = body.find(p => p.isSwitchStatement());
    
    // 提取状态转移逻辑
    const stateMap = new Map();
    switchStmt.get("cases").forEach(casePath => {
      const test = casePath.node.test.value;
      const consequent = casePath.get("consequent");
      stateMap.set(test, consequent);
    });

    // 重构为 for 循环
    const newBody = [
      t.variableDeclaration("let", [t.variableDeclarator(t.identifier("total"), t.numericLiteral(0))]),
      t.forStatement(
        t.variableDeclaration("let", [t.variableDeclarator(t.identifier("i"), t.numericLiteral(0))]),
        t.binaryExpression("<", t.identifier("i"), t.identifier("n")),
        t.updateExpression("++", t.identifier("i")),
        t.blockStatement([t.expressionStatement(
          t.assignmentExpression("+=", t.identifier("total"), t.identifier("i"))
        )])
      ),
      t.returnStatement(t.identifier("total"))
    ];

    path.get("body").replaceWith(t.blockStatement(newBody));
  }
});

// 输出还原后代码
console.log(generator(ast).code);

输出结果

function getSum(n) {
  let total = 0;
  for (let i = 0; i < n; i++) {
    total += i;
  }
  return total;
}

四、对抗混淆的高级技巧

  1. 处理多层嵌套

    • 混淆代码可能把数组多层嵌套,需要递归展开所有层级。

  2. 动态解密函数处理

    • 若字符串解密通过函数实现,AST 需模拟执行函数逻辑。

  3. 符号执行优化

    • 对条件进行数学推导,消除永远无法执行的分支。

五、工具链推荐

工具用途示例命令
@babel/parser代码解析为 ASTparser.parse(code)
@babel/traverse节点遍历与修改traverse(ast, { ... })
@babel/generator从 AST 生成代码generator(ast).code

六、总结

AST 反混淆的核心步骤

  1. 解析:把代码转换为结构化的 AST。

  2. 识别模式:找到字符串数组、控制流状态机等特征。

  3. 语义还原:通过节点替换或逻辑重构恢复原始逻辑。

  4. 验证:确保重构后的代码功能与原混淆代码一致。

注意事项

  • 混淆工具可能插入虚假节点(如无用循环),需结合数据流分析过滤。

  • 遇到 evalFunction 动态代码时,需结合动态执行。

  • 推荐结合 Prettier 格式化还原后的代码,提升可读性。

通过 AST 技术,我们可以从“代码加密 → 结构解析 → 逻辑还原”完成全链路逆向工程,是应对现代混淆技术的核心手段!

相关文章:

  • 如何查询node inode上限是多少?
  • 性能飙升50%,react-virtualized-list如何优化大数据集滚动渲染
  • WPF ComboBox首次加载不触发SelectionChanged事件
  • 企业微信:企业ID、AgentID、SecretID
  • linux进程三件套nohup、ps 和 kill 命令的详细解析
  • 剑指Offer(数据结构与算法面试题精讲)C++版——day12
  • 算法——回溯
  • 【多模态大模型】《Qwen2.5-Omni》 论文解读
  • 弥合多层次差距:用于超声心动图中基于文本引导的标签高效分割的双向循环框架|文献速递-深度学习医疗AI最新文献
  • grafana/loki 部署搜集 k8s 集群日志
  • 电脑知识 | TCP通俗易懂详解 <一>
  • Java获取终端设备信息工具类
  • Day 8(下篇):总线驱动模型实战全解析 —— 以 PCA9450 PMIC 为例
  • 【机器学习】每日一讲-朴素贝叶斯公式
  • 超强大小白工具,应用广泛,PDF 删除,无需下载,在线使用,操作超简单,超实用
  • WMware虚拟机Ubuntu磁盘扩容
  • 突破性能瓶颈:Java微服务多任务管理的架构设计与实践
  • 可编辑33页PPT | 经营管理数字化转型平台解决方案
  • MySQL 优化方案大全
  • Acrel-1000DP分布式光伏监控系统在嘉兴亨泰新能源有限公司2996.37KWP分布式光伏项目中的应用
  • 华侨城网站建设/关键词优化工具
  • 山东家居行业网站开发/网络舆情监测平台
  • 免费做网站有哪些家/今日军事新闻头条视频
  • 百度网页打不开怎么办/大同优化推广
  • 淮安网站开发/如何做优化排名
  • 做期货到哪个网站看新闻/个人网站seo入门