编程猫账号保护

保护你的编程猫账号。

< Feedback on 编程猫账号保护

Review: Good - script works

§
Posted: 21.08.2024.

大佬xhr怎么劫持的,没看懂,能不能讲下思路

SLIGHTNINGAuthor
§
Posted: 22.08.2024.

新建一个假的xhr,把新xhr的属性都指向原xhr。例构造函数中的的代码:

for (let key in XHR) {
    if (typeof XHR[key] == "function") {
        this[key] = XHR[key].bind(XHR)
    } else {
        Object.defineProperty(this, key, {  // 让新xhr的属性都指向原xhr
            get() {
                return XHR[key]
            },
            set(value) {
                XHR[key] = value
            },
            configurable: true  // 允许配置,使属性可以被重新定义,方便后期修改属性
        })
    }
}

重新定义open、send方法:

Object.defineProperty(this, "open", {  // 如果前面没有设置`configurable: true`,这里就会报错,因为`open`已经被定义过了。
    value: function (method, url) {
        this.__url = url  // 把参数存下来,方便在`send`中获取
        this.__openArguments = arguments
        XHR.open.apply(XHR, arguments)
    }
})
Object.defineProperty(this, "send", {
    value: function () {
        onIntercept(this.__url, () => {
            XHR.send.apply(XHR, arguments)  // 如果没有要修改的,就用原xhr发送
        }, reject, (callback) => {
            modifyResponse(this, function (XHR) {
                let { status, text } = callback({
                    status: XHR.status,
                    text: XHR.responseText
                })
                let result = {}
                if (status != null) {
                    result.states = status
                    result.statesText = String(status)
                }
                if (text != null) {
                    result.response = text
                    result.responseText = text
                }
                return result
            })
        })
    }
})

在修改请求时,不能用直接调用原xhr发送请求,因为原xhr上的事件监听器可能比此处的代码更早收到完成事件,这样这些事件监听器会获取到修改前的响应。此处则创建了一个新的xhr,并用新的xhr发送请求,并将请求修改后通过forgeResponse构造响应。

function modifyResponse(XHR, callback) {
    let originalXHR = new originalXMLHttpRequest()  // 新建一个xhr发送请求
    originalXHR.withCredentials = XHR.withCredentials
    originalXHR.open.apply(originalXHR, XHR.__openArguments)
    originalXHR.onreadystatechange = function () {
        if (originalXHR.readyState == 4) {
            // 收到请求后,把响应复制到假xhr上
            for (let key of ["status", "statusText", "responseType", "response", "responseText"]) {
                Object.defineProperty(XHR, key, {
                    value: originalXHR[key]
                })
            }
            forgeResponse(XHR, callback(XHR))  // 修改响应并通知假xhr收到响应
        }
    }
    originalXHR.send()
}

Post reply

Sign in to post a reply.