From 48279007fddcb387dedc8d93045d54b313054ab7 Mon Sep 17 00:00:00 2001 From: CC11001100 Date: Sat, 21 Dec 2024 22:57:13 +0800 Subject: [PATCH 1/2] fix: NPE --- src/analyzer/request-analyzer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyzer/request-analyzer.js b/src/analyzer/request-analyzer.js index 8e9a746..1e759d8 100644 --- a/src/analyzer/request-analyzer.js +++ b/src/analyzer/request-analyzer.js @@ -16,7 +16,7 @@ class RequestAnalyzer { requestContext.params = this.computeParamsJsonpCallbackScore(requestContext.params); // 选出其中可能性最大的一个参数作为jsonp callback参数 - if (requestContext.params && requestContext.params[0].jsonpCallbackScore > 0) { + if (requestContext.params && requestContext.params.length && requestContext.params[0].jsonpCallbackScore > 0) { requestContext.params[0].isJsonpCallback = true; } From 2cbba5937f0a52dfe1cd705943131ffae348e4ca Mon Sep 17 00:00:00 2001 From: CC11001100 Date: Sun, 22 Dec 2024 00:58:15 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=9C=A8?= =?UTF-8?q?=E6=96=AD=E7=82=B9=E6=97=B6=E4=BB=A5=E4=BA=BA=E7=B1=BB=E5=8F=AF?= =?UTF-8?q?=E8=AF=BB=E5=BD=A2=E5=BC=8F=E5=B1=95=E7=A4=BA=E5=BD=93=E5=89=8D?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=E7=9A=84=E4=B8=8A=E4=B8=8B=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- goat/jsonp-request-param-encrypt/README.md | 1 + goat/jsonp-response-encrypt/README.md | 1 + goat/script-src-encrypt/README.md | 16 +++++++++ src/config/config.js | 7 ++++ src/context/request/param.js | 16 +++++++++ src/context/request/request-context.js | 35 ++++++++++++++++++- src/context/response/response-context.js | 4 +++ src/context/script/script-context.js | 40 +++++++++++++++++++++- src/debugger/debugger.js | 23 +++++++++++++ src/index.js | 4 +-- src/utils/string-util.js | 17 +++++++++ 11 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 goat/jsonp-request-param-encrypt/README.md create mode 100644 goat/jsonp-response-encrypt/README.md create mode 100644 goat/script-src-encrypt/README.md create mode 100644 src/utils/string-util.js diff --git a/goat/jsonp-request-param-encrypt/README.md b/goat/jsonp-request-param-encrypt/README.md new file mode 100644 index 0000000..146d5d6 --- /dev/null +++ b/goat/jsonp-request-param-encrypt/README.md @@ -0,0 +1 @@ +这是一个jsonp请求参数有加密的例子。 diff --git a/goat/jsonp-response-encrypt/README.md b/goat/jsonp-response-encrypt/README.md new file mode 100644 index 0000000..b49e444 --- /dev/null +++ b/goat/jsonp-response-encrypt/README.md @@ -0,0 +1 @@ +这是一个jsonp请求的响应被加密的例子。 \ No newline at end of file diff --git a/goat/script-src-encrypt/README.md b/goat/script-src-encrypt/README.md new file mode 100644 index 0000000..4132d76 --- /dev/null +++ b/goat/script-src-encrypt/README.md @@ -0,0 +1,16 @@ + + + + + +这是一个script请求中携带加密参数的例子。 + + + + + + + + + + diff --git a/src/config/config.js b/src/config/config.js index e39ff1a..61ef200 100644 --- a/src/config/config.js +++ b/src/config/config.js @@ -9,8 +9,15 @@ class Config { * @param callbackFunctionParamName {String} 传递jsonp回调函数名字的参数,比如 "callback" */ constructor(urlPattern, callbackFunctionParamName) { + // 让用户能够自己指定前缀,也许会有一些拥有感?之前ast hook好像就有个哥们喜欢这样干... this.prefix = "CC11001100"; + + // 是否忽略.js后缀的请求 + this.isIgnoreJsSuffixRequest = true; + + // 是否忽略不是jsonp的请求 + this.isIgnoreNotJsonpRequest = true; } } diff --git a/src/context/request/param.js b/src/context/request/param.js index e415f5d..0522dd0 100644 --- a/src/context/request/param.js +++ b/src/context/request/param.js @@ -1,3 +1,5 @@ +const {repeat} = require("../../utils/string-util"); + /** * 表示url路径中的一个参数,对于script类型的请求来说,它只有query string类型的参数,因为它无法携带请求体 */ @@ -23,6 +25,20 @@ class Param { } + /** + * 把参数转为适合人类阅读的样式 + * + * @return {string} + */ + toHumanReadable(indent) { + const indentString = repeat(" ", indent); + if (this.isJsonpCallback) { + return `${indentString}${this.name} = ${this.value} <---- this param is jsonp callback function name` + } else { + return `${indentString}${this.name} = ${this.value}`; + } + } + } module.exports = { diff --git a/src/context/request/request-context.js b/src/context/request/request-context.js index 6d98848..12fe9f7 100644 --- a/src/context/request/request-context.js +++ b/src/context/request/request-context.js @@ -1,4 +1,5 @@ const {Param} = require("./param"); +const {repeat} = require("../../utils/string-util"); /** * 用于封装请求的上下文 @@ -22,7 +23,8 @@ class RequestContext { this.host = host; this.port = port; this.path = path; - this.params = params; + // 避免为空 + this.params = params || []; this.hash = hash; } @@ -85,6 +87,37 @@ class RequestContext { return null; } + /** + * + * @return {""|boolean} + */ + isJsSuffixRequest() { + return this.path && this.path.toLowerCase().endsWith(".js") + } + + /** + * 转成方便阅读的格式 + */ + toHumanReadable(indent) { + + const indentSpace = repeat(" ", indent); + + const msgs = []; + msgs.push(`${indentSpace}hostname: ${this.hostname}`); + msgs.push(`${indentSpace}path: ${this.path}`); + + msgs.push(`${indentSpace}params: `); + for (let param of this.params) { + msgs.push(param.toHumanReadable(indent + 4)); + } + + if (this.hash) { + msgs.push(`${indentSpace}hash: ${this.hash}`) + } + + return msgs.join("\n\n"); + } + } module.exports = { diff --git a/src/context/response/response-context.js b/src/context/response/response-context.js index 7d5cd99..136103c 100644 --- a/src/context/response/response-context.js +++ b/src/context/response/response-context.js @@ -31,6 +31,10 @@ class ResponseContext { } + toHumanReadable() { + return ""; + } + } module.exports = { diff --git a/src/context/script/script-context.js b/src/context/script/script-context.js index 2c54e50..20ae15a 100644 --- a/src/context/script/script-context.js +++ b/src/context/script/script-context.js @@ -25,7 +25,45 @@ class ScriptContext { * @returns {boolean} */ isJsonp() { - return this.responseContext.isJsonpResponse() || this.requestContext.isJsonpRequest(); + if (this.requestContext && this.requestContext.isJsonpRequest()) { + return true; + } + if (this.responseContext && this.responseContext.isJsonpResponse()) { + return true; + } + return false; + } + + /** + * 判断是否是请求的js文件 + * + * @return {""|boolean} + */ + isJsSuffixRequest() { + return this.requestContext && this.requestContext.isJsSuffixRequest(); + } + + /** + * + * @return {string} + */ + toHumanReadable() { + + const msgs = []; + + if (this.requestContext) { + msgs.push("Request Information: "); + msgs.push(this.requestContext.toHumanReadable(4)); + } + + msgs.push("\n\n"); + + if (this.responseContext) { + msgs.push("Response Information: ") + msgs.push(this.responseContext.toHumanReadable(4)); + } + + return msgs.join("\n\n"); } } diff --git a/src/debugger/debugger.js b/src/debugger/debugger.js index 23237e2..0a4c10a 100644 --- a/src/debugger/debugger.js +++ b/src/debugger/debugger.js @@ -1,6 +1,7 @@ const {ObjectFunctionHook} = require("../hook/object-function-hook"); const {getUnsafeWindow} = require("../utils/scope-util"); const {JsonpCallbackFunctionAnalyzer} = require("../analyzer/response-analyzer"); +const {globalConfig} = require("../config/config"); /** * 表示一个jsonp的条件断点 @@ -35,8 +36,23 @@ class Debugger { return; } + // 支持忽略js文件请求 + if (globalConfig.isIgnoreJsSuffixRequest && scriptContext.isJsSuffixRequest()) { + return; + } + + // 忽略不是jsonp的请求 + if (globalConfig.isIgnoreNotJsonpRequest && !scriptContext.isJsonp()) { + return; + } + // 请求断点 if (this.enableRequestDebugger) { + // 把一些相关的上下文赋值到变量方便断点命中这里的时候观察 + // _scriptContext中存放的是与当前的script请求相关的一些上下文信息 + const _scriptContext = scriptContext; + const humanReadableScriptInformation = scriptContext.toHumanReadable() + console.log(humanReadableScriptInformation); debugger; } @@ -54,8 +70,15 @@ class Debugger { } // 为响应体中的回调函数增加hook + const jsonpCallbackFunction = getUnsafeWindow()[jsonpCallbackFunctionName]; + if (!jsonpCallbackFunction) { + // TODO 2024-12-20 23:08:29 错误处理 + return; + } + // 跟进去这个 jsonpCallbackFunction 函数的代码位置就是jsonp的回调函数的逻辑,也是处理响应的逻辑 new ObjectFunctionHook(getUnsafeWindow(), jsonpCallbackFunctionName).addHook(function () { // 这里是脚本的响应断点,已经拦截到响应,跟进去holder函数就行了 + console.log(jsonpCallbackFunction); debugger; }); } diff --git a/src/index.js b/src/index.js index 350b10e..bf91312 100644 --- a/src/index.js +++ b/src/index.js @@ -8,8 +8,8 @@ const {Debugger} = require("./debugger/debugger"); // 增加可视化的配置 // 增加一个测试断点 - const jsonpDebugger = new Debugger("http://localhost:10010/?jsonp_callback=jsonpCallback_1734635066"); - debuggerManager.addDebugger(jsonpDebugger) + const jsonpDebugger = new Debugger(/.*/); + debuggerManager.addDebugger(jsonpDebugger); // 为document增加hook点 const unsafeWindow = getUnsafeWindow(); diff --git a/src/utils/string-util.js b/src/utils/string-util.js new file mode 100644 index 0000000..d893119 --- /dev/null +++ b/src/utils/string-util.js @@ -0,0 +1,17 @@ +/** + * + * @param s + * @param times + * @return {string} + */ +function repeat(s, times) { + const msgs = []; + for (let i = 0; i < times; i++) { + msgs.push(s); + } + return msgs.join(""); +} + +module.exports = { + repeat +} \ No newline at end of file