├── .github
└── workflows
│ └── deploy.yml
├── .gitignore
├── LICENSE
├── README.assets
├── Snipaste_2024-10-26_02-28-04.png
├── image-20231030132026541-7614065.png
├── image-20241016230653669.png
├── image-20241016231143315.png
└── jQuery-hook
├── README.md
├── README_en.md
├── jQuery-hook.js
├── jQuery-hook.pdf
├── markdown-images
└── README_images
│ ├── 0e8288d7.png
│ ├── 160b9e7a.png
│ ├── 3409d649.png
│ ├── 69f2a236.png
│ ├── 90f8932a.png
│ ├── a39e269d.png
│ ├── bb826340.png
│ ├── d4bf6528.png
│ └── f12e305d.png
├── package-lock.json
├── package.json
├── tools
├── README.md
└── gen-fuck-jquery-code.html
└── website
├── images
└── logo.png
└── index.html
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: Deploy to GitHub Pages
2 |
3 | on:
4 | push:
5 | branches:
6 | - main # 触发分支
7 |
8 | jobs:
9 | deploy:
10 | runs-on: ubuntu-latest
11 | permissions:
12 | contents: write
13 | steps:
14 | - name: Checkout code
15 | uses: actions/checkout@v3
16 |
17 | - name: Deploy to GitHub Pages
18 | uses: peaceiris/actions-gh-pages@v3
19 | with:
20 | github_token: ${{ secrets.GITHUB_TOKEN }}
21 | publish_dir: ./website
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .DS_Store
3 | node_modules
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 CC11001100
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.assets/Snipaste_2024-10-26_02-28-04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JSREI/jQuery-hook/55345a397910c8aed45e25ebb4dc387610bfb5a7/README.assets/Snipaste_2024-10-26_02-28-04.png
--------------------------------------------------------------------------------
/README.assets/image-20231030132026541-7614065.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JSREI/jQuery-hook/55345a397910c8aed45e25ebb4dc387610bfb5a7/README.assets/image-20231030132026541-7614065.png
--------------------------------------------------------------------------------
/README.assets/image-20241016230653669.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JSREI/jQuery-hook/55345a397910c8aed45e25ebb4dc387610bfb5a7/README.assets/image-20241016230653669.png
--------------------------------------------------------------------------------
/README.assets/image-20241016231143315.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JSREI/jQuery-hook/55345a397910c8aed45e25ebb4dc387610bfb5a7/README.assets/image-20241016231143315.png
--------------------------------------------------------------------------------
/README.assets/jQuery-hook:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # jQuery Hook
2 |
3 | 官网:https://jsrei.github.io/jQuery-hook/
4 |
5 | GitHub Repository: https://github.com/JSREI/jQuery-hook
6 |
7 | 简体中文 | [English](./README_en.md)
8 |
9 |               
10 |
11 | 
12 |
13 | # 一、此脚本的作用是什么?
14 |
15 | 用于快速定位使用`jQuery`绑定到`DOM`元素上的事件的代码的真实位置,辅助逆向分析。
16 |
17 | # 二、为什么会有这个?
18 |
19 | `jQuery`曾经引领过一个时代,虽然现已没落,但是很多遗留下来的系统都用到了`jQuery`,其市场还是比较大的, 而笔者在做`js`逆向的时候发现用`Chrome`自带的开发者工具查看元素绑定事件的功能,看到的值是被`jQuery`包裹着一层的代码:
20 | 
21 | 这是因为`jQuery`在原生的`DOM`元素事件机制上自己定义了一套事件管理机制,这套机制为开发者带来了便利,比如可以很方便的对某个`DOM`元素的相同事件绑定多个回调方法,但同时也为逆向带来不方便,逆向者不太容易能定位到`DOM`事件代码逻辑真实代码所在的位置,而这个小脚本就是解决这个问题的,**提供了一种简单有效的方法能够快速定位到`jQuery DOM`元素事件对应的真实代码的位置**。
22 |
23 | # 三、安装
24 |
25 | ## 3.1 从油猴商店安装(推荐方式)
26 |
27 | 此脚本已在油猴商店上架,点击下面的链接,直接在油猴商店安装快捷方便,并且后续此脚本有版本更新油猴插件会自动提示升级:
28 |
29 | [https://greasyfork.org/zh-CN/scripts/435556-jquery-hook](https://greasyfork.org/zh-CN/scripts/435556-jquery-hook)
30 |
31 | ## 3.2 手动安装
32 |
33 | 手动复制此仓库的`main`分支的根目录下的`jQuery-hook.js`文件到您自己的油猴插件新建一个脚本粘贴代码即可:
34 |
35 | ```
36 | https://github.com/JSREI/jQuery-hook/blob/main/jQuery-hook.js
37 | ```
38 |
39 | 注意此种方式后续此脚本有版本更新油猴插件不会自动提醒升级,不过您可以`star`/`watch`本仓库关注后续更新。
40 |
41 | # 四、使用案例
42 |
43 | 注意:示例网站已经无法访问,可以访问靶场练习,请移步此篇文章:https://github.com/JSREI/jQuery-hook/tree/main/goat/form-submit-sign
44 |
45 | 随便找一个使用`jQuery`开发的网站,比如这个:
46 |
47 | [http://wap.wfu.edu.cn:8001/authz/login/slogin](http://wap.wfu.edu.cn:8001/authz/login/slogin)
48 |
49 | 尝试触发登录请求,会发现它发出的登录请求中密码对应的参数`mm`是被加密传输的:
50 |
51 | 
52 | 通过这里可以看到,发出的请求是`doc`类型的请求,看起来是使用表单提交的方式发送的请求:
53 | 
54 | 那么按照我们以往的js逆向经验来推测:
55 |
56 | - 应该是单击“登录”按钮的时候触发了按钮绑定的`click`事件
57 | - `click`事件的`js`代码获取密码对应的名为`mm`的`input`里的明文密码的值,进行加密得到密码的加密值
58 | - 然后更新密码的`mm input`的值为加密后的密码的值
59 | - 然后提交表单,此时请求中的密码参数`mm`就是被加密后的值了
60 |
61 | 当然上面都是我们基于经验脑补出来的过程,具体还是得找到事件代码看一眼才靠谱,在`Chrome`中使用查看元素功能选中这个登录按钮,左侧会自动切换到`Elements`标签并定位到`DOM`元素的代码位置,然后在右侧切换到`Event Listener`标签查看此元素绑定的事件,发现是有一个`click`事件,只是代码位置是在`jQuery`里,不必在意这些细节,大喜,于是单击跟进去这个代码位置:
62 |
63 | 
64 | 然后会陷入到`jQuery`的闭包中无法自拔,喜早了,这是因为`jQuery`自己封装了一套事件机制不太容易逆向:
65 | 
66 | 此时就是这个脚本发挥作用的时候了,油猴插件开启本脚本`jQuery hook`,刷新页面重新加载以便脚本能够注入到页面,如果加载成功控制台会有提示:
67 |
68 | 
69 | 再次对登录按钮检查元素,不必理睬右边`Event Listener`里`Chrome`给出的的绑定事件, 注意左边`Elements`面板中使用`jQuery`绑定的事件都已经以元素属性的方式展示出来了:
70 |
71 | 
72 | 比如:
73 |
74 | ```text
75 | cc11001100-jquery-click-event-function="cc11001100_click_5"
76 | ```
77 | 表示此元素上有一个click类型的事件,这个事件所关联的回调函数的代码已经赋值到这个名称的全局变量上:
78 | ```text
79 | cc11001100_click_5
80 | ```
81 | 然后我们在开发者工具中切换到`console`,粘贴这个全局变量的名称`cc11001100_click_5`并回车,查看它的内存地址:
82 | 
83 | 然后单击内存地址跟进去,就直接定位到了登录按钮的`click`事件所绑定的代码:
84 | 
85 | 往下拉,可以看到参数`mm`的加密方式:
86 |
87 | 
88 |
89 | 至此梳理完毕,以比较科学的方式很轻松就定位到了加密位置,逆向不是体力活,这才是逆向的乐趣啊!
90 |
91 | # 五、原理概述
92 | 通过`hook` `jQuery`的`$.fn`原型上的一些设置事件的方法来实现,目前支持的`jQuery`事件方法:
93 |
94 | ```text
95 | "click",
96 | "dblclick",
97 | "blur",
98 | "change",
99 | "contextmenu",
100 | "error",
101 | "focus",
102 | "focusin",
103 | "focusout",
104 | "hover",
105 | "holdReady",
106 | "proxy",
107 | "ready",
108 | "keydown",
109 | "keypress",
110 | "keyup",
111 | "live",
112 | "load",
113 | "mousedown",
114 | "mouseenter",
115 | "mouseleave",
116 | "mousemove",
117 | "mouseout",
118 | "mouseover",
119 | "mouseup"
120 | "on"
121 | ```
122 |
123 | 元素每被设置一个事件就会多一个属性,复制这个属性的值,对应着一个全局变量,在`console`上粘贴,这个就是此元素的此事件对应着的真实代码位置。
124 |
125 | # 六、问题反馈
126 |
127 | - 如果发现有`Hook`不到的情况,请在[issue](https://github.com/JSREI/jQuery-hook/issues)中反馈
128 | - 任何诉求与建议,请在[issue](https://github.com/JSREI/jQuery-hook/issues)中反馈
129 | - 如果您觉得此项目有任何可改进的地方(不仅局限于文档、代码)并且懒得说一堆话解释想直接上手改,欢迎提`pr`
130 |
131 | # 七、TODO
132 |
133 | - 对`jQuery`发出的请求进行监控和`Hook`
134 | - 如果希望有其它功能在[issue](https://github.com/CC11001100/jQuery-hook/issues)区留言讨论
135 |
136 |
137 | # 八、Contributors
138 |
139 |
140 |
141 | # 九、Star History
142 |
143 |
144 |
145 | # 十、逆向技术交流群
146 |
147 | 扫码加入逆向技术交流群:
148 |
149 |
150 |
151 | 如群二维码过期,可以加我个人微信,发送【逆向群】拉你进群:
152 |
153 |
154 |
155 | [点此](https://t.me/jsreijsrei)或扫码加入TG交流群:
156 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/README_en.md:
--------------------------------------------------------------------------------
1 | # jQuery Hook
2 |
3 | GitHub Repository: https://github.com/JSREI/jQuery-hook
4 |
5 | [简体中文](./README.md) | English
6 |
7 |
8 |               
9 | 
10 |
11 | # I. What is the purpose of this script?
12 |
13 | It is designed to swiftly identify the actual code location that binds events to `DOM` elements using `jQuery`, facilitating reverse engineering analysis.
14 |
15 | # II. Why does this exist?
16 |
17 | Though `jQuery` has seen better days, it still persists in many legacy systems, maintaining a significant market share. During the author's journey through `js` reverse engineering, it was observed that the Chrome developer tools, when used to inspect element event bindings, reveal code encapsulated by `jQuery`:
18 | 
19 | This封装 occurs because `jQuery` has superimposed its own event management system over the native `DOM` element event mechanism. While this system offers developers conveniences, such as the ability to easily attach multiple callback methods to the same event of a `DOM` element, it poses challenges for reverse engineering efforts. It's not straightforward for reversers to pinpoint the actual code location of `DOM` event logic. This script addresses this issue, **offering a straightforward and potent approach to swiftly identify the true code location associated with `jQuery DOM` element events**.
20 |
21 | # III. Installation
22 |
23 | ## 3.1 Install from the Greasy Fork Store (Recommended Method)
24 |
25 | The script is readily available on the Greasy Fork Store. Click the link below to install it directly from the store with ease and speed. Additionally, should the script be updated in the future, the Greasy Fork extension will automatically notify you to upgrade.
26 |
27 | [Install jQuery Hook from Greasy Fork](https://greasyfork.org/zh-CN/scripts/435556-jquery-hook)
28 |
29 | ## 3.2 Manual Installation
30 |
31 | Copy the `jQuery-hook.js` file manually from the root directory of the `main` branch of this repository into your Greasemonkey plugin to create a new script and paste the code.
32 |
33 | ```
34 | [Download jQuery-hook.js](https://github.com/JSREI/jQuery-hook/blob/main/jQuery-hook.js)
35 | ```
36 |
37 | Please be aware that with this approach, the Greasemonkey plugin will not automatically notify you of updates to this script. However, you can `star`/`watch` this repository to stay informed about future updates.
38 |
39 | # 4. Usage Example
40 |
41 | Locate any website developed with `jQuery`, for instance:
42 |
43 | [Example Website](http://wap.wfu.edu.cn:8001/authz/login/slogin)
44 |
45 | Initiate a login request, and you will notice that the password parameter `mm` in the login request is encrypted during transmission.
46 |
47 | 
48 | From this perspective, it's evident that the request sent is of the `doc` type, seemingly dispatched via the form submission method.
49 | 
50 | Drawing on our past experience with js reverse engineering, we can deduce:
51 |
52 | - The `click` event bound to the "Login" button is likely triggered upon clicking the button.
53 | - The `click` event's `js` code retrieves the plaintext password value from the `input` named `mm`, encrypts it to obtain the encrypted password value.
54 | - It then updates the value of the `mm input` to the encrypted password value.
55 | - The form is subsequently submitted, and the password parameter `mm` in the request is now the encrypted value.
56 |
57 | Of course, the above is all speculative based on experience; the actual event code must be examined for certainty. Using the element inspection feature in `Chrome` to select the login button, the left side automatically switches to the `Elements` tab and locates the code position of the `DOM` element. Then, switch to the `Event Listener` tab on the right to view the events bound to this element and discover a `click` event, albeit with the code position within `jQuery`. Pay no mind to these details, rejoice, and click through to this code location:
58 |
59 | 
60 | Then you find yourself ensnared in `jQuery`'s closure, prematurely excited, because `jQuery` has encapsulated its own event mechanism, which is not easily reversible:
61 | 
62 | This is where the script comes into play. Enable the Greasemonkey plugin with this script `jQuery hook`, refresh the page to reload so that the script can be injected into the page. If the loading is successful, a prompt will appear in the console:
63 |
64 | 
65 | Inspect the login button again, disregarding the bound events provided by `Chrome` in the `Event Listener` on the right. Note that the events bound by `jQuery` in the `Elements` panel on the left are now displayed as element attributes:
66 |
67 | 
68 | For example:
69 |
70 | ```text
71 | cc11001100-jquery-click-event-function="cc11001100_click_5"
72 | ```
73 | This indicates that there is a click event on this element, and the code associated with this event's callback function has been assigned to a global variable with this name:
74 | ```text
75 | cc11001100_click_5
76 | ```
77 | Then, switch to the `console` in the developer tools, paste the name of this global variable `cc11001100_click_5`, and press enter to view its memory address:
78 | 
79 | Click the memory address to navigate directly to the code bound to the `click` event of the login button:
80 | 
81 | Scroll down to see the encryption method of the parameter `mm`:
82 |
83 | 
84 |
85 | With this, the process is clear. We have easily located the encryption position in a more scientific manner. Reverse engineering is not a laborious task; this is the joy of reverse engineering!
86 |
87 | # V. Principle Overview
88 | It is implemented by `hooking` some event setting methods on the prototype of `jQuery`'s `$.fn`. The currently supported `jQuery` event methods are:
89 |
90 | ```text
91 | "click",
92 | "dblclick",
93 | "blur",
94 | "change",
95 | "contextmenu",
96 | "error",
97 | "focus",
98 | "focusin",
99 | "focusout",
100 | "hover",
101 | "holdReady",
102 | "proxy",
103 | "ready",
104 | "keydown",
105 | "keypress",
106 | "keyup",
107 | "live",
108 | "load",
109 | "mousedown",
110 | "mouseenter",
111 | "mouseleave",
112 | "mousemove",
113 | "mouseout",
114 | "mouseover",
115 | "mouseup"
116 | "on"
117 | ```
118 |
119 | Each time an element is assigned an event, an additional attribute is created. Copy the value of this attribute, which corresponds to a global variable. Paste it in the `console`, and this is the actual code location associated with this element's event.
120 |
121 | # VI. Feedback
122 |
123 | - If you encounter any events that are not `Hooked`, please provide feedback in the [issue](https://github.com/JSREI/jQuery-hook/issues) section.
124 | - For any requests or suggestions, please provide feedback in the [issue](https://github.com/JSREI/jQuery-hook/issues) section.
125 | - If you feel that this project has any areas for improvement (not limited to documentation, code) and prefer to jump straight into making changes rather than explaining at length, welcome to submit a `pr`.
126 |
127 | # VII. TODO
128 |
129 | - Monitor and `Hook` requests issued by `jQuery`.
130 | - If you wish for additional features, please discuss in the [issue](https://github.com/CC11001100/jQuery-hook/issues) section.
131 |
132 | # VIII、Contributors
133 |
134 |
135 |
136 | # IX、Star History
137 |
138 |
139 |
140 | # X. Reverse Engineering Technical Discussion Group
141 |
142 | Scan the QR code to join the reverse engineering technical discussion group:
143 |
144 |
145 |
146 | If the group QR code has expired, you can add my personal WeChat, send "Reverse Engineering Group" and I will invite you to the group:
147 |
148 |
149 |
150 | [Click here](https://t.me/jsreijsrei) or scan the QR code to join the TG discussion group:
151 |
152 |
153 |
--------------------------------------------------------------------------------
/jQuery-hook.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name jQuery Hook
3 | // @namespace https://github.com/JSREI/jQuery-hook
4 | // @version 0.4
5 | // @description 用于快速定位使用jQuery绑定到DOM元素上的事件的代码的真实位置,辅助逆向分析。
6 | // @document https://github.com/JSREI/jQuery-hook
7 | // @author CC11001100
8 | // @match *://*/*
9 | // @run-at document-start
10 | // @grant none
11 | // ==/UserScript==
12 | (() => {
13 |
14 | // 可自定义的一个变量前缀,尽量唯一有区分度即可,可以替换为为自己的ID
15 | const globalUniqPrefix = "cc11001100";
16 |
17 | // 用于控制打印在控制台的消息的大小
18 | const consoleLogFontSize = 12;
19 |
20 | // ----------------------------------------------- -----------------------------------------------------------------
21 |
22 | /**
23 | * 用于统一构建待颜色的日志输出,采用构建者模式
24 | *
25 | * from: https://github.com/JSREI/js-color-log
26 | */
27 | class ColorLogBuilder {
28 |
29 | /**
30 | * 创建一条日志,调用show()方法将其打印到控制台
31 | *
32 | * 因为认为字体颜色是没有区分度的,所以这里就不支持指定字体的颜色,字体恒定为黑色
33 | *
34 | * @param normalTextBackgroundColor {string} 此条日志中普通文本的背景色
35 | * @param highlightTextBackgroundColor {string} 此条日志中要高亮的文本的背景色
36 | * @param _consoleLogFontSize {string} 日志的大小
37 | */
38 | constructor(normalTextBackgroundColor = "#FFFFFF", highlightTextBackgroundColor = "#FFFFFF", _consoleLogFontSize = consoleLogFontSize) {
39 | this.normalTextBackgroundColor = normalTextBackgroundColor;
40 | this.highlightTextBackgroundColor = highlightTextBackgroundColor;
41 | this.consoleLogFontSize = _consoleLogFontSize;
42 | this.messageArray = [];
43 |
44 | // 每天日志都使用统一的前缀,在创建的时候就设置好
45 | // 先是一个日期,然后是插件的名字,以便与其它工具的输出相区分
46 | // 此处的统一前缀自行修改,因为使用的时候都是拷贝过去的
47 | this.append(`[${this.nowTimeString()}] `).append("jQuery Hook: ");
48 | }
49 |
50 | /**
51 | * 往日志中追加普通类型的信息
52 | *
53 | * @param msg {string}
54 | * @return {ColorLogBuilder}
55 | */
56 | append(msg) {
57 | this.appendNormal(msg);
58 | return this;
59 | }
60 |
61 | /**
62 | * 往日志中追加普通类型的信息
63 | *
64 | * @param msg {string}
65 | * @return {ColorLogBuilder}
66 | */
67 | appendNormal(msg) {
68 | this.messageArray.push(`color: black; background: ${this.normalTextBackgroundColor}; font-size: ${this.consoleLogFontSize}px;`);
69 | this.messageArray.push(msg);
70 | return this;
71 | }
72 |
73 | /**
74 | * 往日志中追加高亮的内容
75 | *
76 | * @param msg {string}
77 | */
78 | appendHighlight(msg) {
79 | this.messageArray.push(`color: black; background: ${this.highlightTextBackgroundColor}; font-size: ${this.consoleLogFontSize}px; font-weight: bold;`);
80 | this.messageArray.push(msg);
81 | return this;
82 | }
83 |
84 | /**
85 | * 把当前这条日志打印出来
86 | */
87 | show() {
88 | console.log(this.genFormatArray(this.messageArray), ...this.messageArray);
89 | }
90 |
91 | nowTimeString(fmt = "yyyy-MM-dd HH:mm:ss") {
92 | const now = new Date();
93 | let o = {
94 | "M+": now.getMonth() + 1, "d+": now.getDate(), //日
95 | "H+": now.getHours(), //小时
96 | "m+": now.getMinutes(), //分
97 | "s+": now.getSeconds(), //秒
98 | "q+": Math.floor((now.getMonth() + 3) / 3), //季度
99 | "S": now.getMilliseconds() //毫秒
100 | };
101 | if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (now.getFullYear() + "").substr(4 - RegExp.$1.length));
102 | for (let k in o) if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
103 | return fmt;
104 | }
105 |
106 | genFormatArray(messageAndStyleArray) {
107 | const formatArray = [];
108 | for (let i = 0, end = messageAndStyleArray.length / 2; i < end; i++) {
109 | formatArray.push("%c%s");
110 | }
111 | return formatArray.join("");
112 | }
113 |
114 | }
115 |
116 | // ----------------------------------------------- -----------------------------------------------------------------
117 |
118 | // 在第一次初始化jQuery的时候添加Hook,jQuery初始化的时候会添加一个名为$的全局变量,在添加这个变量的时候对其动一些手脚
119 | Object.defineProperty(window, "$", {
120 | set: $ => {
121 |
122 | // 为jquery的各种方法添加Hook
123 | try {
124 | addHook($);
125 | } catch (e) {
126 | new ColorLogBuilder("#FF6766", "#E50000")
127 | .append("add hook error, msg = ")
128 | .appendHighlight(e)
129 | .show();
130 | }
131 | // 删除set描述符拦截,恢复正常赋值,假装啥都没发生过,但实际上已经狸猫换太子了...
132 | delete window["$"];
133 | window["$"] = $;
134 | }, configurable: true
135 | });
136 |
137 | /**
138 | * 为jquery添加一些hook,等会儿使用jquery为dom元素绑定事件的话就会被捕获到
139 | * @param $
140 | */
141 | function addHook($) {
142 |
143 | addEventHook($);
144 |
145 | addAjaxHook($);
146 |
147 | new ColorLogBuilder("#65CC66", "#669934")
148 | .append("在当前页面上检测到jQuery的加载,添加jQuery Hook完成")
149 | .show();
150 | }
151 |
152 | /**
153 | * 增加Ajax Hook
154 | *
155 | * @param $
156 | */
157 | function addAjaxHook($) {
158 | if (!$["ajaxSetup"]) {
159 | new ColorLogBuilder("#FF6766", "#E50000")
160 | .appendHighlight("$不是jQuery对象,没有 ajaxSetup 属性,因此不添加Ajax Hook")
161 | .show();
162 | return;
163 | }
164 | const oldAjaxSetUp = $.ajaxSetup;
165 | $.ajaxSetup = function () {
166 | try {
167 | if (arguments.length === 1) {
168 | const {formatEventName, eventFuncGlobalName} = storeToWindow("ajaxSetup", arguments[0]);
169 | new ColorLogBuilder("#65CC66", "#669934")
170 | .append("检测到ajaxSetup全局拦截器设置请求参数,已经挂载到全局变量:")
171 | .appendHighlight(eventFuncGlobalName)
172 | .show();
173 | }
174 | } catch (e) {
175 | console.error(e);
176 | }
177 | return oldAjaxSetUp.apply(this, arguments);
178 | }
179 | }
180 |
181 | /**
182 | * 增加事件Hook
183 | *
184 | * @param $
185 | */
186 | function addEventHook($) {
187 | if (!$["fn"]) {
188 | new ColorLogBuilder("#FF6766", "#E50000")
189 | .appendHighlight("$不是jQuery对象,没有 fn 属性,因此不添加 Event Hook")
190 | .show();
191 | return;
192 | }
193 |
194 | // 一些比较通用的事件的拦截
195 | const eventNameList = ["click", "dblclick", "blur", "change", "contextmenu", "error", "focus", "focusin", "focusout", "hover", "holdReady", "proxy", "ready", "keydown", "keypress", "keyup", "live", "load", "mousedown", "mouseenter", "mouseleave", "mousemove", "mouseout", "mouseover", "mouseup"];
196 | for (let eventName of eventNameList) {
197 | const old = $.fn[eventName];
198 | $.fn[eventName] = function () {
199 | try {
200 | setEventFunctionNameToDomObjectAttribute(this, eventName, arguments[0]);
201 | } catch (e) {
202 | new ColorLogBuilder("#FF6766", "#E50000")
203 | .appendHighlight(`为jQuery添加${eventName}类型的事件的Hook时发生错误: ${e}`)
204 | .show();
205 | }
206 | return old.apply(this, arguments);
207 | }
208 | }
209 |
210 | // on,不仅是内置事件类型,还有可能有一些自定义的事件类型
211 | // https://api.jquery.com/on/
212 | const fnOnHolder = $.fn.on;
213 | $.fn.on = function () {
214 | try {
215 | const eventName = arguments[0];
216 | let eventFunction = undefined;
217 | for (let x of arguments) {
218 | if (x instanceof Function) {
219 | eventFunction = x;
220 | break;
221 | }
222 | }
223 | if (eventFunction instanceof Function) {
224 | setEventFunctionNameToDomObjectAttribute(this, eventName, eventFunction);
225 | }
226 | } catch (e) {
227 | new ColorLogBuilder("#FF6766", "#E50000")
228 | .appendHighlight(`为jQuery添加on方法的Hook时发生错误: ${e}`)
229 | .show();
230 | }
231 | return fnOnHolder.apply(this, arguments);
232 | }
233 |
234 | // TODO 还有delegate之类的比较隐晦的绑定事件的方式
235 |
236 | }
237 |
238 |
239 | /**
240 | * 为绑定了jquery事件的dom元素添加元素,提示所绑定的事件与对应的函数代码的全局变量的名称,只需要复制粘贴跟进去即可
241 | * 注意,有可能会为同一个元素重复绑定相同的事件
242 | *
243 | * @param domObject
244 | * @param eventName
245 | * @param eventFunction
246 | */
247 | function setEventFunctionNameToDomObjectAttribute(domObject, eventName, eventFunction) {
248 | eventName.split(' ').map((eventName) => {
249 | const {formatEventName, eventFuncGlobalName} = storeToWindow(eventName, eventFunction);
250 | const attrName = `${globalUniqPrefix}-jQuery-${formatEventName}-event-function`;
251 | if (domObject.attr(attrName)) {
252 | domObject.attr(attrName + "-" + new Date().getTime(), eventFuncGlobalName);
253 | } else {
254 | domObject.attr(attrName, eventFuncGlobalName);
255 | }
256 | })
257 | }
258 |
259 | // ----------------------------------------------- -----------------------------------------------------------------
260 |
261 | // 用于缓存事件函数到全局变量的映射关系
262 | // <事件函数, 全局变量>
263 | const eventFuncCacheMap = new Map();
264 |
265 | /**
266 | * 为事件的函数绑定一个全局变量,如果之前已经绑定过了则返回之前的
267 | *
268 | * @param eventName {string}
269 | * @param eventFunc {Function}
270 | * @return {{string, string}} 事件名和其对应的函数绑定到的全局变量
271 | */
272 | function storeToWindow(eventName, eventFunc) {
273 | if (eventFunc in eventFuncCacheMap) {
274 | return eventFuncCacheMap[eventFunc];
275 | }
276 | // 注意,事件名可能会包含一些非法的字符,所以需要转义
277 | // cc11001100-jquery-$destroy-event-function
278 | const formatEventName = safeSymbol(eventName);
279 | const eventFuncGlobalName = globalUnique(formatEventName);
280 | window[eventFuncGlobalName] = eventFunc;
281 | eventFuncCacheMap[eventFunc] = eventFuncGlobalName;
282 | return {
283 | formatEventName, eventFuncGlobalName,
284 | };
285 | }
286 |
287 | /***
288 | * 将事件名称转为合法的变量名称
289 | *
290 | * @param name
291 | */
292 | function safeSymbol(name) {
293 | const replaceMap = {
294 | ".": "_dot_",
295 | "$": "_dollar_",
296 | "-": "_dash_",
297 | " ": "_whitespace_"
298 | };
299 | let newName = "";
300 | for (let c of name) {
301 | if (c in replaceMap) {
302 | newName += replaceMap[c];
303 | } else if (isOkVarChar(c)) {
304 | newName += c;
305 | }
306 | }
307 | return newName;
308 | }
309 |
310 | /**
311 | * 判断字符是否是合法的变量名字符
312 | *
313 | * @param c {string}
314 | * @returns {boolean}
315 | */
316 | function isOkVarChar(c) {
317 | return (/^[a-zA-Z0-9]$/).test(c);
318 | }
319 |
320 | // ----------------------------------------------- -----------------------------------------------------------------
321 |
322 | // 每个事件一个独立的自增id
323 | const addressIdGeneratorMap = {};
324 |
325 | /**
326 | * 为给定的事件生成一个全局唯一的标识,这个标识中会带上事件类型以方便区分不同事件
327 | *
328 | * @param eventName {string}
329 | */
330 | function globalUnique(eventName) {
331 | const id = (addressIdGeneratorMap[eventName] || 0) + 1;
332 | addressIdGeneratorMap[eventName] = id;
333 | return `${globalUniqPrefix}__${eventName}__${id}`;
334 | }
335 |
336 | // ----------------------------------------------- -----------------------------------------------------------------
337 |
338 | /**
339 | * 解析当前代码的位置,以便能够直接定位到事件触发的代码位置
340 | *
341 | * @param keyword {string}
342 | * @returns {string}
343 | */
344 | function getCodeLocation(keyword = "cc11001100") {
345 | const callstack = new Error().stack.split("\n");
346 | while (callstack.length && callstack[0].indexOf(keyword) === -1) {
347 | callstack.shift();
348 | }
349 | callstack.shift();
350 | // callstack.shift();
351 |
352 | return callstack[0].trim();
353 | }
354 |
355 | })();
356 |
357 |
--------------------------------------------------------------------------------
/jQuery-hook.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JSREI/jQuery-hook/55345a397910c8aed45e25ebb4dc387610bfb5a7/jQuery-hook.pdf
--------------------------------------------------------------------------------
/markdown-images/README_images/0e8288d7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JSREI/jQuery-hook/55345a397910c8aed45e25ebb4dc387610bfb5a7/markdown-images/README_images/0e8288d7.png
--------------------------------------------------------------------------------
/markdown-images/README_images/160b9e7a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JSREI/jQuery-hook/55345a397910c8aed45e25ebb4dc387610bfb5a7/markdown-images/README_images/160b9e7a.png
--------------------------------------------------------------------------------
/markdown-images/README_images/3409d649.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JSREI/jQuery-hook/55345a397910c8aed45e25ebb4dc387610bfb5a7/markdown-images/README_images/3409d649.png
--------------------------------------------------------------------------------
/markdown-images/README_images/69f2a236.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JSREI/jQuery-hook/55345a397910c8aed45e25ebb4dc387610bfb5a7/markdown-images/README_images/69f2a236.png
--------------------------------------------------------------------------------
/markdown-images/README_images/90f8932a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JSREI/jQuery-hook/55345a397910c8aed45e25ebb4dc387610bfb5a7/markdown-images/README_images/90f8932a.png
--------------------------------------------------------------------------------
/markdown-images/README_images/a39e269d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JSREI/jQuery-hook/55345a397910c8aed45e25ebb4dc387610bfb5a7/markdown-images/README_images/a39e269d.png
--------------------------------------------------------------------------------
/markdown-images/README_images/bb826340.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JSREI/jQuery-hook/55345a397910c8aed45e25ebb4dc387610bfb5a7/markdown-images/README_images/bb826340.png
--------------------------------------------------------------------------------
/markdown-images/README_images/d4bf6528.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JSREI/jQuery-hook/55345a397910c8aed45e25ebb4dc387610bfb5a7/markdown-images/README_images/d4bf6528.png
--------------------------------------------------------------------------------
/markdown-images/README_images/f12e305d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JSREI/jQuery-hook/55345a397910c8aed45e25ebb4dc387610bfb5a7/markdown-images/README_images/f12e305d.png
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-hook",
3 | "version": "1.0.0",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "jquery-hook",
9 | "version": "1.0.0",
10 | "dependencies": {
11 | "@babel/core": "^7.26.0",
12 | "@babel/generator": "^7.26.0",
13 | "@babel/traverse": "^7.25.9",
14 | "@babel/types": "^7.26.0"
15 | }
16 | },
17 | "node_modules/@ampproject/remapping": {
18 | "version": "2.3.0",
19 | "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
20 | "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
21 | "license": "Apache-2.0",
22 | "dependencies": {
23 | "@jridgewell/gen-mapping": "^0.3.5",
24 | "@jridgewell/trace-mapping": "^0.3.24"
25 | },
26 | "engines": {
27 | "node": ">=6.0.0"
28 | }
29 | },
30 | "node_modules/@babel/code-frame": {
31 | "version": "7.26.0",
32 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.0.tgz",
33 | "integrity": "sha512-INCKxTtbXtcNbUZ3YXutwMpEleqttcswhAdee7dhuoVrD2cnuc3PqtERBtxkX5nziX9vnBL8WXmSGwv8CuPV6g==",
34 | "license": "MIT",
35 | "dependencies": {
36 | "@babel/helper-validator-identifier": "^7.25.9",
37 | "js-tokens": "^4.0.0",
38 | "picocolors": "^1.0.0"
39 | },
40 | "engines": {
41 | "node": ">=6.9.0"
42 | }
43 | },
44 | "node_modules/@babel/compat-data": {
45 | "version": "7.26.0",
46 | "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.0.tgz",
47 | "integrity": "sha512-qETICbZSLe7uXv9VE8T/RWOdIE5qqyTucOt4zLYMafj2MRO271VGgLd4RACJMeBO37UPWhXiKMBk7YlJ0fOzQA==",
48 | "license": "MIT",
49 | "engines": {
50 | "node": ">=6.9.0"
51 | }
52 | },
53 | "node_modules/@babel/core": {
54 | "version": "7.26.0",
55 | "resolved": "https://mirrors.cloud.tencent.com/npm/@babel/core/-/core-7.26.0.tgz",
56 | "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==",
57 | "license": "MIT",
58 | "dependencies": {
59 | "@ampproject/remapping": "^2.2.0",
60 | "@babel/code-frame": "^7.26.0",
61 | "@babel/generator": "^7.26.0",
62 | "@babel/helper-compilation-targets": "^7.25.9",
63 | "@babel/helper-module-transforms": "^7.26.0",
64 | "@babel/helpers": "^7.26.0",
65 | "@babel/parser": "^7.26.0",
66 | "@babel/template": "^7.25.9",
67 | "@babel/traverse": "^7.25.9",
68 | "@babel/types": "^7.26.0",
69 | "convert-source-map": "^2.0.0",
70 | "debug": "^4.1.0",
71 | "gensync": "^1.0.0-beta.2",
72 | "json5": "^2.2.3",
73 | "semver": "^6.3.1"
74 | },
75 | "engines": {
76 | "node": ">=6.9.0"
77 | },
78 | "funding": {
79 | "type": "opencollective",
80 | "url": "https://opencollective.com/babel"
81 | }
82 | },
83 | "node_modules/@babel/generator": {
84 | "version": "7.26.0",
85 | "resolved": "https://mirrors.cloud.tencent.com/npm/@babel/generator/-/generator-7.26.0.tgz",
86 | "integrity": "sha512-/AIkAmInnWwgEAJGQr9vY0c66Mj6kjkE2ZPB1PurTRaRAh3U+J45sAQMjQDJdh4WbR3l0x5xkimXBKyBXXAu2w==",
87 | "license": "MIT",
88 | "dependencies": {
89 | "@babel/parser": "^7.26.0",
90 | "@babel/types": "^7.26.0",
91 | "@jridgewell/gen-mapping": "^0.3.5",
92 | "@jridgewell/trace-mapping": "^0.3.25",
93 | "jsesc": "^3.0.2"
94 | },
95 | "engines": {
96 | "node": ">=6.9.0"
97 | }
98 | },
99 | "node_modules/@babel/helper-compilation-targets": {
100 | "version": "7.25.9",
101 | "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz",
102 | "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==",
103 | "license": "MIT",
104 | "dependencies": {
105 | "@babel/compat-data": "^7.25.9",
106 | "@babel/helper-validator-option": "^7.25.9",
107 | "browserslist": "^4.24.0",
108 | "lru-cache": "^5.1.1",
109 | "semver": "^6.3.1"
110 | },
111 | "engines": {
112 | "node": ">=6.9.0"
113 | }
114 | },
115 | "node_modules/@babel/helper-module-imports": {
116 | "version": "7.25.9",
117 | "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz",
118 | "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==",
119 | "license": "MIT",
120 | "dependencies": {
121 | "@babel/traverse": "^7.25.9",
122 | "@babel/types": "^7.25.9"
123 | },
124 | "engines": {
125 | "node": ">=6.9.0"
126 | }
127 | },
128 | "node_modules/@babel/helper-module-transforms": {
129 | "version": "7.26.0",
130 | "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz",
131 | "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==",
132 | "license": "MIT",
133 | "dependencies": {
134 | "@babel/helper-module-imports": "^7.25.9",
135 | "@babel/helper-validator-identifier": "^7.25.9",
136 | "@babel/traverse": "^7.25.9"
137 | },
138 | "engines": {
139 | "node": ">=6.9.0"
140 | },
141 | "peerDependencies": {
142 | "@babel/core": "^7.0.0"
143 | }
144 | },
145 | "node_modules/@babel/helper-string-parser": {
146 | "version": "7.25.9",
147 | "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
148 | "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
149 | "license": "MIT",
150 | "engines": {
151 | "node": ">=6.9.0"
152 | }
153 | },
154 | "node_modules/@babel/helper-validator-identifier": {
155 | "version": "7.25.9",
156 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
157 | "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
158 | "license": "MIT",
159 | "engines": {
160 | "node": ">=6.9.0"
161 | }
162 | },
163 | "node_modules/@babel/helper-validator-option": {
164 | "version": "7.25.9",
165 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz",
166 | "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==",
167 | "license": "MIT",
168 | "engines": {
169 | "node": ">=6.9.0"
170 | }
171 | },
172 | "node_modules/@babel/helpers": {
173 | "version": "7.26.0",
174 | "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz",
175 | "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==",
176 | "license": "MIT",
177 | "dependencies": {
178 | "@babel/template": "^7.25.9",
179 | "@babel/types": "^7.26.0"
180 | },
181 | "engines": {
182 | "node": ">=6.9.0"
183 | }
184 | },
185 | "node_modules/@babel/parser": {
186 | "version": "7.26.1",
187 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.1.tgz",
188 | "integrity": "sha512-reoQYNiAJreZNsJzyrDNzFQ+IQ5JFiIzAHJg9bn94S3l+4++J7RsIhNMoB+lgP/9tpmiAQqspv+xfdxTSzREOw==",
189 | "license": "MIT",
190 | "dependencies": {
191 | "@babel/types": "^7.26.0"
192 | },
193 | "bin": {
194 | "parser": "bin/babel-parser.js"
195 | },
196 | "engines": {
197 | "node": ">=6.0.0"
198 | }
199 | },
200 | "node_modules/@babel/template": {
201 | "version": "7.25.9",
202 | "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz",
203 | "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==",
204 | "license": "MIT",
205 | "dependencies": {
206 | "@babel/code-frame": "^7.25.9",
207 | "@babel/parser": "^7.25.9",
208 | "@babel/types": "^7.25.9"
209 | },
210 | "engines": {
211 | "node": ">=6.9.0"
212 | }
213 | },
214 | "node_modules/@babel/traverse": {
215 | "version": "7.25.9",
216 | "resolved": "https://mirrors.cloud.tencent.com/npm/@babel/traverse/-/traverse-7.25.9.tgz",
217 | "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==",
218 | "license": "MIT",
219 | "dependencies": {
220 | "@babel/code-frame": "^7.25.9",
221 | "@babel/generator": "^7.25.9",
222 | "@babel/parser": "^7.25.9",
223 | "@babel/template": "^7.25.9",
224 | "@babel/types": "^7.25.9",
225 | "debug": "^4.3.1",
226 | "globals": "^11.1.0"
227 | },
228 | "engines": {
229 | "node": ">=6.9.0"
230 | }
231 | },
232 | "node_modules/@babel/types": {
233 | "version": "7.26.0",
234 | "resolved": "https://mirrors.cloud.tencent.com/npm/@babel/types/-/types-7.26.0.tgz",
235 | "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==",
236 | "license": "MIT",
237 | "dependencies": {
238 | "@babel/helper-string-parser": "^7.25.9",
239 | "@babel/helper-validator-identifier": "^7.25.9"
240 | },
241 | "engines": {
242 | "node": ">=6.9.0"
243 | }
244 | },
245 | "node_modules/@jridgewell/gen-mapping": {
246 | "version": "0.3.5",
247 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
248 | "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
249 | "license": "MIT",
250 | "dependencies": {
251 | "@jridgewell/set-array": "^1.2.1",
252 | "@jridgewell/sourcemap-codec": "^1.4.10",
253 | "@jridgewell/trace-mapping": "^0.3.24"
254 | },
255 | "engines": {
256 | "node": ">=6.0.0"
257 | }
258 | },
259 | "node_modules/@jridgewell/resolve-uri": {
260 | "version": "3.1.2",
261 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
262 | "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
263 | "license": "MIT",
264 | "engines": {
265 | "node": ">=6.0.0"
266 | }
267 | },
268 | "node_modules/@jridgewell/set-array": {
269 | "version": "1.2.1",
270 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
271 | "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
272 | "license": "MIT",
273 | "engines": {
274 | "node": ">=6.0.0"
275 | }
276 | },
277 | "node_modules/@jridgewell/sourcemap-codec": {
278 | "version": "1.5.0",
279 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
280 | "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
281 | "license": "MIT"
282 | },
283 | "node_modules/@jridgewell/trace-mapping": {
284 | "version": "0.3.25",
285 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
286 | "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
287 | "license": "MIT",
288 | "dependencies": {
289 | "@jridgewell/resolve-uri": "^3.1.0",
290 | "@jridgewell/sourcemap-codec": "^1.4.14"
291 | }
292 | },
293 | "node_modules/browserslist": {
294 | "version": "4.24.2",
295 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz",
296 | "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==",
297 | "funding": [
298 | {
299 | "type": "opencollective",
300 | "url": "https://opencollective.com/browserslist"
301 | },
302 | {
303 | "type": "tidelift",
304 | "url": "https://tidelift.com/funding/github/npm/browserslist"
305 | },
306 | {
307 | "type": "github",
308 | "url": "https://github.com/sponsors/ai"
309 | }
310 | ],
311 | "license": "MIT",
312 | "dependencies": {
313 | "caniuse-lite": "^1.0.30001669",
314 | "electron-to-chromium": "^1.5.41",
315 | "node-releases": "^2.0.18",
316 | "update-browserslist-db": "^1.1.1"
317 | },
318 | "bin": {
319 | "browserslist": "cli.js"
320 | },
321 | "engines": {
322 | "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
323 | }
324 | },
325 | "node_modules/caniuse-lite": {
326 | "version": "1.0.30001671",
327 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001671.tgz",
328 | "integrity": "sha512-jocyVaSSfXg2faluE6hrWkMgDOiULBMca4QLtDT39hw1YxaIPHWc1CcTCKkPmHgGH6tKji6ZNbMSmUAvENf2/A==",
329 | "funding": [
330 | {
331 | "type": "opencollective",
332 | "url": "https://opencollective.com/browserslist"
333 | },
334 | {
335 | "type": "tidelift",
336 | "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
337 | },
338 | {
339 | "type": "github",
340 | "url": "https://github.com/sponsors/ai"
341 | }
342 | ],
343 | "license": "CC-BY-4.0"
344 | },
345 | "node_modules/convert-source-map": {
346 | "version": "2.0.0",
347 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
348 | "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
349 | "license": "MIT"
350 | },
351 | "node_modules/debug": {
352 | "version": "4.3.7",
353 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
354 | "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
355 | "license": "MIT",
356 | "dependencies": {
357 | "ms": "^2.1.3"
358 | },
359 | "engines": {
360 | "node": ">=6.0"
361 | },
362 | "peerDependenciesMeta": {
363 | "supports-color": {
364 | "optional": true
365 | }
366 | }
367 | },
368 | "node_modules/electron-to-chromium": {
369 | "version": "1.5.47",
370 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.47.tgz",
371 | "integrity": "sha512-zS5Yer0MOYw4rtK2iq43cJagHZ8sXN0jDHDKzB+86gSBSAI4v07S97mcq+Gs2vclAxSh1j7vOAHxSVgduiiuVQ==",
372 | "license": "ISC"
373 | },
374 | "node_modules/escalade": {
375 | "version": "3.2.0",
376 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
377 | "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
378 | "license": "MIT",
379 | "engines": {
380 | "node": ">=6"
381 | }
382 | },
383 | "node_modules/gensync": {
384 | "version": "1.0.0-beta.2",
385 | "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
386 | "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
387 | "license": "MIT",
388 | "engines": {
389 | "node": ">=6.9.0"
390 | }
391 | },
392 | "node_modules/globals": {
393 | "version": "11.12.0",
394 | "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
395 | "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
396 | "license": "MIT",
397 | "engines": {
398 | "node": ">=4"
399 | }
400 | },
401 | "node_modules/js-tokens": {
402 | "version": "4.0.0",
403 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
404 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
405 | "license": "MIT"
406 | },
407 | "node_modules/jsesc": {
408 | "version": "3.0.2",
409 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
410 | "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==",
411 | "license": "MIT",
412 | "bin": {
413 | "jsesc": "bin/jsesc"
414 | },
415 | "engines": {
416 | "node": ">=6"
417 | }
418 | },
419 | "node_modules/json5": {
420 | "version": "2.2.3",
421 | "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
422 | "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
423 | "license": "MIT",
424 | "bin": {
425 | "json5": "lib/cli.js"
426 | },
427 | "engines": {
428 | "node": ">=6"
429 | }
430 | },
431 | "node_modules/lru-cache": {
432 | "version": "5.1.1",
433 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
434 | "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
435 | "license": "ISC",
436 | "dependencies": {
437 | "yallist": "^3.0.2"
438 | }
439 | },
440 | "node_modules/ms": {
441 | "version": "2.1.3",
442 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
443 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
444 | "license": "MIT"
445 | },
446 | "node_modules/node-releases": {
447 | "version": "2.0.18",
448 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
449 | "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==",
450 | "license": "MIT"
451 | },
452 | "node_modules/picocolors": {
453 | "version": "1.1.1",
454 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
455 | "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
456 | "license": "ISC"
457 | },
458 | "node_modules/semver": {
459 | "version": "6.3.1",
460 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
461 | "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
462 | "license": "ISC",
463 | "bin": {
464 | "semver": "bin/semver.js"
465 | }
466 | },
467 | "node_modules/update-browserslist-db": {
468 | "version": "1.1.1",
469 | "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz",
470 | "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==",
471 | "funding": [
472 | {
473 | "type": "opencollective",
474 | "url": "https://opencollective.com/browserslist"
475 | },
476 | {
477 | "type": "tidelift",
478 | "url": "https://tidelift.com/funding/github/npm/browserslist"
479 | },
480 | {
481 | "type": "github",
482 | "url": "https://github.com/sponsors/ai"
483 | }
484 | ],
485 | "license": "MIT",
486 | "dependencies": {
487 | "escalade": "^3.2.0",
488 | "picocolors": "^1.1.0"
489 | },
490 | "bin": {
491 | "update-browserslist-db": "cli.js"
492 | },
493 | "peerDependencies": {
494 | "browserslist": ">= 4.21.0"
495 | }
496 | },
497 | "node_modules/yallist": {
498 | "version": "3.1.1",
499 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
500 | "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
501 | "license": "ISC"
502 | }
503 | }
504 | }
505 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-hook",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "jQuery-hook.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/JSREI/jQuery-hook.git"
12 | },
13 | "private": true,
14 | "dependencies": {
15 | "@babel/core": "^7.26.0",
16 | "@babel/generator": "^7.26.0",
17 | "@babel/traverse": "^7.25.9",
18 | "@babel/types": "^7.26.0"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/tools/README.md:
--------------------------------------------------------------------------------
1 | # jQuery-hook 工具目录
2 |
3 | 此目录包含了与 jQuery-hook 项目相关的辅助工具。
4 |
5 | ## 文件介绍
6 |
7 | ### gen-fuck-jquery-code.html
8 |
9 | 这个 HTML 文件用于生成大量的 jQuery 相关代码,主要目的是创建混淆视听的代码样本。
10 |
11 | 功能特点:
12 | - 生成随机的 jQuery 选择器和操作
13 | - 创建大量的伪 jQuery 代码块
14 | - 用于测试或演示 jQuery 代码混淆场景
15 |
16 | 使用方法:
17 | 1. 在浏览器中打开此 HTML 文件
18 | 2. 页面将自动生成并显示大量随机的 jQuery 代码块
19 | 3. 这些代码可用于测试 jQuery-hook 工具在复杂代码环境中的性能和有效性
20 |
21 | ## 注意事项
22 |
23 | 这些工具主要用于开发和测试目的。在使用过程中,请参考相关文档和项目主 README 以获取更多指导。
--------------------------------------------------------------------------------
/tools/gen-fuck-jquery-code.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 这个页面用于生成jQuery相关的混淆视听的代码
6 |
7 |
8 |
9 |
42 |
43 |
--------------------------------------------------------------------------------
/website/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JSREI/jQuery-hook/55345a397910c8aed45e25ebb4dc387610bfb5a7/website/images/logo.png
--------------------------------------------------------------------------------
/website/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | jQuery Hook - 现代逆向工程工具包
7 |
8 |
9 |
179 |
231 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
逆向工程从未如此优雅
290 |
穿透jQuery事件迷雾,直达原生代码核心
291 |
297 |
298 |
299 |
300 |
301 |
302 |
303 | 🎯 核心功能
304 |
305 | - 原生事件定位 - 穿透jQuery封装直达原生代码
306 | - 加密逻辑追踪 - 快速定位加密函数调用栈
307 | - 动态事件追踪 - 实时监控DOM事件绑定
308 |
309 |
310 | 【此处为GIF预留位置】
311 |
312 |
313 |
314 |
332 |
333 | 🔍 演示视频
334 |
335 |
336 |
344 |
345 |
346 |
347 |
348 |
349 | 👥 逆向技术交流群
350 |
351 |
扫码加入逆向技术微信交流群:
352 |
353 |
354 |

355 |
微信交流群
356 |
357 |
358 |
359 |

360 |
如群二维码过期,可加此微信并发送【逆向群】
361 |
362 |
363 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
389 |
390 |
391 |
392 |
446 |
447 |
--------------------------------------------------------------------------------