[油猴脚本开发指南]Fetch劫持的第二种方式
# 前言之前我们已经谈过了fetch劫持,但是由于那个代码相对较为复杂,cxxjackie提供了一个相对简单的方式,并未使用proxy劫持,我们这节课来分析一下。
```javascript
let oldfetch = fetch;
function fuckfetch() {
return new Promise((resolve, reject) => {
oldfetch.apply(this, arguments).then(response => {
const oldJson = response.json;
response.json = function() {
return new Promise((resolve, reject) => {
oldJson.apply(this, arguments).then(result => {
result.hook = 'success';
resolve(result);
});
});
};
resolve(response);
});
});
}
window.fetch = fuckfetch;
```
oldfetch保存了原fetch的引用
这时候我们对window.fetch挂载成我们的劫持函数,fuckfetch
因为fetch需要返回一个promise,所以这里我们通过
```
return new Promise((resolve, reject) => {})
```
包裹了一下,并且在原fetch函数内调用,并获取返回内容,对其进行一些处理并resolve返回过去。
附注:函数一旦返回一个Promise,我们只考虑输出相同的结果即可,而无须考虑Promise内处理过程的一致性。
```javascript
oldfetch.apply(this, arguments).then(response => {
const oldJson = response.json;
response.json = function() {
return new Promise((resolve, reject) => {
oldJson.apply(this, arguments).then(result => {
result.hook = 'success';
resolve(result);
});
});
};
resolve(response);
});
```
这里我们使用fetch的原函数,通过apply更改了this指针至自身,并且传入了参数。注意这点有一个需要注意的是,我们劫持函数的时候,由劫持函数调用原函数的过程中一定要使用call/apply进行修改this指针,来符合原来的调用过程。
在then后则是我们处理response的过程
```javascript
const oldJson = response.json;
response.json = function() {
return new Promise((resolve, reject) => {
oldJson.apply(this, arguments).then(result => {
result.hook = 'success';
resolve(result);
});
});
};
```
这部分代码是针对某些特定的函数进行过滤,我们可以对网页进行分析以及调试,或去返回内容进行查看,来判断调用了哪些函数。
这里以json为例进行劫持
首先保存了原json的引用
然后修改json属性为一个劫持函数
由于json返回的是一个promise对象,所以我们这里也需要返回一个promise
在promise内依然是对其原json函数进行调用,并修改了this指向以及参数,最后对其结果进行一定的修改,然后通过resolve(result)进行返回。
那么这节课我们就了解到了一个相对较为轻量的fetch劫持方法!
# 结语
撒花~
ggnba!!! 懒男孩 发表于 2021-9-22 17:15
ggnba!!!
好久没看到哥哥了 按键精灵您肯定知道,他们很多导师都有自己的一套或几套插件,就是一个函数集啦。这对新手非常友好。甚至不需要去了解实现的原理。拖过来直接就可以用。能不能有针对性的做一些这种类似的东西,函数命名规范化。比如网络劫持类,这种叫釜底抽薪式。XMLHttpRequest那个叫红杏出墙式,等等 脚本体验师001 发表于 2021-9-22 21:30
按键精灵您肯定知道,他们很多导师都有自己的一套或几套插件,就是一个函数集啦。这对新手非常友好。甚至不 ...
这个是有计划的!其实
准备以后有机会慢慢搞,先集中精力给教程搞完...
呜呜呜,教程东西太他妈多了.... 脚本体验师001 发表于 2021-9-22 21:30
按键精灵您肯定知道,他们很多导师都有自己的一套或几套插件,就是一个函数集啦。这对新手非常友好。甚至不 ...
那是因为按键有自己的框架和编辑器,而油猴是开放的,源码也是开放的,如果在scriptcat基础上运行,倒是可以封装你提到的库或者API,但是需要时间和资金 ```
//劫持前fetch
window.hook_fetch=window.fetch
//劫持后fetch
window.fetch= async function(...args){
let result = await hook_fetch(...args).then((e)=>{
let res =e.clone() //克隆response
e.text().then((ee)=>{
console.log("第一次text()"+ee)
//对劫持数据进行操作
})
return res //返回克隆的response
})
returnresult
}
//网站"原生"fetch
fetch("abc").then((e)=>{
e.text().then((ee)=>{
console.log("第二次text()"+ee)
//网站"原生"操作
})
})
```
话说response的stream虽然只能读一次,但是response本身能用.clone()的方式被克隆(这不是扯淡吗 那stream只读一次有什么用)
感觉可以利用response.clone()克隆response,直接把原始response复制一份给网站原生的then,然后我们对原本的response就可以爱怎么操作怎么操作了
随便写了个代码,GG看看有没有什么可以改进的(我异步不是很熟练 应该是这么写的吧)
!(data/attachment/forum/202207/01/165817mfk4yykyzfratwg5.png) steven026 发表于 2022-7-1 16:59
```
//劫持前fetch
window.hook_fetch=window.fetch
你这个没有起到修改response的效果啊,只是返回了一份复制品,网站读到的response还是原来的,这个劫持的目的就是让返回值发生变化。 cxxjackie 发表于 2022-7-1 20:40
你这个没有起到修改response的效果啊,只是返回了一份复制品,网站读到的response还是原来的,这个劫持的 ...
```
//劫持前fetch
window.hook_fetch=window.fetch
//劫持后fetch
window.fetch= async function(...args){
return await hook_fetch(...args).then((e)=>{
let res =e.clone() //克隆response
e.text().then((ee)=>console.log("原始response内容",ee))
res.text=()=>{return new Promise((resolve)=>{resolve("hooked")})} //修改返回内容
return res //返回克隆并修改的response
})
}
//网站"原生"fetch
fetch("https://bbs.tampermonkey.net.cn/").then((e)=>{
e.text().then((ee)=>{
console.log("修改后response内容",ee)
//网站"原生"操作
})
})
```
要修改返回内容的话,我写成了这个样子,GG看下这样会有什么问题吗?
!(data/attachment/forum/202207/01/220236q2nykwnng3xyznih.png) steven026 发表于 2022-7-1 22:02
```
//劫持前fetch
window.hook_fetch=window.fetch
这样是覆盖,不能在原数据的基础上修改,或者把e.text().then挪到Promise里面,先取得原数据再修改返回就好了,不过这样就跟这篇的思路完全一样了,而且多克隆了一个response,可能产生额外的性能开销。
页:
[1]
2