JS逆向 AST 抽象语法树解析与实践

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: JS逆向 AST 抽象语法树解析与实践

🧩 JS逆向 AST 抽象语法树解析与实践

🔍 什么是 AST 技术?

抽象语法树(Abstract Syntax Tree,AST)是一种以树状结构表示程序源代码的方式,它将代码中的每个组成部分表示为树的一个节点。AST 是编译器和解释器中的重要概念,它用于将源代码转换为计算机能够理解的形式。AST 的主要作用是将源代码中的语法结构转化为树形结构,便于对代码进行分析、转换和优化。

在 JavaScript 中,AST 是通过解析器(如 acornesprima)生成的。这些解析器会将 JavaScript 代码转换为 AST,随后可以通过 AST 对代码进行深入分析或转换。

AST 示例

以下是一个较复杂的 JavaScript 代码示例及其对应的 AST:

// JavaScript 代码示例
function add(a, b) {
  const sum = a + b;
  return sum;
}

const result = add(10, 20);
console.log(result);

在这个代码示例中,函数 add 定义了两个参数 ab,并返回它们的和。代码的 AST 可能如下所示:

Program
  ├── FunctionDeclaration (add)
  │    ├── Parameters
  │    │    ├── Identifier (a)
  │    │    └── Identifier (b)
  │    ├── BlockStatement
  │    │    ├── VariableDeclaration (const)
  │    │    │    ├── VariableDeclarator (sum)
  │    │    │    │    └── BinaryExpression (+)
  │    │    │    │         ├── Identifier (a)
  │    │    │    │         └── Identifier (b)
  │    │    └── ReturnStatement
  │    │         └── Identifier (sum)
  ├── VariableDeclaration (const)
  │    ├── VariableDeclarator (result)
  │    │    └── CallExpression (add)
  │    │         ├── Literal (10)
  │    │         └── Literal (20)
  └── ExpressionStatement (console.log)
       └── Identifier (result)

🛠️ Parser API 学习

JavaScript 提供了一些工具和库,用于解析源代码并生成 AST。其中,acornesprima 是最常用的解析器库。acorn 是一个轻量级的解析器,具有高效且快速的特点,能够将 JavaScript 代码解析为 AST。

使用 acorn 解析 JavaScript 代码

以下是如何使用 acorn 解析 JavaScript 代码并输出 AST 的示例:

const acorn = require('acorn');

// 需要解析的 JavaScript 代码
const code = `
function add(a, b) {
  const sum = a + b;
  return sum;
}

const result = add(10, 20);
console.log(result);
`;

// 使用 acorn 解析代码
const ast = acorn.parse(code, { ecmaVersion: 2020 });

// 输出 AST
console.log(JSON.stringify(ast, null, 2));

在这个示例中,我们使用 acorn.parse 方法将 JavaScript 代码解析为 AST。ecmaVersion 选项指定了 ECMAScript 的版本,确保解析器能够正确处理不同版本的语法。JSON.stringify 方法用于将 AST 对象转换为 JSON 字符串,以便于阅读和调试。

acorn 配置选项

acorn 解析器提供了多种配置选项,允许我们根据需要调整解析行为:

const ast = acorn.parse(code, {
  ecmaVersion: 2020,  // ECMAScript 版本
  sourceType: 'module', // 支持 ES6 模块
  locations: true,     // 启用位置信息
  onComment: (block, text, start, end) => {
    console.log(`Comment: ${text}`);
  }
});
  • ecmaVersion: 指定 ECMAScript 的版本,例如 2020。
  • sourceType: 可以是 scriptmodule,指定源代码类型。
  • locations: 启用位置信息以便于调试。
  • onComment: 回调函数,用于处理代码中的注释。

🔍 traverse 库学习

traverse 是一个用于遍历和操作 AST 的库,它可以帮助我们对 AST 进行各种操作,如遍历、修改和转换。traverse 提供了一种简洁的方式来访问 AST 的各个部分。

安装 traverse

npm install traverse

使用 traverse 遍历 AST

以下是如何使用 traverse 库遍历 AST 的示例:

const traverse = require('traverse');
const acorn = require('acorn');

// 解析 JavaScript 代码
const code = `
function add(a, b) {
  const sum = a + b;
  return sum;
}

const result = add(10, 20);
console.log(result);
`;
const ast = acorn.parse(code, { ecmaVersion: 2020 });

// 遍历 AST
traverse(ast).forEach(function (node) {
    if (node.type === 'Identifier') {
        console.log(`Found identifier: ${node.name}`);
    }
});

在这个示例中,我们使用 traverse 库遍历 AST,并打印出所有标识符节点的名称。traverse 提供了一种简洁的方式来访问和操作 AST 的各个部分。traverse 支持多种遍历策略,可以根据需要定制遍历行为。

自定义遍历策略

traverse 允许我们定义自定义遍历策略,以满足特定需求:

