Skip to content

Commit ef922a7

Browse files
committed
feat: 实现支持多种hook方式
1 parent 4e6b6cd commit ef922a7

18 files changed

+644
-35
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/**
2+
* 分析参数加密
3+
*/
4+
class ParamEncryptionAnalyzer {
5+
6+
/**
7+
*
8+
* @param param {Param}
9+
*/
10+
analyze(param) {
11+
return this.detectEncryptionType(param.value);
12+
}
13+
14+
detectEncryptionType(input) {
15+
// Base64
16+
const base64Regex = /^[A-Za-z0-9+/]+={0,2}$/;
17+
if (base64Regex.test(input) && input.length % 4 === 0) {
18+
return "Base64";
19+
}
20+
21+
// MD5
22+
const md5Regex = /^[a-f0-9]{32}$/i;
23+
if (md5Regex.test(input)) {
24+
return "MD5";
25+
}
26+
27+
// SHA-1
28+
const sha1Regex = /^[a-f0-9]{40}$/i;
29+
if (sha1Regex.test(input)) {
30+
return "SHA-1";
31+
}
32+
33+
// SHA-256
34+
const sha256Regex = /^[a-f0-9]{64}$/i;
35+
if (sha256Regex.test(input)) {
36+
return "SHA-256";
37+
}
38+
39+
// SHA-512
40+
const sha512Regex = /^[a-f0-9]{128}$/i;
41+
if (sha512Regex.test(input)) {
42+
return "SHA-512";
43+
}
44+
45+
// bcrypt
46+
const bcryptRegex = /^\$2[aby]\$\d{2}\$[.\/A-Za-z0-9]{53}$/;
47+
if (bcryptRegex.test(input)) {
48+
return "bcrypt";
49+
}
50+
51+
// URL编码
52+
const urlEncodedRegex = /%[0-9A-Fa-f]{2}/;
53+
if (urlEncodedRegex.test(input)) {
54+
return "URL Encoded";
55+
}
56+
57+
// Hex编码
58+
const hexRegex = /^[0-9A-Fa-f]+$/;
59+
if (hexRegex.test(input) && input.length % 2 === 0) {
60+
return "Hex Encoded";
61+
}
62+
63+
// ROT13
64+
const rot13Regex = /^[A-Za-z]+$/;
65+
if (rot13Regex.test(input) && input === input.replace(/[A-Za-z]/g, function (c) {
66+
return String.fromCharCode(c.charCodeAt(0) + (c.toLowerCase() < 'n' ? 13 : -13));
67+
})) {
68+
return "ROT13";
69+
}
70+
71+
// JWT
72+
const jwtRegex = /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/;
73+
if (jwtRegex.test(input)) {
74+
return "JWT";
75+
}
76+
77+
// UUID
78+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
79+
if (uuidRegex.test(input)) {
80+
return "UUID";
81+
}
82+
83+
// 如果都不匹配,返回未知
84+
return null;
85+
}
86+
87+
// // 测试示例
88+
// console.log(detectEncryptionType("SGVsbG8gV29ybGQ=")); // Base64
89+
// console.log(detectEncryptionType("5d41402abc4b2a76b9719d911017c592")); // MD5
90+
// console.log(detectEncryptionType("2fd4e1c67a2d28fced849ee1bb76e7391b93eb12")); // SHA-1
91+
// console.log(detectEncryptionType("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")); // SHA-256
92+
// console.log(detectEncryptionType("$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy")); // bcrypt
93+
// console.log(detectEncryptionType("Hello%20World")); // URL Encoded
94+
// console.log(detectEncryptionType("48656c6c6f20576f726c64")); // Hex Encoded
95+
// console.log(detectEncryptionType("Uryyb Jbeyq")); // ROT13
96+
// console.log(detectEncryptionType("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c")); // JWT
97+
// console.log(detectEncryptionType("550e8400-e29b-41d4-a716-446655440000")); // UUID
98+
// console.log(detectEncryptionType("randomstring")); // Unknown Encryption Type
99+
100+
}
101+
102+
103+
module.exports = {
104+
ParamEncryptionAnalyzer
105+
}

src/analyzer/request-analyzer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class RequestAnalyzer {
7070
}
7171

