JS逆向之快速定位关键参数通用hook脚本

大家好,在 JS逆向时,首先需要做的就是定位加密参数的生成位置,然而在大量的 JS 中找到它不是很容易。在定位过程中,经常用到的一个技术就是 hook 技术,今天分享几个可以快速定位 JS 逆向加密参数的通用 hook 脚本。

油猴脚本框架

以下所有的脚本都要放到油猴脚本中使用,为了简化代码,这里先给出油猴脚本的框架,后续在进行 hook 的时候,只需要在框架中添加相应的 hook 代码即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ==UserScript==
// @name demo
// @namespace Violentmonkey Scripts
// @match https://xxxx.xxxx-xxxx.com/*
// @grant none
// @version 1.0
// @author -
// @description 2025/2/25 21:20:14
// @run-at document-start
// ==/UserScript==
(function () {

//这里添加所需的 hook 代码

})();

别忘了修改上面的 @match 注释中的网址,此网址是 hook 脚本运行的网站,例如想要 hook 百度,填写 // @match https://www.baidu.com/* 即可。可以按需修改其他注释,但是 @run-at 一定要是 document-start,这样才可以在网页加载前执行 hook 代码,hook 才能正常生效。

定位 json 序列化反序列化

json 数据是在逆向中经常遇到的,分享一个 hook json 序列化和反序列化过程的脚本,可以在遇到请求和响应都是 json 数据的情况下快速定位 json 的序列化和反序列化的位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Hook JSON.stringify
const originalStringify = JSON.stringify;
JSON.stringify = function(params) {
console.log("[Hook] JSON.stringify 参数:", params);
// 检测关键加密参数(如token、sign等)
if (typeof params === 'object' && params !== null) {
if ('encryptedData' in params || 'token' in params) {
debugger; // 触发断点
}
}
return originalStringify.apply(this, arguments);
};

// Hook JSON.parse
const originalParse = JSON.parse;
JSON.parse = function(text) {
console.log("[Hook] JSON.parse 输入数据:", text);
// 检测解密后的响应数据
if (typeof text === 'string' && text.includes('{')) {
try {
const parsed = originalParse(text);
if ('data' in parsed && parsed.data.length > 100) {
debugger; // 触发断点
}
} catch (e) {}
}
return originalParse.apply(this, arguments);
};

image-20250309214924820

使用结果如图所示,在请求和响应的时候都会打印出对应的数据,这个时候如果想要打断点的话,直接点击图片上的蓝色脚本在 hook 代码中打断点即可,向上查找调用栈即可找到 json 数据生成的位置。

cookie 在逆向中也经常遇到,一般情况下会在本地通过 JS 生成一段 cookie,提交请求的时候发送给服务端验证,如果验证不通过,则拒绝。这个时候往往要先定位特定的 cookie 是在哪里生成的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// ====== 核心:重写 document.cookie 的 getter/setter ======
const cookieDesc = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie') || {
configurable: true,
enumerable: true
};

Object.defineProperty(Document.prototype, 'cookie', {
configurable: cookieDesc.configurable,
enumerable: cookieDesc.enumerable,
get: function() {
const cookies = cookieDesc.get ? cookieDesc.get.call(this) : this._cookie || '';
// 监控所有读取操作
if (/(token|session|auth)/i.test(cookies)) {
console.log('[Cookie Get]', cookies);
}
return cookies;
},
set: function(value) {
// 监控所有写入操作
console.log('[Cookie Set]', value);
if (/(token=|session=|sign=)/i.test(value)) {
console.trace('关键Cookie设置');

}
return cookieDesc.set ? cookieDesc.set.call(this, value) : (this._cookie = value);
}
});

image-20250309221103919

手动获取 token 并且设置 token,可以看到均正常 hook 到了 cookie 操作并且打印了日志。

定位 eval 执行代码

eval 也是 JS逆向中常用的方式,将代码进行混淆加密后转成字符串形式,在运行时使用 eval 动态的加载并执行,这时可以通过 hook eval 函数的方式来定位动态加载的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 配置检测关键词(支持正则表达式)
const TARGET_PATTERN = /login|encrypt|signature/; // ← 修改这里

