找回密码
 立即注册
快捷导航

[Html/Css/JS] 油猴脚本 - Hook XmlhttpRequest

[复制链接]
庶民 2023-6-13 15:53:34 | 显示全部楼层
本帖最后由 庶民 于 2023-6-13 15:55 编辑
// ==UserScript==
// @name         XmlhttpRequest Hook
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        https://A.net.cn/*
// @grant        none
// ==/UserScript==

function addXMLRequestCallback(callback){
    var oldSend, i;
    if( XMLHttpRequest.callbacks ) {
        // 判断XMLHttpRequest对象下是否存在回调列表,存在就push一个回调的函数
        // we've already overridden send() so just add the callback
        XMLHttpRequest.callbacks.push( callback );
    } else {
        // create a callback queue
        XMLHttpRequest.callbacks = [callback];
        // 如果不存在则在xmlhttprequest函数下创建一个回调列表
        // store the native send()
        oldSend = XMLHttpRequest.prototype.send;
        // 获取旧xml的send函数,并对其进行劫持
        // override the native send()
        XMLHttpRequest.prototype.send = function(){
            // process the callback queue
            // the xhr instance is passed into each callback but seems pretty useless
            // you can't tell what its destination is or call abort() without an error
            // so only really good for logging that a request has happened
            // I could be wrong, I hope so...
            // EDIT: I suppose you could override the onreadystatechange handler though
            for( i = 0; i < XMLHttpRequest.callbacks.length; i++ ) {
                XMLHttpRequest.callbacks[i]( this );
            }
            // 循环回调xml内的回调函数
            // call the native send()
            oldSend.apply(this, arguments);
            // 由于我们获取了send函数的引用,并且复写了send函数,这样我们在调用原send的函数的时候,需要对其传入引用,而arguments是传入的参数
        }
    }
}

// e.g.
addXMLRequestCallback( function( xhr ) {
            // 调用劫持函数,填入一个function的回调函数
                // 回调函数监听了对xhr调用了监听load状态,并且在触发的时候再次调用一个function,进行一些数据的劫持以及修改
        xhr.addEventListener("load", function(){
        if ( xhr.readyState == 4 && xhr.status == 200 ) {
            console.log( xhr.responseURL );
        }
    });

});



回复

使用道具 举报

主题

0

回帖

1050

积分

功行圆满

 楼主| 庶民 2023-6-13 16:30:50 | 显示全部楼层

对xhr的返回内容劫持

如果只关心返回内容的话,是不是没必要劫持整个对象,只用Object.defineProperty劫持属性比较好?可以试一下这段代码,也不确定性能会不会比proxy好:

const xhrOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function() {
  const xhr = this;
  if (arguments[1] == hookUrl) {
    const property = xhr.responseType ? 'response' : 'responseText';
    const getter = xhr.__lookupGetter__(property);
    Object.defineProperty(xhr, property, {
      get: () => {
        let result = getter.call(xhr);
        console.log(result);
        return result;
      }
    });
  }
  return xhrOpen.apply(xhr, arguments);
};

这有个问题就是 __lookupGetter__ 的兼容性不是很好,可能有其他获取getter的办法?还有个比较dirty的做法是open以后延迟100毫秒再劫持onreadystatechange,从readystatechange里面对response做手脚

引用:https://bbs.tampermonkey.net.cn/forum.php?mod=redirect&goto=findpost&ptid=835&pid=4707


   
回复

使用道具 举报

主题

0

回帖

1050

积分

功行圆满

 楼主| 庶民 2023-6-13 16:39:22 | 显示全部楼层
本帖最后由 庶民 于 2023-6-13 16:43 编辑

AI
使用Proxy劫持XMLHttpRequest 的响应 (注意:proxy会在频繁通信中降低性能)

// ==UserScript==
// @name         XMLHttpRequest Proxy Demo
// @namespace    http://tampermonkey-demo/
// @version      1
// @description  Intercept XMLHttpRequest responses using Proxy
// @match        https://example.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Create a Proxy object to intercept XMLHttpRequest responses
    const responseProxy = new Proxy(XMLHttpRequest.prototype, {
        get(target, property, receiver) {
            if (property === 'onreadystatechange') {
                // Intercept the onreadystatechange event handler
                return function() {
                    const xhr = this;
                    const oldReadyStateChange = xhr.onreadystatechange;
                    xhr.onreadystatechange = function() {
                        if (xhr.readyState === 4 && xhr.status === 200) {
                            // Intercept the response when readyState is 4 (DONE) and status is 200 (OK)
                            const responseText = xhr.responseText;
                            console.log('Intercepted response:', responseText);
                            // Modify the response as needed
                            const modifiedResponseText = responseText.replace(/foo/g, 'bar');
                            // Call the original onreadystatechange event handler with the modified response
                            oldReadyStateChange.call(xhr, modifiedResponseText);
                        } else {
                            // Call the original onreadystatechange event handler for other cases
                            oldReadyStateChange.call(xhr);
                        }
                    };
                };
            } else {
                // Return the original XMLHttpRequest property for other cases
                return Reflect.get(target, property, receiver);
            }
        }
    });

    // Replace the original XMLHttpRequest with the Proxy object
    XMLHttpRequest.prototype = responseProxy;
})();

上面这脚本使用 Proxy 对 XMLHttpRequest.prototype 对象进行劫持,拦截了其 onreadystatechange 属性的读取操作,并返回一个新的函数,该函数会在 XMLHttpRequest 对象的 onreadystatechange 事件触发时被调用。

在这个函数中,我们可以拦截 XMLHttpRequest 的响应,修改它并返回给原始的 onreadystatechange 事件处理程序。


   
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼
3楼
温馨提示

关于 注册码 问题

      由于近期经常大量注册机器人注册发送大量广告,本站开启免费入群领取注册码注册网站账号,注册码在群公告上贴着...

关于 注册码 问题

      由于近期经常大量注册机器人注册发送大量广告,本站开启免费入群领取注册码注册网站账号,注册码在群公告上贴着...

Archiver|手机版|小黑屋|DLSite

GMT+8, 2024-11-23 00:53

Powered by Discuz! X3.5 and PHP8

快速回复 返回顶部 返回列表