7272
/**
73-
* 判断时间戳是否是合法的jsonp时间戳,它的事件范围不应该太过于离谱,应该是一个近期的时间
73+
* 判断时间戳是否是合法的jsonp时间戳,它的时间范围不应该太过于离谱,应该是一个近期的时间
7474
*
7575
* @param timestampString
7676
* @return {boolean}

src/analyzer/response-analyzer.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
*/
44
class ResponseAnalyzer {
55

6+
// 2025-01-07 21:44:27 似乎并不需要这部分逻辑了,仅从请求参数进行推测就已经足够用了
7+
68
/**
9+
*
710
* 从一次完整的请求中分析
811
*
912
* @param scriptContext {ScriptContext}

src/config/config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ class Config {
1515
// 让用户能够自己指定前缀,也许会有一些拥有感?之前ast hook好像就有个哥们喜欢这样干...
1616
this.prefix = "CC11001100";
1717

18+
this.hookType = "use-proxy-function";
19+
1820
// 是否忽略.js后缀的请求
1921
this.isIgnoreJsSuffixRequest = true;
2022

@@ -60,6 +62,7 @@ class Config {
6062
const o = JSON.parse(configJsonString);
6163
this.language = o.language;
6264
this.prefix = o.prefix;
65+
this.hookType = o.hookType;
6366
this.isIgnoreJsSuffixRequest = o.isIgnoreJsSuffixRequest;
6467
this.isIgnoreNotJsonpRequest = o.isIgnoreNotJsonpRequest;
6568
this.autoJumpProjectSiteOnConfiguraion = o.autoJumpProjectSiteOnConfiguraion;

src/config/ui/component/debugger-component.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,13 @@ class DebuggerComponent {
210210
getGlobalConfig().persist();
211211
});
212212

213+
// ${debuggerConfig.id}-hook-type
214+
debuggerElt.find(`#${debuggerInformation.id}-hook-type`).change(function () {
215+
const localDebuggerInformation = getGlobalConfig().findDebuggerById(debuggerInformation.id);
216+
localDebuggerInformation.hookType = $(this).val();
217+
getGlobalConfig().persist();
218+
});
219+
213220
// callbackFunctionParamName
214221
debuggerElt.find(`#${debuggerInformation.id}-callbackFunctionParamName-text`).on('input', function () {
215222
const localDebuggerInformation = getGlobalConfig().findDebuggerById(debuggerInformation.id);

src/config/ui/component/global-options-component.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,27 @@ class GlobalOptionsComponent {
3939
</div>
4040
</td>
4141
</tr>
42+
<tr>
43+
<td align="right">
44+
<div class="js-script-hook-tips-icon" >
45+
?
46+
<div class="js-script-hook-tooltip">
47+
${language.global_settings.responseDebuggerHookTypeTips}
48+
</div>
49+
</div>
50+
<span>${language.global_settings.responseDebuggerHookType}</span>
51+
</td>
52+
<td align="left" style="padding: 10px;">
53+
<div style="display: inline-block;">
54+
<div class="js-script-hook-select-container" style="width: 400px !important; ">
55+
<select id="js-script-hook-global-config-hook-type">
56+
<option value="use-proxy-function" >${language.global_settings.responseDebuggerHookTypeUseProxyFunction}</option>
57+
<option value="use-redeclare-function">${language.global_settings.responseDebuggerHookTypeUseRedeclareFunction}</option>
58+
</select>
59+
</div>
60+
</div>
61+
</td>
62+
</tr>
4263
<tr>
4364
<td align="right">
4465
<!-- 问号形式的 Tips 组件 -->
@@ -122,6 +143,15 @@ class GlobalOptionsComponent {
122143
render(language, oldConfig) {
123144
const component = $(this.template(oldConfig, language));
124145

146+
if (oldConfig.hookType) {
147+
component.find(`#js-script-hook-global-config-hook-type`).val(oldConfig.hookType);
148+
}
149+
150+
component.find("#js-script-hook-global-config-hook-type").change(function () {
151+
getGlobalConfig().hookType = $(this).val();
152+
getGlobalConfig().persist();
153+
});
154+
125155
// 切换语言选择
126156
component.find("#js-script-hook-global-config-language").change(function () {
127157
getGlobalConfig().language = $(this).val();

src/config/ui/component/language.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ const chinese = {
1111
flagPrefixTips: "在Hook的时候会设置一些全局唯一的标志位,你可以个性化修改为自定义的前缀",
1212
flagPrefixPlaceholder: "可自定义全局前缀,未设置默认为 CC11001100_js_script_hook",
1313

14+
responseDebuggerHookType: "响应断点Hook方式:",
15+
responseDebuggerHookTypeTips: "此选项刷新页面后生效",
16+
responseDebuggerHookTypeUseProxyFunction: "使用代理函数实现Hook",
17+
responseDebuggerHookTypeUseRedeclareFunction: "直接修改网站callback函数体(注意可能会有作用域问题)",
18+
1419
isIgnoreJsSuffixRequest: "是否忽略.js后缀的请求:",
1520
isIgnoreJsSuffixRequestTips: "大多数时候.js后缀的请求都是单纯的加载JavaScript资源文件,可以选择忽略掉这类请求,当勾选的时候,控制台上也不会再打印.js请求",
1621

@@ -57,6 +62,18 @@ const chinese = {
5762
comment: "备注:",
5863
commentTips: "你可以输入一些备注,或者相关信息的一些上下文,以防止时间长了之后忘记。",
5964
commentPlaceholder: "好记性不如烂笔头",
65+
},
66+
console: {
67+
time: "时间",
68+
requestId: "请求ID",
69+
isJsonpRequest: "是否是jsonp请求",
70+
hostname: "请求域名",
71+
path: "请求路径",
72+
param: "请求参数",
73+
hash: "请求#hash",
74+
paramName: "参数名称",
75+
paramValue: "参数值",
76+
isJsonpCallback: "是否是jsonp回调函数",
6077
}
6178
};
6279

src/debugger/debugger-tester.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
const {getGlobalConfig} = require("../config/config");
2-
const {getUnsafeWindow} = require("../utils/scope-util");
3-
const {ObjectFunctionHook} = require("../hook/object-function-hook");
4-
const {ResponseFormatter} = require("../formatter/response-formatter");
5-
const {ResponseContext} = require("../context/response/response-context");
6-
71
class DebuggerTester {
82

93
/**

src/debugger/debugger.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
const {ObjectFunctionHook} = require("../hook/object-function-hook");
2-
const {getUnsafeWindow} = require("../utils/scope-util");
3-
const {getGlobalConfig} = require("../config/config");
4-
51
/**
62
* 表示一个jsonp的条件断点
73
*/

src/formatter/json-formatter.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
const styles = {
2+
key: 'color: green;',
3+
string: 'color: yellow;',
4+
number: 'color: blue;',
5+
boolean: 'color: red;',
6+
null: 'color: magenta;'
7+
};
8+
9+
function buildString(val, strArr, styleArr) {
10+
if (typeof val === 'string') {
11+
styleArr.push(styles.string);
12+
strArr.push('%c"' + val + '"');
13+
} else if (typeof val === 'number') {
14+
styleArr.push(styles.number);
15+
strArr.push('%c' + val);
16+
} else if (typeof val === 'boolean') {
17+
styleArr.push(styles.boolean);
18+
strArr.push('%c' + val);
19+
} else if (val === null) {
20+
styleArr.push(styles.null);
21+
strArr.push('%cnull');
22+
} else if (Array.isArray(val)) {
23+
strArr.push('[');
24+
for (let i = 0; i < val.length; i++) {
25+
if (i > 0) strArr.push(', ');
26+
buildString(val[i], strArr, styleArr);
27+
}
28+
strArr.push(']');
29+
} else if (typeof val === 'object' && val !== null) {
30+
strArr.push('{');
31+
const keys = Object.keys(val);
32+
for (let i = 0; i < keys.length; i++) {
33+
if (i > 0) strArr.push(', ');
34+
const key = keys[i];
35+
styleArr.push(styles.key);
36+
strArr.push('%c"' + key + '"');
37+
strArr.push(': ');
38+
buildString(val[key], strArr, styleArr);
39+
}
40+
strArr.push('}');
41+
}
42+
}
43+
44+
function highlightJSON(jsonObj) {
45+
const strArr = [];
46+
const styleArr = [];
47+
buildString(jsonObj, strArr, styleArr);
48+
return [strArr.join(''), ...styleArr];
49+
}
50+
51+
module.exports = {
52+
highlightJSON
53+
}

0 commit comments

Comments
 (0)