// 保存原生eval
const _nativeEval = window.eval;

// 重定义eval
window.eval = function(code) {
console.log("[eval监控] 捕获关键代码:\n", code.slice(0, 200) + "...");
// 调试触发逻辑
if (TARGET_PATTERN.test(code)) {
console.log("[eval监控] 捕获关键代码:\n", code.slice(0, 200) + "..."); // 截取前200
debugger; // 自动断点
}

// 执行原始eval
return _nativeEval.call(window, code);
};

// 伪装成原生eval
Object.defineProperty(window.eval, 'toString', {
value: () => 'function eval() { [native code] }',
writable: false,
configurable: false
});

image-20250309222317806

可以看到,在执行 eval 的时候,会自动打印出所有 eval 执行的代码。

定位 Function 执行

Function 是 JS 中动态创建函数的一种方式,它是所有函数的构造函数。在 JS逆向中,很多时候会通过新建 Function 对象的方式来新建一个函数,从而在搜索某个加密函数的时候会搜索不到,因为它不是静态的,而是动态创建的。

它与 eval 的区别如下:

特性Functioneval
作用域在全局作用域执行在当前作用域执行
返回值返回新函数返回最后一条语句的结果
安全性相对隔离(但仍不安全)更高风险
典型应用场景动态生成函数动态执行代码片段

Function 用法示例:

1
2
3
const code = 'return Date.now().toString(32)';
const getDynamicValue = new Function(code);
console.log(getDynamicValue()); // 输出类似 "1smn3v"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function hookFunction(func) {
return new Proxy(func, {
construct(target, args) {
console.log(`拦截构造函数: ${target.name}, 参数: ${args}`);
return Reflect.construct(target, args);
},
apply(target, thisArg, args) {
console.log(`拦截函数调用: ${target.name}, 参数: ${args}`);
return Reflect.apply(target, thisArg, args);
}
});
}

// Hook 所有通过 Function 创建的函数
window.Function = hookFunction(window.Function);

image-20250309222947310

使用代理的方式来拦截针对 Function 的调用,因为一般在使用 Function 的时候,会遇到比较强的校测,重写函数可能会被检测到,使用代理的隐蔽性更强,不会轻易被检测到。

定位 Ajax 请求

定位 Ajax 请求不使用 hook,只需要在浏览器中添加 XHR 断点即可。

image-20250309224142111

可以选择对所有的 Ajax 请求或者某个含有特定字符串的请求打断点,这样在请求发起时,会自动断在 send 函数上。

image-20250309224421605

如果想要快速定位某个特定的 cookie 是从哪个请求生成的,其实也可以不用写 hook 代码,直接点点鼠标就可以了。

来看方法:

image-20250309225314678

image-20250309225419624 例如想要快速定位这个 sign 是在哪个请求生成的,网络请求有这么多,这个网站比较简单,如果是复杂的网站可能会达到几十个之多。

image-20250309225338635

只需要在 cookie 上面点击右键,然后点显示涉及此 cookie 的请求,就会自动跳转到 network 选项卡,并且将 cookie 中有 sign 的请求全部都过滤出来,此时只要看第一个请求就可以了。

image-20250309225630612

此方法其实就是 Chrome 自动添加了过滤条件,过滤出所有涉及到 cookie 的请求,对于快速定位 cookie 生成位置还是很有用的。

总结

以上就是本次分享的所有 hook 脚本,由于每个网站的加密内容都不同,大家可以根据上面的代码自行编写其他 hook 操作。

本文章首发于个人博客 LLLibra146’s blog

本文作者:LLLibra146

更多文章请关注公众号 (LLLibra146):LLLibra146

版权声明:本博客所有文章除特别声明外,均采用 © BY-NC-ND 许可协议。非商用转载请注明出处!严禁商业转载!

本文链接
https://blog.d77.xyz/archives/e62ce8ac.html