traverse(ast).forEach(function (node) {
    if (node.type === 'FunctionDeclaration') {
        console.log(`Found function declaration: ${node.id.name}`);
    } else if (node.type === 'VariableDeclarator') {
        console.log(`Found variable declarator: ${node.id.name}`);
    }
});

在这个示例中,我们定制了遍历策略,以便分别处理函数声明和变量声明节点。

🧩 字符串和编码还原

在处理 JavaScript 代码时,我们常常需要对字符串和编码进行还原。字符串可能包含转义字符、Unicode 编码等,需要对其进行解析和还原。

字符串解码

JavaScript 字符串中可能包含转义字符,例如 Unicode 转义序列。我们可以使用 JSON.parse 方法将这些转义字符还原为普通字符串:

// 原始字符串
const encodedString = '\\u0048\\u0065\\u006C\\u006C\\u006F';

// 将转义字符还原为普通字符串
const decodedString = JSON.parse(`"${encodedString}"`);

console.log(decodedString); // 输出: Hello

在这个示例中,我们将包含 Unicode 转义序列的字符串 \\u0048\\u0065\\u006C\\u006C\\u006F 还原为普通字符串 Hello。这种方法对于处理编码和转义字符非常有效。

编码还原

URL 编码是一种常见的编码方式,我们可以使用 decodeURIComponent 方法将其还原为普通字符串:

// URL 编码字符串
const encodedURI = 'Hello%20World%21';

// 还原为普通字符串
const decodedURI = decodeURIComponent(encodedURI);

console.log(decodedURI); // 输出: Hello World!

🛠️ 通用常量还原

在 JavaScript 代码中,常量的还原通常涉及将常量值恢复为其原始形式。常量可能以不同的格式存在,如十六进制、二进制等。

十六进制常量还原

// 十六进制常量
const hexValue = 0x1A3F;

// 还原为十进制
const decimalValue = hexValue;

console.log(decimalValue); // 输出: 6719

在这个示例中,我们将十六进制常量 0x1A3F 还原为其十进制值 6719。十六进制常量在 JavaScript 中经常用于表示颜色值、内存地址等。

二进制常量还原

// 二进制常量
const binaryValue = 0b101010;

// 还原为十进制
const decimalValue = binaryValue;

console.log(decimalValue); // 输出: 42

在这个示例中,我们将二进制常量 0b101010 还原为其十进制值 42。二进制常量在 JavaScript 中用于表示位操作或二进制数据。

🧩 evaluate 方法学习

evaluate 方法通常用于执行或计算表达式。它可以在 JavaScript 代码中动态执行表达式并返回结果。使用 eval 方法时要特别

小心,因为它可以执行任意代码,可能导致安全问题。

使用 eval 执行代码

const expression = '2 + 3 * 4';

// 使用 eval 执行表达式
const result = eval(expression);

console.log(result); // 输出: 14

在这个示例中,我们使用 eval 执行一个简单的数学表达式,并输出结果。eval 可以动态地执行任意 JavaScript 代码,因此使用时需谨慎。

使用 Function 构造函数

为了避免使用 eval,可以使用 Function 构造函数动态地创建和执行代码:

const expression = '2 + 3 * 4';

// 使用 Function 构造函数执行表达式
const result = new Function('return ' + expression)();

console.log(result); // 输出: 14

Function 构造函数提供了一种更安全的方式来动态执行代码,但仍然需要确保代码的安全性。

🔍 实战解 OB 高级混淆

在实际应用中,我们可能会遇到 JavaScript 代码的高级混淆技术,这些技术可以使代码难以理解。以下是如何解混淆高级混淆代码的示例:

解混淆示例

高级混淆技术可能涉及到复杂的函数调用、字符串加密等。以下是一个解混淆示例:

// 混淆代码示例
const obfuscatedCode = `
(function() {
    var _0x1a2b = ['\x66\x6F\x6F', '\x62\x61\x72', '\x62\x61\x7A'];
    var _0x1234 = function(_0x5678) {
        return _0x1a2b[_0x5678];
    };
    console.log(_0x1234(0));
})();
`;

// 还原混淆代码
const restoredCode = `
(function() {
    var _0x1a2b = ['foo', 'bar', 'baz'];
    var _0x1234 = function(index) {
        return _0x1a2b[index];
    };
    console.log(_0x1234(0));
})();
`;

console.log(restoredCode); // 输出: 还原后的代码

在这个示例中,混淆代码使用了十六进制表示的字符串和函数调用。我们将混淆代码还原为更易读的形式,使其更容易理解。

极验 JS 实战解混淆

极验验证码是一种常见的防护技术,它通过混淆 JavaScript 代码来防止自动化访问。以下是如何解混淆极验 JS 代码的示例:

