JavaScript Hook 技术实战指南

1. 什么是 Hook 技术

Hook(钩子)技术是一种在程序运行时拦截和修改函数调用的方法。通过 Hook,我们可以在目标函数执行前后插入自定义代码,从而实现对函数行为的监控或修改。

Hook 技术的核心原理

  1. 函数重写:替换原始函数实现
  2. 控制流劫持:在函数执行前后插入自定义逻辑
  3. 透明代理:保持原始函数功能的同时增加额外行为

2. 现代 Hook 工具推荐

2.1 Tampermonkey(油猴)

Tampermonkey 是最流行的浏览器用户脚本管理器,支持 Chrome、Firefox、Edge 等主流浏览器。

安装方法

  1. Chrome 应用商店搜索 "Tampermonkey" 安装
  2. 或从官网下载:https://www.tampermonkey.net/

2.2 其他 Hook 工具

  • Frida:跨平台动态插桩工具
  • Xposed(Android):Android 运行时 Hook 框架
  • Cydia Substrate(iOS):iOS 平台的 Hook 框架

3. Tampermonkey 脚本开发

3.1 基础脚本结构

// ==UserScript==
// @name         示例Hook脚本
// @namespace    http://example.com/
// @version      1.0
// @description  用于演示Hook技术的示例脚本
// @author       YourName
// @match        https://example.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    
    // Hook逻辑代码
    console.log('脚本已加载');
})();

3.2 常用元数据说明

指令说明示例
@name脚本名称@name 登录Hook
@match生效URL模式@match https://.example.com/
@grant授权API@grant GM_xmlhttpRequest
@require引入外部JS@require https://code.jquery.com/jquery-3.6.0.min.js
@run-at执行时机@run-at document-end

4. JavaScript Hook 实战

4.1 基础Hook方法

function hook(object, attr) {
    const original = object[attr];
    object[attr] = function() {
        console.log('Hook捕获:', attr, '参数:', arguments);
        const result = original.apply(this, arguments);
        console.log('Hook结果:', result);
        return result;
    };
}

// 示例:Hook console.log
hook(window.console, 'log');

4.2 高级Hook模式

4.2.1 条件断点Hook

function conditionalHook(object, attr, condition) {
    const original = object[attr];
    object[attr] = function() {
        if (condition.apply(this, arguments)) {
            debugger; // 符合条件时触发断点
        }
        return original.apply(this, arguments);
    };
}

// 示例:当localStorage.setItem的key为'token'时断点
conditionalHook(window.localStorage, 'setItem', 
    (key) => key === 'token');

4.2.2 原型链Hook

function hookPrototype(className, methodName) {
    const original = className.prototype[methodName];
    className.prototype[methodName] = function() {
        console.log(`${className.name}.${methodName}被调用`, this);
        return original.apply(this, arguments);
    };
}

// 示例:Hook XMLHttpRequest的open方法
hookPrototype(XMLHttpRequest, 'open');

5. 实战案例:登录加密分析

https://login1.scrape.center/ 为例,分析登录时的token生成逻辑。

5.1 分析过程

  1. 观察网络请求:发现提交的是加密后的token
  2. 推测加密方式:token类似Base64编码
  3. 确定Hook点:JavaScript的btoa方法

5.2 Hook实现

// ==UserScript==
// @name         Login Token Hook
// @namespace    http://example.com/
// @version      1.0
// @description  Hook登录页面的token生成
// @match        https://login1.scrape.center/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    
    function hookBtoa() {
        const originalBtoa = window.btoa;
        window.btoa = function(input) {
            console.group('btoa Hook');
            console.log('输入:', input);
            console.trace('调用栈');
            debugger;
            
            const result = originalBtoa(input);
            
            console.log('输出:', result);
            console.groupEnd();
            return result;
        };
    }
    
    // 延迟执行确保页面加载完成
    setTimeout(hookBtoa, 1000);
})();

5.3 分析结果

通过Hook发现:

  1. 用户名和密码被JSON序列化
  2. 序列化结果通过btoa进行Base64编码
  3. 编码结果作为token提交

6. 进阶Hook技巧

6.1 异步函数Hook

function hookAsync(object, attr) {
    const original = object[attr];
    object[attr] = async function() {
        console.log(`开始执行 ${attr}`);
        const start = performance.now();
        
        try {
            const result = await original.apply(this, arguments);
            console.log(`${attr} 执行成功`, result);
            return result;
        } catch (error) {
            console.error(`${attr} 执行失败`, error);
            throw error;
        } finally {
            console.log(`${attr} 执行耗时: ${performance.now() - start}ms`);
        }
    };
}

// 示例:Hook fetch API
hookAsync(window, 'fetch');

6.2 属性访问Hook

function hookProperty(object, prop) {
    let value = object[prop];
    Object.defineProperty(object, prop, {
        get: function() {
            console.log(`获取 ${prop}:`, value);
            return value;
        },
        set: function(newValue) {
            console.log(`设置 ${prop}:`, newValue);
            value = newValue;
        },
        configurable: true
    });
}

// 示例:Hook localStorage
hookProperty(window, 'localStorage');

7. 安全与反Hook

现代网站常采用以下反Hook措施:

  1. 对象冻结Object.freeze()Object.seal()
  2. 配置检查:检查关键API是否被修改
  3. 代码混淆:增加分析难度

应对策略

// 解除对象冻结
function unfreeze(obj) {
    if (Object.isFrozen(obj)) {
        return JSON.parse(JSON.stringify(obj));
    }
    return obj;
}

// 绕过属性描述符检查
function deepHook(object, attr) {
    const original = object[attr];
    const newFunc = function() {
        console.log(`Deep Hook: ${attr}`);
        return original.apply(this, arguments);
    };
    
    Object.defineProperty(object, attr, {
        value: newFunc,
        writable: true,
        configurable: true,
        enumerable: true
    });
}

8. 最佳实践

  1. 精准匹配:使用@match限制脚本作用域
  2. 最小权限:只申请必要的@grant权限
  3. 错误处理:添加try-catch块防止脚本崩溃
  4. 性能优化:避免频繁的Hook操作影响页面性能
  5. 代码组织:复杂Hook逻辑拆分为多个函数

9. 总结

Hook技术是JavaScript逆向工程中的核心技能,通过本文我们学习了:

  • Tampermonkey脚本开发基础
  • 多种Hook实现模式
  • 实际案例分析
  • 进阶Hook技巧
  • 反Hook对抗方法

掌握这些技术后,你将能够更高效地分析现代Web应用的前端逻辑,为爬虫开发、安全测试等工作打下坚实基础。