> ## Content Index
> Fetch the complete content index at: https://blog.vercanti.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# JS 逆向调试技巧
- URL: https://blog.vercanti.com/js-ni-xiang-diao-shi-ji-qiao/
- Published: 2026-08-28T14:35:09.000Z
- Updated: 2026-08-28T14:58:11.000Z
- Description: 浏览器页面的执行流程决定了逆向的切入点： 核心目标是在「加密函数调用」这一环节断下，分析参数的生成逻辑。 在 Sources 面板中直接点击行号，最基础的断点方式。适合已知目标代码位置时使用。 右键行号 → Add conditional breakpoint，输入 JS 表达式，仅在条件为真时暂停。 在 Sources → XHR/fetch Breakpoints 中添加 URL 关键字（如 api、login），发起请求时自动在 send() 处断下。断下后查看 Call Stack 向上追溯加密逻辑。 操作步骤： 1. 打开 DevTools →
- Author: yellowdog
- Tags: js逆向, 技巧步骤

> 官方文档：<https://developer.chrome.com/docs/devtools/javascript/>  
> 适用场景：使用 Chrome DevTools 在浏览器中定位和分析加密参数生成逻辑

## 整体分析流程

浏览器页面的执行流程决定了逆向的切入点：

```
加载 HTML → 加载 JS → 运行初始化 → 用户触发事件
  → 调用加密函数 → XHR 发送请求 → 接收响应 → 解密渲染

```

核心目标是在「加密函数调用」这一环节断下，分析参数的生成逻辑。

---

## 断点类型

### 普通断点

在 Sources 面板中直接点击行号，最基础的断点方式。适合已知目标代码位置时使用。

### 条件断点

右键行号 → `Add conditional breakpoint`，输入 JS 表达式，仅在条件为真时暂停。

```javascript
// 示例：只在参数包含 "sign" 时断下
param.includes('sign')

```

### XHR/Fetch 断点

在 Sources → `XHR/fetch Breakpoints` 中添加 URL 关键字（如 `api`、`login`），发起请求时自动在 `send()` 处断下。断下后查看 **Call Stack** 向上追溯加密逻辑。

**操作步骤：**

1. 打开 DevTools → Sources → 右侧 `XHR/fetch Breakpoints`
2. 点击 `+` 输入 URL 关键字（留空匹配所有请求）
3. 触发目标请求，断点自动命中
4. 在 Call Stack 中从下往上逐帧分析

### 事件监听断点

Sources → `Event Listener Breakpoints`，展开对应事件类型（如 `Mouse` → `click`），触发该事件时自动断下。常用于定位按钮点击后的加密逻辑。

| 常用事件类型  | 场景          |
| ------- | ----------- |
| click   | 登录/提交按钮     |
| submit  | 表单提交        |
| keydown | 键盘输入触发      |
| load    | 页面加载完成后的初始化 |

### DOM 断点

右键目标 DOM 元素 → `Break on` → 选择类型：

- `subtree modifications`：子节点变化
- `attribute modifications`：属性变化
- `node removal`：节点被移除

适合追踪动态更新的验证码、token 等元素的生成来源。

### Logpoint（日志断点）

右键行号 → `Add logpoint`，在不暂停执行的情况下打印表达式值。适合生产环境或不方便暂停的场景。

```javascript
// 示例 logpoint 表达式
"sign 值:", sign, "timestamp:", Date.now()

```

---

## 调用堆栈分析

断点命中后，Call Stack 面板显示完整调用链。**从下往上**阅读，下方是最早的调用者，上方是最近的调用者。

分析技巧：

1. 跳过框架代码（`webpack`、`chunk` 等文件），关注业务逻辑文件。
2. 逐帧点击，观察右侧 **Scope** 面板中各层级的变量值。
3. 找到参数从「明文」变为「加密值」的那一帧，即加密函数所在位置。

---

## 快速定位加密函数

### 全局搜索关键字

`Ctrl + Shift + F`（全局搜索），搜索策略：

