文章总结: 本文详细讲解JavaScript中正确hook方法的两种场景:静态方法可直接覆盖原方法但需保存原始方法避免栈溢出;实例方法需通过修改原型链并使用apply/call确保this正确指向。文章通过代码示例演示hook实现原理,强调动态绑定、原型共享等机制,并推荐MDN作为学习资源。 综合评分: 78 文章分类: WEB安全,代码审计,逆向分析,安全开发,其他
如何 “正确” hook JS方法
原创
LLLibra146 LLLibra146
LLLibra146
2025年5月14日 08:00 北京
在小说阅读器读本章
去阅读
大家好,好几天没有更新文章了,其实是去了趟外地参加了同学的婚礼,正好赶上这几天工作比较忙没有抽出时间来,所以停了几天哈哈。不过今天我回来了,今天分享一下在 JS 中如何正确 hook 我们想要 hook 的方法。
hook是什么
先说 hook,hook 不是 JS 中的特例,hook 其实是一种方法,本质是在不修改源码的前提下,通过拦截函数调用来实现监控、修改或扩展程序行为的技术。这种方法很多语言中普遍存在,在 Python 叫装饰器,在 Java 中叫切面,大同小异。
在 JS 中,根据方法的类型可分为两类 hook 场景:
静态方法hook
静态方法是直接挂载在构造函数或类上的方法(如 Math.random()、Object.keys()),hook 时可以直接覆盖原方法,例如 hook Math 的 random 方法:
// 保存原始方法
const originalRandom = Math.random;
// 覆盖静态方法
Math.random = function() {
const result = originalRandom();
console.log(`Random value generated: ${result}`);
return result;
};
image-20250513211156743
hook 静态方法时可以直接覆盖原始方法,但是别忘了保存原始方法,不然在调用函数的时候就会进入死循环一直调用自己,导致的后果就是栈溢出,见下图:
image-20250513211716310
其他静态方法
静态方法还有很多,很多内置对象都有自己的静态方法:
image-20250513212036087
image-20250513212136206
image-20250513212232333
image-20250513212249643
可能有人会问上面的内容在哪里可以找到,这里推荐一个网站:MDN[1],可以把它当做学习 JS 的官方网站来用,想要知道某个对象的某个方法如何使用,都可以来这个网站上来查询,里面的内容相当丰富,随时打开网页就能看。
如何判断是否是静态方法
那如何判断一方法是否是静态方法呢?很简单,在浏览器中输入这个方法,看一下浏览器自动提示出来的方法中有没有想要的方法就知道了。例如:
image-20250513213151722
image-20250513213308156
会发现 JSON 有四个静态方法,Date 有三个静态方法,注意哦,name 和 length 是属性,不是静态方法。属性和方法如何区分这个就不用我说了吧,教大家一个小技巧。
image-20250513213438705
image-20250513213501175
在输入对应的方法或者属性名的时候,注意哦,我没有敲回车,方法下面会自动提示一个 f,意思就是当前输入的是一个方法,如果是一个属性,会自动显示属性的值。可以使用这种方法来判断当前输入的是一个属性还是方法。
实例方法 hook
对于实例方法,就不能直接覆盖原始方法了,在上面讲静态方法的时候也能看到,如果不实例化的话,根本看不到实例方法,重写也就无从谈起。
实例方法存在于对象原型链中(如 Array.prototype.push),需要通过修改原型实现:
// 保存原型方法
const originalPush = Array.prototype.push;
// 重写原型方法
Array.prototype.push = function(...items) {
console.log(`Pushing ${items.length} elements`);
return originalPush.apply(this, items);
};
如果要 hook 实例方法,那么就要通过 prototype 重写原型方法,因为 JS 的实例方法默认存储在原型对象(prototype)中,所有实例通过原型链共享这些方法,直接修改原型会影响所有已存在和未来的实例。
image-20250513214459923
image-20250513215420526
可能有小伙伴注意到了,除了打印日志之外,return 并没有直接调用原型方法,而是使用了原型方法的 apply 方法(其实这里使用 call 也是一样的,区别不大,先忽略),这是为什么呢?
apply 方法的作用
apply 方法是定义在了函数的原型上的,也就是说所有的函数都可以使用这个方法。apply 和 call 方法几乎相同,可以互相替换,不过要注意参数的传递方式有所区别。
image-20250513222902113
image-20250513220839724
image-20250513223306968
它的作用就是以给定的 this 值来调用该函数,说白了就是改变 this 的指向。那 this 的指向是什么意思呢?来看一个示例:
image-20250513223201503
先定义一个对象,它有一个 aa 方法和一个 pro 属性,在调用 aa 方法的时候输出 this 指向的 pro 属性,发现输出为 undefined,但是如果我传入 ob2 对象,它有 pro 属性,则可以正确的获取 pro 属性的值,值为 ob2 对象中的 pro 属性的值。
通过以上代码应该可以很好的理解 this 指向的意思了,如果在调用 apply 的时候不提供第一个参数,则会被替换为 undefined,如果提供了则 this 会指向提供的对象。
在实际 hook 实例方法的时候,因为不同的实例调用的都是相同的实例方法,这个时候如何针对不同的实例进行操作呢?这里就要用到 apply 方法的第一个参数 this ,那么问题又来了,为什么使用不同的实例调用同一个 push 方法,this 会默认指向不同的实例呢?
// 伪代码解释执行过程
const arr = [];
arr.push(1);
// 实际执行步骤:
// 1. 在 arr 实例上查找 push 方法
// 2. 发现 arr 自身没有 push,沿原型链找到 Array.prototype.push
// 3. 调用 push 方法时,this 被绑定为 arr 实例
Array.prototype.push.call(arr, 1); // 这是真实底层行为
因为 JS 帮我们进行了自动绑定,在调用 push 方法的时候底层会自动将当前的对象绑定到 this 中。
总结下来,为了可以正确的 hook 实例方法,有以下三种机制在起作用:
- 动态绑定:JS 中方法的
this始终指向调用该方法的对象实例。 - 原型共享:所有数组实例共享
Array.prototype上的方法,但每次调用时this会绑定到当前实例。 apply的作用:通过originalPush.apply(this, ...)确保原始方法操作正确的实例数据。
以上三种机制可以保证重写原型方法的时候透明的作用于所有的实例,而不用为每个实例维护单独的副本。
注:以上内容根据我当前所了解的知识整理而成,如有疏漏或错误请大家指出,谢谢大家。
总结
以上就是关于如何正确 hook JS 方法的所有内容了,可能有些内容大家都没咋见过,不过高级一点的混淆代码中大量运用了这些日常开发中不怎么会用到的知识点,这些 JS 的“底层逻辑”还是建议大家掌握一下,对于以后扣代码或者搞懂混淆代码很有好处。
参考资料
[1]
MDN: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/
最近一直有小伙伴问我有没有交流群,为了能让大家更好的交流,我组建了一个逆向交流群,想要进群的小伙伴可以在后台点击“联系我”菜单或者扫码,添加微信并且备注“交流群”,我会拉你进群。
推荐阅读:
一日一技:反爬虫的极致手段,几行代码直接炸了爬虫服务器
JS调试技巧:如何让时间和随机数“听你指挥”?
【Windows版】tcpdump + wireshark 联动 frida,实现APP无感抓取HTTPS数据包
AST 技巧:还在手动扣代码?AST技术帮你自动扣代码
AST 技巧:打印控制流混淆执行路径
JS逆向实战:加强版的 OB 混淆 AST 处理方法
alfred 使用技巧:一键自动格式化 JS 代码
JS逆向技巧:日志断点如何正确输出 JSON 而不报错
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:LLLibra146 LLLibra146 LLLibra146《如何 “正确” hook JS方法》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。











评论