JS 逆向完整技能图谱

JS 逆向完整技能图谱


一、基础知识篇

1. 浏览器开发者工具

功能 用途
Elements 查看/修改 DOM 结构
Console 执行 JS、查看输出
Network 抓包、分析请求参数
Sources 查看/调试 JS 代码
Application 查看 Cookie、Storage

2. 断点调试技巧

// 常用断点类型
1. 普通断点     - 点击行号
2. 条件断点     - 右键 → Add conditional breakpoint
3. XHR 断点     - 监听特定 URL 请求
4. DOM 断点     - 监听元素变化
5. 事件断点     - 监听 click、submit 等事件

示例:XHR 断点定位加密函数

Sources → XHR/fetch Breakpoints → 添加 URL 关键词(如 "api" 或 "sign")
→ 发起请求 → 自动断住 → 查看调用栈 Call Stack

二、代码分析篇

3. 搜索定位技巧

方法 快捷键/操作 适用场景
全局搜索 Ctrl+Shift+F 搜索关键词(sign、encrypt、token)
请求参数搜索 Network → 找到参数名 定位参数生成位置
Hook 搜索 注入代码拦截 动态定位
调用栈回溯 断点后看 Call Stack 找到函数调用链

4. Hook 技术 ⭐

原理:拦截/替换原生函数,监控调用

// Hook JSON.stringify - 监控所有 JSON 序列化
(function() {
    var stringify = JSON.stringify;
    JSON.stringify = function() {
        console.log('JSON.stringify 被调用:', arguments);
        console.trace(); // 打印调用栈
        return stringify.apply(this, arguments);
    };
})();