| 搜索词                 | 说明      |
| ------------------- | ------- |
| sign                | 签名参数名   |
| encrypt / cipher    | 通用加密函数名 |
| md5 / sha / aes     | 算法名称    |
| CryptoJS            | 常见加密库标志 |
| \\.encode\\( / btoa | 编码函数    |

### Initiator 堆栈

Network 面板中点击目标请求 → `Initiator` 标签页，直接显示请求发起的调用链，点击对应行跳转到源码。

### 搜索技巧

若直接搜索参数名找不到，尝试：

- 搜索参数名的部分字符串
- 搜索接口路径末段（如 `/api/login` → 搜 `login`）
- 搜索相邻参数名（和加密参数在同一个对象里的其他字段）

---

## 反调试对抗

### 无限 debugger

**原因**：网站在代码中插入循环触发的 `debugger`，打开 DevTools 就无法正常操作。

**对抗方法：**

| 方法      | 操作                                                       |
| ------- | -------------------------------------------------------- |
| 禁用断点    | DevTools 右上角 Deactivate breakpoints（蓝色圆圈图标）              |
| 替换函数    | Console 执行 Function.prototype.constructor = function(){} |
| 本地覆盖    | 下载 JS 文件，删除 debugger 相关代码，启用 Local Override              |
| Hook 绕过 | 使用反无限 debugger Hook 脚本（见 hook.md）                        |

### 开发者工具检测

常见检测手段：

- 监听 `F12`/`Ctrl+Shift+I` 键盘事件
- 检测 `window.outerHeight - window.innerHeight` 差值
- 通过 `console.log` 对象检测 DevTools 是否打开
- 利用计时差：`debugger` 在 DevTools 开启时执行时间远大于正常值

**对抗方法**：使用单独的 Chrome 配置文件，启动时带 `--disable-devtools-autoupdate`，或直接使用 Local Override 修改检测逻辑。

---

## 本地覆盖（Local Override）

适合：需要持久化修改 JS 文件（删除反调试、添加 Hook）的场景。

**操作步骤：**

1. DevTools → Sources → `Overrides` 标签
2. 点击 `+ Select folder for overrides`，选择本地目录并授权
3. Network 面板中右键目标 JS 文件 → `Save for overrides`
4. 在 Sources 中找到覆盖文件，直接编辑保存
5. 刷新页面，浏览器将加载本地版本而非网络版本

---

## 代码格式化

混淆或压缩过的代码可通过以下方式还原可读性：

- **DevTools 内置**：Sources 面板左下角 `{}` 按钮（Pretty Print）
- **在线工具**：`js-beautify`（支持本地 npm 安装）
- **命令行**：`npx prettier --write target.js`

---

## Scope 面板使用

断点暂停后，右侧 Scope 面板显示当前及上层作用域的所有变量。

- `Local`：当前函数局部变量
- `Closure`：闭包捕获的变量
- `Module`：模块级变量
- `Global`：全局变量

重点关注 `Closure` 层，加密 key、盐值等敏感数据常存储在闭包中。

---

## Watch 表达式

在 Watch 面板添加任意 JS 表达式，断点暂停时自动求值显示：

```javascript
// 示例
window._key
JSON.stringify(requestData)
btoa(signStr)

```

---

## 最佳实践

**XHR/Fetch 断点是首选入口**：在 DevTools Sources → Event Listener Breakpoints → XHR → `fetch` / `XMLHttpRequest` 勾选，下次请求时自动暂停，从调用栈往上追溯签名生成函数，比盲目搜索快 10 倍。

**条件断点过滤无关请求**：在断点上右键 → "Edit breakpoint" 添加条件（如 `url.includes('/api/sign')`），只在目标 URL 触发，避免其他请求干扰。

**Scope 面板追踪局部变量**：暂停后展开 Scope 面板（Local / Closure / Global），直接查看当前函数的所有变量值，比在 Console 输入变量名更全面，能看到对象的完整结构。

**`copy()` 函数复制复杂对象**：`copy(JSON.stringify(window._signData))` 将对象序列化后复制到剪贴板，方便粘贴到 Python 代码中测试，避免手动抄写长字符串。

**Overrides 持久化修改**：在 DevTools Sources → Overrides 本地覆盖 JS 文件，添加 `console.log` 或 `debugger`，即使刷新页面修改也会保留，适合需要多次调试的目标。

---

## 常见陷阱

### 陷阱：断点触发后堆栈太深找不到加密函数

**现象：** XHR 断点触发，Call Stack 有几十层，看不出哪里是签名逻辑。  
**原因：** 现代框架（Vue/React）的请求拦截器、Promise 链会在实际发送前插入多层调用。  
**解决：** 从最顶层（最近调用）往下查找包含 `sign`、`hash`、`token` 字样的函数；或在 Network 请求的 Initiator 列直接点击跳转到触发该请求的代码行。

### 陷阱：`debugger` 语句导致 DevTools 卡死循环

**现象：** 打开 DevTools 后页面不断触发 `debugger`，无法正常调试。  
**原因：** 网站注入了反调试代码，检测到 DevTools 后循环触发 `debugger` 语句。  
**解决：** 在 Sources 页右键 → "Never pause here" 跳过该 `debugger`；或在 DevTools 设置中禁用 JavaScript 断点，先找到反调试函数并 patch 后再重新开启。

### 陷阱：Hook 注入时机太晚，目标函数已执行

**现象：** 在 Console 注入 Hook 后触发请求，Hook 没有被调用。  
**原因：** 页面初始化时就执行了加密函数（如计算设备指纹），Console 注入时已错过。  
**解决：** 使用 Tampermonkey（`@run-at document-start`）或 DevTools Snippets 在页面加载最早期注入；或用 Overrides 直接修改 JS 源文件在函数定义处插入 Hook。

---

## 参见

[hook](https://blog.vercanti.com/hook-dai-ma-duan/)  
[RPC远程调用](https://blog.vercanti.com/rpc-yuan-cheng-diao-yong/)  
[混淆还原](https://blog.vercanti.com/hun-yao-huan-yuan/)  
[代码片段大全](https://blog.vercanti.com/js-ni-xiang-hook-yu-dai-ma-pian-duan-da-quan/)

适合追踪某个变量在不同断点间的变化。