├── README.md └── 油猴脚本 ├── force_status_and_modify_json.js └── hook_localStorage_sessionStorage_getItem.js /README.md: -------------------------------------------------------------------------------- 1 | # adsec_file 2 | 此文件用于配套公众号“卫界安全-阿呆攻防”中所涉及的代码类文档 3 | 4 | -------------------------------------------------------------------------------- /油猴脚本/force_status_and_modify_json.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name combined_xhr_fetch_modifier 3 | // @version 2025-04-26 4 | // @description 拦截 XMLHttpRequest 和 fetch 请求,强制状态码为 200,并递归修改响应体 JSON 中指定字段的值,支持数组和嵌套对象,特殊处理 data 键值为 null 改为 {}。 5 | // @author 阿呆攻防 6 | // @match *://*/* 7 | // @grant none 8 | // ==/UserScript== 9 | 10 | (function() { 11 | 'use strict'; 12 | 13 | // 配置:要修改的字段和目标值(支持多个) 14 | const MODIFY_CONFIG = [ 15 | { field: 'success', newValue: '1' }, 16 | { field: 'errorCode', newValue: "" }, 17 | ]; 18 | 19 | // 递归修改 JSON 中的指定字段 20 | function modifyJsonRecursively(data, config) { 21 | if (!data || typeof data !== 'object') { 22 | return data; 23 | } 24 | 25 | // 处理数组 26 | if (Array.isArray(data)) { 27 | return data.map(item => modifyJsonRecursively(item, config)); 28 | } 29 | 30 | // 处理对象 31 | const result = { ...data }; 32 | for (const key in result) { 33 | if (Object.prototype.hasOwnProperty.call(result, key)) { 34 | // 特殊处理:当 key 为 'data' 且值为 null 时,改为 {} 35 | if (key === 'data' && result[key] === null) { 36 | console.log(`Modifying field "${key}" from null to {}`); 37 | result[key] = {}; 38 | } else { 39 | // 检查是否需要修改当前键 40 | const configItem = config.find(item => item.field === key); 41 | if (configItem) { 42 | console.log(`Modifying field "${key}" from "${result[key]}" to "${configItem.newValue}"`); 43 | result[key] = configItem.newValue; 44 | } else { 45 | // 递归处理嵌套对象或数组 46 | result[key] = modifyJsonRecursively(result[key], config); 47 | } 48 | } 49 | } 50 | } 51 | return result; 52 | } 53 | 54 | // --- 拦截 XMLHttpRequest --- 55 | const OriginalXMLHttpRequest = window.XMLHttpRequest; 56 | 57 | function CustomXMLHttpRequest() { 58 | const xhr = new OriginalXMLHttpRequest(); 59 | const xhrInfo = { method: '', url: '' }; 60 | 61 | // 代理 open 方法以捕获请求信息 62 | const originalOpen = xhr.open; 63 | xhr.open = function(method, url, async, user, password) { 64 | xhrInfo.method = method || 'GET'; 65 | xhrInfo.url = url; 66 | return originalOpen.apply(this, arguments); 67 | }; 68 | 69 | // 定义 status 属性,始终返回 200 70 | Object.defineProperty(xhr, 'status', { 71 | get: function() { 72 | const originalStatus = this._originalStatus !== undefined ? this._originalStatus : 0; 73 | console.log(`XHR [${xhrInfo.method} ${xhrInfo.url}] Original status: ${originalStatus}, Forced to: 200`); 74 | return 200; 75 | }, 76 | configurable: true 77 | }); 78 | 79 | // 捕获原始状态码并修改 JSON 响应 80 | xhr.addEventListener('readystatechange', function() { 81 | if (this.readyState === OriginalXMLHttpRequest.DONE) { 82 | try { 83 | Object.defineProperty(this, '_originalStatus', { 84 | value: this._originalStatus || this.status, 85 | writable: false, 86 | configurable: true 87 | }); 88 | } catch (e) { 89 | console.warn('Failed to capture XHR original status:', e); 90 | } 91 | } 92 | }); 93 | 94 | // 拦截 load 事件以修改 JSON 响应 95 | xhr.addEventListener('load', function() { 96 | if (xhr.getResponseHeader('Content-Type')?.includes('application/json')) { 97 | try { 98 | const originalResponse = xhr.responseText; 99 | const jsonData = JSON.parse(originalResponse); 100 | const modifiedJson = modifyJsonRecursively(jsonData, MODIFY_CONFIG); 101 | const modifiedResponseText = JSON.stringify(modifiedJson); 102 | 103 | console.log(`XHR [${xhrInfo.method} ${xhrInfo.url}] Modified JSON response`); 104 | 105 | // 劫持 response 和 responseText 属性 106 | Object.defineProperty(xhr, 'responseText', { 107 | get: function() { 108 | return modifiedResponseText; 109 | }, 110 | configurable: true 111 | }); 112 | Object.defineProperty(xhr, 'response', { 113 | get: function() { 114 | return modifiedResponseText; 115 | }, 116 | configurable: true 117 | }); 118 | } catch (e) { 119 | console.error(`Failed to modify JSON response for [${xhrInfo.method} ${xhrInfo.url}]:`, e); 120 | } 121 | } 122 | }); 123 | 124 | return new Proxy(xhr, { 125 | get(target, prop) { 126 | if (prop === 'status') { 127 | return 200; 128 | } 129 | return typeof target[prop] === 'function' ? target[prop].bind(target) : target[prop]; 130 | }, 131 | set(target, prop, value) { 132 | target[prop] = value; 133 | return true; 134 | } 135 | }); 136 | } 137 | 138 | window.XMLHttpRequest = CustomXMLHttpRequest; 139 | 140 | // --- 拦截 fetch --- 141 | const originalFetch = window.fetch; 142 | 143 | window.fetch = async function(input, init) { 144 | const requestInfo = { 145 | method: 'GET', 146 | url: '' 147 | }; 148 | 149 | if (typeof input === 'string') { 150 | requestInfo.url = input; 151 | } else if (input instanceof Request) { 152 | requestInfo.url = input.url; 153 | requestInfo.method = input.method || 'GET'; 154 | } 155 | 156 | if (init && init.method) { 157 | requestInfo.method = init.method.toUpperCase(); 158 | } 159 | 160 | const response = await originalFetch(input, init); 161 | 162 | // 读取原始响应体 163 | const originalBody = await response.text(); 164 | let modifiedBody = originalBody; 165 | 166 | // 处理 JSON 响应 167 | if (response.headers.get('Content-Type')?.includes('application/json')) { 168 | try { 169 | const jsonData = JSON.parse(originalBody); 170 | const modifiedJson = modifyJsonRecursively(jsonData, MODIFY_CONFIG); 171 | modifiedBody = JSON.stringify(modifiedJson); 172 | console.log(`Fetch [${requestInfo.method} ${requestInfo.url}] Modified JSON response`); 173 | } catch (e) { 174 | console.error(`Failed to modify JSON response for [${requestInfo.method} ${requestInfo.url}]:`, e); 175 | } 176 | } 177 | 178 | // 创建新的 Response 对象,强制 status 为 200 179 | const customResponse = new Response(modifiedBody, { 180 | status: 200, 181 | statusText: 'OK', 182 | headers: response.headers 183 | }); 184 | 185 | customResponse._originalStatus = response.status; 186 | 187 | return new Proxy(customResponse, { 188 | get(target, prop) { 189 | if (prop === 'status') { 190 | console.log(`Fetch [${requestInfo.method} ${requestInfo.url}] Original status: ${target._originalStatus}, Forced to: 200`); 191 | return 200; 192 | } 193 | if (prop === 'ok') { 194 | return true; 195 | } 196 | return typeof target[prop] === 'function' ? target[prop].bind(target) : target[prop]; 197 | } 198 | }); 199 | }; 200 | })(); -------------------------------------------------------------------------------- /油猴脚本/hook_localStorage_sessionStorage_getItem.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name hook_localStorage_sessionStorage_getItem 3 | // @version 2025-04-26 4 | // @description 重写 localStorage.getItem 和 sessionStorage.getItem 方法,打印调用堆栈信息。 5 | // @author 阿呆攻防 6 | // @match *://*/* 7 | // @grant none 8 | // ==/UserScript== 9 | 10 | (function() { 11 | 'use strict'; 12 | 13 | // Hook localStorage.getItem 14 | const originalLocalStorageGetItem = localStorage.getItem; 15 | localStorage.getItem = function(key) { 16 | console.log('localStorage.getItem called with key:', key); 17 | console.log(new Error().stack); 18 | console.log("-----------------------------------------------------------------------------------------------------"); 19 | return originalLocalStorageGetItem.apply(localStorage, [key]); 20 | }; 21 | 22 | // Hook sessionStorage.getItem 23 | const originalSessionStorageGetItem = sessionStorage.getItem; 24 | sessionStorage.getItem = function(key) { 25 | console.log('sessionStorage.getItem called with key:', key); 26 | console.log(new Error().stack); 27 | console.log("-----------------------------------------------------------------------------------------------------"); 28 | return originalSessionStorageGetItem.apply(sessionStorage, [key]); 29 | }; 30 | })(); --------------------------------------------------------------------------------