Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions goat/jsonp-request-param-encrypt/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
这是一个jsonp请求参数有加密的例子。
1 change: 1 addition & 0 deletions goat/jsonp-response-encrypt/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
这是一个jsonp请求的响应被加密的例子。
16 changes: 16 additions & 0 deletions goat/script-src-encrypt/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@





这是一个script请求中携带加密参数的例子。










2 changes: 1 addition & 1 deletion src/analyzer/request-analyzer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
7 changes: 7 additions & 0 deletions src/config/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

}
Expand Down
16 changes: 16 additions & 0 deletions src/context/request/param.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const {repeat} = require("../../utils/string-util");

/**
* 表示url路径中的一个参数,对于script类型的请求来说,它只有query string类型的参数,因为它无法携带请求体
*/
Expand All @@ -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 = {
Expand Down
35 changes: 34 additions & 1 deletion src/context/request/request-context.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const {Param} = require("./param");
const {repeat} = require("../../utils/string-util");

/**
* 用于封装请求的上下文
Expand All @@ -22,7 +23,8 @@ class RequestContext {
this.host = host;
this.port = port;
this.path = path;
this.params = params;
// 避免为空
this.params = params || [];
this.hash = hash;
}

Expand Down Expand Up @@ -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 = {
Expand Down
4 changes: 4 additions & 0 deletions src/context/response/response-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ class ResponseContext {

}

toHumanReadable() {
return "";
}

}

module.exports = {
Expand Down
40 changes: 39 additions & 1 deletion src/context/script/script-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}

}
Expand Down
23 changes: 23 additions & 0 deletions src/debugger/debugger.js
Original file line number Diff line number Diff line change
@@ -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的条件断点
Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
});
}
Expand Down
4 changes: 2 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
17 changes: 17 additions & 0 deletions src/utils/string-util.js
Original file line number Diff line number Diff line change
@@ -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
}