在 JS逆向时如何 hook 属性?

大家好,昨天讲过了如何 hook JS 中的方法,今天来讲讲如何 hook JS 中的属性。

在 JS 逆向时,比较常用的属性我第一想到的就是 cookie 了,cookie 有读取和写入两个动作,部分反爬方案就是在访问的时候先返回一个加密后的 JS,JS 会计算一个 cookie 然后重定向到首页,并且带上刚才计算出来的 cookie。如果 cookie 有效则正常显示页面,否则提示失败。下面就以 cookie 来举例,讲一下如何 hook cookie。

hook 属性

在 hook cookie 之前,先来讲一下在 JS 中如何 hook 属性。hook 属性和 hook 方法有点不一样,方法可以被重写,但是属性不行。要 hook 属性,就离不开一个方法,它就是:Object.defineProperty

image-20250514200914004

image-20250514201137882

这里只展示部分使用方式,更多内容请大家查看官方文档

hook 属性原理

hook 属性的原理其实就是重新定义属性,使用 Object.defineProperty 可以到达这个目的。

对象中存在的属性描述符有两种主要类型:数据描述符和访问器描述符。数据描述符是一个具有可写或不可写值的属性。访问器描述符是由 getter/setter 函数对描述的属性。描述符只能是这两种类型之一,不能同时为两者。在 hook 中,访问器描述符用的比较多,因为一般 hook 都是针对设置或者访问操作进行 hook。

image-20250514203536987

看文档有点枯燥,来看一个案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const o = {}; // 创建一个新对象

// 通过 defineProperty 使用访问器属性描述符添加对象属性的示例
Object.defineProperty(o, "b", {
get() {
console.log('get...')
return this.value;
},
set(newValue) {
console.log('new value:'+newValue)
this.value = newValue;
},
enumerable: true,
configurable: true,
});

image-20250514212217293

定义一个 o 对象,然后使用 Object.defineProperty 方法重新定义 o 对象的 b 属性,并且配置访问器属性描述符,在对应的位置打印日志。可以看到在首次访问的时候,value 的值为 undefined,设置值后可以正常获取到 b 属性的值,并且在获取和设置的时候也可以正常打印日志。

数据描述符在 hook 中用的比较少,我这里就不多解释了,大家可以自行查看文档。

原理讲完了,现在使用刚才学到的知识来 hook 一下 cookie 试试。

在 hook cookie 之前,要先知道 cookie 是如何使用的,查一下 MDN 的文档:

image-20250514213814601

尝试设置 cookie:

image-20250514213936308

可以正常的打印出 cookie,说明访问和获取 cookie 的用法是没错的。

下面来尝试 hook cookie 的读取和设置操作,使用以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
let _cookie = document.cookie;
Object.defineProperty(document, 'cookie', {
configurable: true,
get() {
console.log('[GET] Cookie:', _cookie);
return _cookie;
},
set(value) {
console.log('[SET] Cookie:', value);
_cookie = value;
return value;
}
});

先保存之前的 cookie 值,然后在设置 cookie 的时候覆盖原有的值,并且在获取 cookie 值的时候返回 cookie 即可。

image-20250514214228398

为什么这里设置了两个 cookie,但是只获取到了一个呢?上面也说过了,cookie 是一个变量,第二次设置的 cookie 覆盖了第一次的值,所以只获取到了一个。

使用一个变量值来模拟 cookie 的设置和获取,实际的 cookie 设置和获取是比较复杂的,使用单个的变量无法完全模拟 cookie 的行为,但是加上 debugger 语句用来查找 cookie 的设置和获取动作的调用位置已经足够了。

打印堆栈

如果不想使用 debugger 语句,则可以使用 new Error().stack 来获取调用堆栈,一样可以知道各个方法的调用关系。

image-20250514220418989

这样就可以在不打断点的情况下,获取到 cookie 的调用位置了。

总结

以上内容使用 cookie 作为示例演示了 hook 对象属性的方法,对于其他对象的其他属性,都可以使用这种方法来实现 hook,具体如何操作就留给大家去实战了。

注:以上内容根据我当前所了解的知识整理而成,如有疏漏或错误请大家指出,谢谢大家。

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

本文作者:LLLibra146

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

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

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