// 极验混淆代码示例
const geetestObfuscatedCode = `
(function() {
    var _0x1a2b = ['\x62\x79\x70\x61\x73\x73', '\x6c\x6f\x67'];
    console.log(_0x1a2b[0]);
})();
`;
// 还原混淆代码
const geetestRestoredCode = `
(function() {
    var _0x1a2b = ['bypass', 'log'];
    console.log(_0x1a2b[0]);
})();
`;
console.log(geetestRestoredCode); // 输出: 还原后的代码
目录
相关文章
|
4月前
|
运维 持续交付 云计算
深入解析云计算中的微服务架构:原理、优势与实践
深入解析云计算中的微服务架构:原理、优势与实践
159 3
|
4月前
|
存储 缓存 安全
Java内存模型深度解析:从理论到实践####
【10月更文挑战第21天】 本文深入探讨了Java内存模型(JMM)的核心概念与底层机制,通过剖析其设计原理、内存可见性问题及其解决方案,结合具体代码示例,帮助读者构建对JMM的全面理解。不同于传统的摘要概述,我们将直接以故事化手法引入,让读者在轻松的情境中领略JMM的精髓。 ####
71 6
|
6天前
|
缓存 边缘计算 安全
阿里云CDN:全球加速网络的实践创新与价值解析
在数字化浪潮下,用户体验成为企业竞争力的核心。阿里云CDN凭借技术创新与全球化布局,提供高效稳定的加速解决方案。其三层优化体系(智能调度、缓存策略、安全防护)确保低延迟和高命中率,覆盖2800+全球节点,支持电商、教育、游戏等行业,帮助企业节省带宽成本,提升加载速度和安全性。未来,阿里云CDN将继续引领内容分发的行业标准。
49 7
|
6天前
|
机器学习/深度学习 人工智能 自然语言处理
DeepSeek 实践应用解析:合力亿捷智能客服迈向 “真智能” 时代
DeepSeek作为人工智能领域的创新翘楚,凭借领先的技术实力,在智能客服领域掀起变革。通过全渠道智能辅助、精准对话管理、多语言交互、智能工单处理、个性化推荐、情绪分析及反馈监控等功能,大幅提升客户服务效率和质量,助力企业实现卓越升级,推动智能化服务发展。
47 1
|
10天前
|
机器学习/深度学习 人工智能 监控
鸿蒙赋能智慧物流:AI类目标签技术深度解析与实践
在数字化浪潮下,物流行业面临变革,传统模式的局限性凸显。AI技术为物流转型升级注入动力。本文聚焦HarmonyOS NEXT API 12及以上版本,探讨如何利用AI类目标签技术提升智慧物流效率、准确性和成本控制。通过高效数据处理、实时监控和动态调整,AI技术显著优于传统方式。鸿蒙系统的分布式软总线技术和隐私保护机制为智慧物流提供了坚实基础。从仓储管理到运输监控再到配送优化,AI类目标签技术助力物流全流程智能化,提高客户满意度并降低成本。开发者可借助深度学习框架和鸿蒙系统特性,开发创新应用,推动物流行业智能化升级。
|
7天前
|
存储 自然语言处理 监控
深度解析淘宝商品评论API接口:技术实现与应用实践
淘宝商品评论API接口是电商数据驱动的核心工具,帮助开发者高效获取用户评价、画像及市场趋势。其核心功能包括多维度信息采集、筛选排序、动态更新、OAuth 2.0认证和兼容多种请求方式。通过该接口,开发者可进行商品优化、竞品分析、舆情监控等。本文详细解析其技术原理、实战应用及挑战应对策略,助力开启数据驱动的电商运营新篇章。
|
2月前
|
缓存 NoSQL JavaScript
Vue.js应用结合Redis数据库:实践与优化
将Vue.js应用与Redis结合,可以实现高效的数据管理和快速响应的用户体验。通过合理的实践步骤和优化策略,可以充分发挥两者的优势,提高应用的性能和可靠性。希望本文能为您在实际开发中提供有价值的参考。
65 11
|
2月前
|
Serverless 对象存储 人工智能
智能文件解析:体验阿里云多模态信息提取解决方案
在当今数据驱动的时代,信息的获取和处理效率直接影响着企业决策的速度和质量。然而,面对日益多样化的文件格式(文本、图像、音频、视频),传统的处理方法显然已经无法满足需求。
114 4
智能文件解析:体验阿里云多模态信息提取解决方案
|
3月前
|
机器学习/深度学习 人工智能 算法
深入解析图神经网络:Graph Transformer的算法基础与工程实践
Graph Transformer是一种结合了Transformer自注意力机制与图神经网络(GNNs)特点的神经网络模型,专为处理图结构数据而设计。它通过改进的数据表示方法、自注意力机制、拉普拉斯位置编码、消息传递与聚合机制等核心技术,实现了对图中节点间关系信息的高效处理及长程依赖关系的捕捉,显著提升了图相关任务的性能。本文详细解析了Graph Transformer的技术原理、实现细节及应用场景,并通过图书推荐系统的实例,展示了其在实际问题解决中的强大能力。
342 30
|
3月前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
225 14

热门文章

最新文章

推荐镜像

更多