Skip to content

Commit 8ffd620

Browse files
committed
init
1 parent 630c8d6 commit 8ffd620

11 files changed

+208
-0
lines changed

README.md

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# jQuery Hook
2+
3+
# 一、此脚本的作用是什么?
4+
5+
用于快速定位使用jQuery绑定到DOM元素上的事件的代码的真实位置,辅助逆向分析。
6+
7+
# 二、为什么会有这个?
8+
9+
jQuery曾经引领过一个时代,虽然现已没落,但是很多遗留下来的系统都用到了jQuery,其市场还是比较大的, 而笔者在做js逆向的时候发现用Chrome自带的查看元素绑定事件的功能看到的值是被jQuery包裹着一层的代码:
10+
![](markdown-images/README_images/160b9e7a.png)
11+
不容易定位到事件代码逻辑真实代码所在的位置, 这个小脚本就是解决这个问题的,提供一种简单有效的方式能够快速找到jQuery事件对应的真实代码的位置。
12+
13+
# 三、安装
14+
已在油猴商店上架:
15+
[https://greasyfork.org/zh-CN/scripts/435556-jquery-hook](https://greasyfork.org/zh-CN/scripts/435556-jquery-hook)
16+
17+
# 四、使用案例
18+
随便找一个使用jQuery开发的网站,比如这个:
19+
[http://wap.wfu.edu.cn:8001/authz/login/slogin](http://wap.wfu.edu.cn:8001/authz/login/slogin)
20+
尝试触发登录请求,会发现它的登录密码是被加密的:
21+
![](markdown-images/README_images/69f2a236.png)
22+
通过这里可以看到,是doc请求:
23+
![](markdown-images/README_images/d4bf6528.png)
24+
那么按照经验推测, 应该是单击登录按钮的时候js对明文密码加密替换然后提交表单的,
25+
因此如果能定位到按钮的事件则很快就能定位到加密代码的位置,查看这个按钮绑定的事件,跟进去:
26+
![](markdown-images/README_images/160b9e7a.png)
27+
会发现会陷入到jQuery的闭包中无法自拔:
28+
![](markdown-images/README_images/bb826340.png)
29+
油猴脚本开启本插件jQuery hook,刷新页面,如果加载成功控制台会有提示:
30+
![](markdown-images/README_images/90f8932a.png)
31+
再次对登录按钮检查元素,不必理睬右边Chrome给出的的绑定事件, 注意Elements面板中使用jQuery绑定的事件都已经以属性的方式展示出来了:
32+
![](markdown-images/README_images/a39e269d.png)
33+
比如:
34+
```text
35+
cc11001100-jquery-click-event-function="cc11001100_click_5"
36+
```
37+
表示此元素上有一个click类型的事件,所关联的函数的代码已经赋值到全局变量:
38+
```text
39+
cc11001100_click_5
40+
```
41+
上,切换到console,粘贴`cc11001100_click_5`回车:
42+
![](markdown-images/README_images/f12e305d.png)
43+
单击跟进去,直接定位到了登录按钮的click事件所绑定的代码:
44+
![](markdown-images/README_images/3409d649.png)
45+
往下拉,可以看到参数`mm`的加密方式:
46+
![](markdown-images/README_images/0e8288d7.png)
47+
至此梳理完毕,以比较科学的方式很轻松就定位到了加密位置。
48+
49+
# 五、原理概述
50+
通过hook jQuery的$.fn原型上的一些设置事件的方法来实现,目前支持的方法:
51+
52+
```text
53+
"click", "dblclick", "blur", "change", "contextmenu", "error", "focus",
54+
"focusin", "focusout", "hover", "holdReady", "proxy", "ready", "keydown", "keypress",
55+
"keyup", "live", "load", "mousedown", "mouseenter", "mouseleave", "mousemove", "mouseout",
56+
"mouseover", "mouseup"
57+
"on"
58+
```
59+
60+
元素每被设置一个事件就会多一个属性,复制这个属性的值,对应着一个全局变量,在console上粘贴,这个就是此元素的此事件对应着的真实代码位置。
61+
62+
# 六、问题反馈
63+
64+
如果发现有Hook不到的情况,请在issue中反馈。
65+
66+

jquery-hook.js

+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
// ==UserScript==
2+
// @name jQuery Hook
3+
// @namespace https://github.com/CC11001100/crawler-js-hook-framework-public/tree/master/020-jQuery-hook
4+
// @version 0.2
5+
// @description 用于快速定位使用jQuery绑定到DOM元素上的事件的代码的真实位置,辅助逆向分析。
6+
// @document https://github.com/CC11001100/crawler-js-hook-framework-public/blob/master/020-jQuery-hook/README.md
7+
// @author CC11001100
8+
// @match *://*/*
9+
// @run-at document-start
10+
// @grant none
11+
// ==/UserScript==
12+
(() => {
13+
14+
const globalUniqPrefix = "cc11001100";
15+
16+
// 在第一次设置jquery的时候添加Hook
17+
Object.defineProperty(window, "$", {
18+
set: $ => {
19+
20+
// 为jquery的各种方法添加Hook
21+
try {
22+
addHook($);
23+
} catch (e) {
24+
console.error("为jQuery添加Hook时报错: " + e)
25+
}
26+
27+
// 删除set描述符拦截,恢复正常赋值
28+
delete window["$"];
29+
window["$"] = $;
30+
},
31+
configurable: true
32+
});
33+
34+
/**
35+
* 为jquery添加一些hook,等会儿使用jquery为dom元素绑定事件的话就会被捕获到
36+
* @param $
37+
*/
38+
function addHook($) {
39+
40+
if (!$["fn"]) {
41+
console.log("当前页面虽然声明了$变量,但并不是jQuery,因此忽略。");
42+
return;
43+
}
44+
45+
// 一些比较通用的事件的拦截
46+
const eventNameList = [
47+
"click", "dblclick", "blur", "change", "contextmenu", "error", "focus",
48+
"focusin", "focusout", "hover", "holdReady", "proxy", "ready", "keydown", "keypress",
49+
"keyup", "live", "load", "mousedown", "mouseenter", "mouseleave", "mousemove", "mouseout",
50+
"mouseover", "mouseup"
51+
];
52+
for (let eventName of eventNameList) {
53+
const old = $.fn[eventName];
54+
$.fn[eventName] = function () {
55+
try {
56+
setEventFunctionNameToDomObjectAttribute(this, eventName, arguments[0]);
57+
} catch (e) {
58+
console.error(`为jQuery添加${eventName}类型的事件的Hook时发生错误: ${e}`);
59+
}
60+
return old.apply(this, arguments);
61+
}
62+
}
63+
64+
// on,不仅是内置事件类型,还有可能有一些自定义的事件类型
65+
// https://api.jquery.com/on/
66+
const fnOnHolder = $.fn.on;
67+
$.fn.on = function () {
68+
try {
69+
const eventName = arguments[0];
70+
let eventFunction = undefined;
71+
for (let x of arguments) {
72+
if (x instanceof Function) {
73+
eventFunction = x;
74+
break;
75+
}
76+
}
77+
if (eventFunction instanceof Function) {
78+
setEventFunctionNameToDomObjectAttribute(this, eventName, eventFunction);
79+
}
80+
} catch (e) {
81+
console.error(`为jQuery添加on方法的Hook时发生错误: ${e}`);
82+
}
83+
return fnOnHolder.apply(this, arguments);
84+
}
85+
86+
// TODO 还有delegate之类的比较隐晦的绑定事件的方式
87+
88+
console.log(`当前页面使用了jQuery,jQuery Hook已初始化完毕。`);
89+
}
90+
91+
const addressIdGeneratorMap = {};
92+
93+
/**
94+
* 生成一个全局唯一的标识
95+
* @param eventName
96+
*/
97+
function globalUnique(eventName) {
98+
const id = (addressIdGeneratorMap[eventName] || 0) + 1;
99+
addressIdGeneratorMap[eventName] = id;
100+
return `${globalUniqPrefix}_${eventName}_${id}`;
101+
}
102+
103+
/**
104+
* 为绑定了jquery事件的dom元素添加元素,提示所绑定的事件与对应的函数代码的全局变量的名称,只需要复制粘贴跟进去即可
105+
* 注意,有可能会为同一个元素重复绑定相同的事件
106+
*
107+
* @param domObject
108+
* @param eventName
109+
* @param eventFunction
110+
*/
111+
function setEventFunctionNameToDomObjectAttribute(domObject, eventName, eventFunction) {
112+
// TODO bug fix 注意,事件名可能会包含一些非法的字符
113+
// cc11001100-jquery-$destroy-event-function
114+
eventName = safeSymbol(eventName);
115+
const eventFunctionGlobalName = globalUnique(eventName);
116+
window[eventFunctionGlobalName] = eventFunction;
117+
const attrName = `${globalUniqPrefix}-jQuery-${eventName}-event-function`;
118+
if (domObject.attr(attrName)) {
119+
domObject.attr(attrName + "-" + new Date().getTime(), eventFunctionGlobalName);
120+
} else {
121+
domObject.attr(attrName, eventFunctionGlobalName);
122+
}
123+
}
124+
125+
/***
126+
*
127+
* @param name
128+
*/
129+
function safeSymbol(name) {
130+
const replaceMap = {
131+
".": "_dot_",
132+
"$": "_dollar_",
133+
"-": "_dash_"
134+
};
135+
for (let key of Object.getOwnPropertyNames(replaceMap)) {
136+
name = name.replace(key, replaceMap[key]);
137+
}
138+
return name;
139+
}
140+
141+
})();
142+
140 KB
Loading
307 KB
Loading
253 KB
Loading
371 KB
Loading
49.6 KB
Loading
799 KB
Loading
254 KB
Loading
9.08 KB
Loading
119 KB
Loading

0 commit comments

Comments
 (0)