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

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 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); // 输出: 还原后的代码
目录
相关文章
|
29天前
|
JavaScript 前端开发 Go
CSS 与 JS 对 DOM 解析和渲染的影响
【10月更文挑战第16天】CSS 和 JS 会在一定程度上影响 DOM 解析和渲染,了解它们之间的相互作用以及采取适当的优化措施是非常重要的。通过合理的布局和加载策略,可以提高网页的性能和用户体验,确保页面能够快速、流畅地呈现给用户。在实际开发中,要根据具体情况进行权衡和调整,以达到最佳的效果。
|
1月前
|
存储 JavaScript 前端开发
使用JavaScript构建动态交互式网页:从基础到实践
【10月更文挑战第12天】使用JavaScript构建动态交互式网页:从基础到实践
77 1
|
25天前
|
存储 前端开发 JavaScript
JavaScript垃圾回收机制深度解析
【10月更文挑战第21】JavaScript垃圾回收机制深度解析
99 59
|
13天前
|
编解码 前端开发 UED
探索无界:前端开发中的响应式设计深度解析与实践####
【10月更文挑战第29天】 本文深入探讨了响应式设计的核心理念,即通过灵活的布局、媒体查询及弹性图片等技术手段,使网站能够在不同设备上提供一致且优质的用户体验。不同于传统摘要概述,本文将以一次具体项目实践为引,逐步剖析响应式设计的关键技术点,分享实战经验与避坑指南,旨在为前端开发者提供一套实用的响应式设计方法论。 ####
39 4
|
15天前
|
安全 编译器 PHP
PHP 8新特性解析与实践应用####
————探索PHP 8的创新功能及其在现代Web开发中的实际应用
|
23天前
|
存储 安全 Java
系统安全架构的深度解析与实践:Java代码实现
【11月更文挑战第1天】系统安全架构是保护信息系统免受各种威胁和攻击的关键。作为系统架构师,设计一套完善的系统安全架构不仅需要对各种安全威胁有深入理解,还需要熟练掌握各种安全技术和工具。
67 10
|
23天前
|
存储 弹性计算 NoSQL
"从入门到实践,全方位解析云服务器ECS的秘密——手把手教你轻松驾驭阿里云的强大计算力!"
【10月更文挑战第23天】云服务器ECS(Elastic Compute Service)是阿里云提供的基础云计算服务,允许用户在云端租用和管理虚拟服务器。ECS具有弹性伸缩、按需付费、简单易用等特点,适用于网站托管、数据库部署、大数据分析等多种场景。本文介绍ECS的基本概念、使用场景及快速上手指南。
66 3
|
25天前
|
PHP 数据安全/隐私保护 开发者
PHP 7新特性解析与实践
【10月更文挑战第20天】本文将深入浅出地介绍PHP 7的新特性,包括性能提升、语法改进等方面。我们将通过实际代码示例,展示如何利用这些新特性优化现有项目,提高开发效率。无论你是PHP新手还是资深开发者,都能从中获得启发和帮助。
|
26天前
|
人工智能 资源调度 数据可视化
【AI应用落地实战】智能文档处理本地部署——可视化文档解析前端TextIn ParseX实践
2024长沙·中国1024程序员节以“智能应用新生态”为主题,吸引了众多技术大咖。合合信息展示了“智能文档处理百宝箱”的三大工具:可视化文档解析前端TextIn ParseX、向量化acge-embedding模型和文档解析测评工具markdown_tester,助力智能文档处理与知识管理。
|
1月前
|
前端开发 JavaScript
深入理解JavaScript中的事件循环(Event Loop):从原理到实践
【10月更文挑战第12天】 深入理解JavaScript中的事件循环(Event Loop):从原理到实践
36 1

推荐镜像

更多