// Hook Cookie 设置
(function() {
    var cookieDesc = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie');
    Object.defineProperty(document, 'cookie', {
        set: function(val) {
            console.log('设置 Cookie:', val);
            debugger; // 自动断点
            return [cookieDesc.set.call](http://cookieDesc.set.call)(document, val);
        },
        get: function() {
            return [cookieDesc.get.call](http://cookieDesc.get.call)(document);
        }
    });
})();

// Hook setInterval/setTimeout - 定位定时器
(function() {
    var _setInterval = setInterval;
    setInterval = function(func, delay) {
        console.log('setInterval 被调用, 延迟:', delay);
        return _setInterval(func, delay);
    };
})();

5. 常用 Hook 注入方式

方式 工具 特点
Console 注入 浏览器控制台 简单快速,刷新失效
油猴脚本 Tampermonkey 持久化,自动注入
代理注入 Fiddler/Charles 可修改响应内容
浏览器插件 自己开发 最灵活

三、代码还原篇

6. 反混淆技术

常见混淆类型:

// 1. 变量名混淆
var _0x1a2b = function(_0x3c4d) { return _0x3c4d + 1; }

// 2. 字符串加密
var str = _0x5e6f('0x1'); // 实际是 "password"

// 3. 控制流平坦化
switch(state) {
    case 0: state = 3; break;
    case 3: state = 1; break;
    case 1: state = 2; break;
    // ...
}

// 4. 死代码注入
if (false) { /* 永远不执行的垃圾代码 */ }

// 5. eval 动态执行
eval(atob('YWxlcnQoMSk=')); // 解码后是 alert(1)

反混淆工具:

工具 用途
de4js 在线反混淆
JStillery AST 反混淆
AST Explorer 分析语法树
手动 + Console 最可靠的方式

示例:还原字符串加密

// 混淆代码中通常有个解密数组
var _0x5e6f = ['password', 'username', 'token'];

// 找到这个数组,在控制台执行
console.log(_0x5e6f('0x1')); // 输出真实字符串

7. AST(抽象语法树)还原

// 使用 Babel 解析和还原
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generator = require('@babel/generator').default;

// 解析混淆代码
const ast = parser.parse(obfuscatedCode);

// 遍历并修改 AST
traverse(ast, {
    // 还原字符串
    StringLiteral(path) {
        // 自定义还原逻辑
    },
    // 删除死代码
    IfStatement(path) {
        if (path.node.test.value === false) {
            path.remove();
        }
    }
});

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

四、环境模拟篇

8. 补环境

JS逆向中的"补环境"

补环境是指在 Node.js 或其他非浏览器环境中执行从网页提取的 JavaScript 代码时,模拟浏览器原生对象和 API 的过程。

为什么需要补环境?

当你从网站逆向出加密算法的 JS 代码后,想在本地运行它,会遇到一个问题:浏览器里有很多原生对象(如 windowdocumentnavigator 等),而 Node.js 没有这些。如果代码里用到了这些对象,直接运行就会报错。

常见需要补的环境对象
对象 说明
window 浏览器窗口对象
document DOM 文档对象
navigator 浏览器信息(userAgent 等)
location URL 信息
localStorage / sessionStorage 本地存储
XMLHttpRequest / fetch 网络请求
canvas 画布(常用于指纹检测)

示例 1:基础补环境框架
// 补 window 和 document
var window = global;
var document = {
    cookie: '',
    location: {
        href: 'https://example.com',
        hostname: '[example.com](http://example.com)',
        protocol: 'https:'
    },
    createElement: function(tag) {
        return {};
    },
    getElementById: function(id) {
        return null;
    }
};
window.document = document;

// 补 navigator
var navigator = {
    userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    platform: 'Win32',
    language: 'zh-CN'
};
window.navigator = navigator;

// 补 location
var location = document.location;
window.location = location;

// 然后在下面粘贴网站的加密JS代码...

示例 2:代理检测(Proxy 大法)

用 Proxy 自动检测代码访问了哪些未定义的属性:

function createEnvProxy(name) {
    return new Proxy({}, {
        get: function(target, prop) {
            console.log(`[检测] ${name}.${prop} 被访问`);
            if (!(prop in target)) {
                target[prop] = createEnvProxy(`${name}.${prop}`);
            }
            return target[prop];
        },
        set: function(target, prop, value) {
            console.log(`[检测] ${name}.${prop} 被设置为`, value);
            target[prop] = value;
            return true;
        }
    });
}

var window = createEnvProxy('window');
var document = createEnvProxy('document');
var navigator = createEnvProxy('navigator');

// 粘贴目标JS代码,运行后查看控制台输出
// 就知道需要补哪些属性了

示例 3:补 canvas 指纹

很多网站用 canvas 做浏览器指纹识别:

document.createElement = function(tag) {
    if (tag === 'canvas') {
        return {
            getContext: function(type) {
                return {
                    fillRect: function() {},
                    fillText: function() {},
                    measureText: function() {
                        return { width: 100 };
                    },
                    getImageData: function() {
                        return { data: new Uint8Array(10000) };
                    }
                };
            },
            toDataURL: function() {
                return 'data:image/png;base64,iVBORw0KGgo...'; // 固定值
            }
        };
    }
    return {};
};

补环境的一般流程

  1. 提取 JS 代码 — 从网页中找到加密/签名相关的代码
  2. 本地运行报错 — 直接跑会提示 xxx is not defined
  3. 逐个补齐 — 根据报错信息,依次补上缺少的对象和方法
  4. 使用 Proxy 辅助 — 用代理快速定位所有被访问的属性
  5. 验证结果 — 对比本地生成的结果和浏览器中的结果是否一致

常用工具/库

  • jsdom — 在 Node.js 中模拟 DOM 环境
  • vm2 — 安全的沙箱执行 JS
  • puppeteer — 直接用无头浏览器(不用补环境,但更慢)

补环境是 JS 逆向中最核心的技能之一,熟练掌握后可以脱离浏览器独立运行各种加密算法 🔧

9. 浏览器指纹对抗

// Canvas 指纹
HTMLCanvasElement.prototype.toDataURL = function() {
    return 'data:image/png;base64,固定值...';
};

// WebGL 指纹
WebGLRenderingContext.prototype.getParameter = function(param) {
    if (param === 37445) return 'Intel Inc.';  // VENDOR
    if (param === 37446) return 'Intel Iris OpenGL'; // RENDERER
    return [originalGetParameter.call](http://originalGetParameter.call)(this, param);
};

// AudioContext 指纹
AudioContext.prototype.createOscillator = function() {
    return { /* 伪造的返回值 */ };
};

// 字体指纹
// 通过 CSS @font-face 检测,需要模拟特定字体列表

五、算法还原篇

10. 常见加密算法识别

特征 算法
32位十六进制 MD5
40位十六进制 SHA1
64位十六进制 SHA256
Base64 格式 可能是 AES/DES 加密后的
很长的数字 可能是 RSA
= 结尾 Base64 编码

11. 算法还原示例

// 识别 MD5
function md5(string) {
    // 看到 0x67452301, 0xefcdab89 等魔数 → MD5
    var a = 0x67452301;
    var b = 0xefcdab89;
    var c = 0x98badcfe;
    var d = 0x10325476;
    // ...
}

// 识别 AES
// 看到 S-box (0x63, 0x7c, 0x77, 0x7b...) → AES
var Sbox = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5...];

// 识别 Base64
// 看到 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

12. 自定义算法分析

// 示例:某网站的签名算法
function getSign(params, timestamp) {
    var str = '';
    // 1. 参数排序拼接
    Object.keys(params).sort().forEach(function(key) {
        str += key + '=' + params[key] + '&';
    });
    // 2. 加上时间戳和密钥
    str += 'timestamp=' + timestamp + '&key=secretKey123';
    // 3. MD5
    return md5(str);
}

// 逆向时需要:
// 1. 找到这个函数
// 2. 确定参数排序规则
// 3. 找到密钥 (secretKey123)
// 4. 确定 MD5 还是其他哈希

六、高级技巧篇

13. RPC(远程过程调用)

原理:直接调用浏览器里的函数,不用补环境

// 浏览器端 - 注入 WebSocket 服务
var ws = new WebSocket('ws://[localhost:8080](http://localhost:8080)');
ws.onmessage = function(e) {
    var data = JSON.parse([e.data](http://e.data));
    // 直接调用页面里的加密函数
    var result = window.encrypt(data.params);
    ws.send(JSON.stringify({id: [data.id](http://data.id), result: result}));
};
# Python 端 - 调用
import websocket
import json

ws = websocket.WebSocket()
ws.connect('ws://[localhost:8080](http://localhost:8080)')
ws.send(json.dumps({'id': 1, 'params': 'test'}))
result = json.loads(ws.recv())
print(result)

14. 无头浏览器方案

# Playwright 示例
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = [browser.new](http://browser.new)_page()
    page.goto('https://example.com')
    
    # 直接在浏览器里执行 JS
    sign = page.evaluate('window.getSign("test")')
    print(sign)
    
    # 或者拦截请求
    page.on('request', lambda req: print(req.url, [req.post](http://req.post)_data))

15. WASM 逆向

// 导出 WASM 函数列表
WebAssembly.instantiate(wasmCode).then(module => {
    console.log(Object.keys(module.instance.exports));
});

// 工具
// - wasm2wat: 转成文本格式
// - Ghidra: 反编译 WASM
// - Chrome DevTools: 可以调试 WASM

七、实战流程总结

┌─────────────────────────────────────────────────────────┐
│                    JS 逆向完整流程                        │
├─────────────────────────────────────────────────────────┤
│  1. 抓包分析                                             │
│     └─ 找到加密参数 (sign, token, _signature 等)          │
│                          ↓                              │
│  2. 定位加密函数                                         │
│     ├─ 全局搜索关键词                                    │
│     ├─ XHR 断点 + 调用栈                                 │
│     └─ Hook 拦截                                        │
│                          ↓                              │
│  3. 分析加密逻辑                                         │
│     ├─ 单步调试                                         │
│     ├─ 打印中间变量                                      │
│     └─ 识别算法类型                                      │
│                          ↓                              │
│  4. 提取/还原代码                                        │
│     ├─ 直接复制 (简单情况)                               │
│     ├─ 反混淆 (混淆代码)                                 │
│     └─ 算法重写 (复杂情况)                               │
│                          ↓                              │
│  5. 本地运行                                            │
│     ├─ 补环境 (Node.js)          ← 最常用               │
│     ├─ RPC (浏览器直接调用)                              │
│     └─ 无头浏览器 (兜底方案)                             │
│                          ↓                              │
│  6. 集成到爬虫                                          │
│     └─ Python 调用 Node.js / 本地服务                    │
└─────────────────────────────────────────────────────────┘

八、学习资源推荐

类型 资源
练习平台 猿人学、极验 Demo、各种 CTF
工具 Fiddler、Charles、mitmproxy
浏览器 Chrome DevTools(必须精通)
社区 吾爱破解、52pojie、看雪论坛

学习建议:从 Hook → 断点调试 → 补环境 这条主线入手,覆盖 80% 场景后,再学反混淆和高级技巧!

💬 评论

0/200