您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
深度查询(Shadow DOM/iframe)核心执行器(页面上下文)。仅接受带签名消息,页面代码无法直接调用。
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/548365/1654734/DeepQuery%20Secure%20Core%20%28page-world%20only%29.js
// ==UserScript== // @name DeepQuery Secure Core (page-world only) // @namespace dq.secure.v2 // @version 2.0.0 // @description 深度查询(Shadow DOM/iframe)核心执行器(页面上下文)。仅接受带签名消息,页面代码无法直接调用。 // @author you // @match http://*/* // @match https://*/* // @include about:blank // @run-at document-start // @grant none // @inject-into page // ==/UserScript== (function () { 'use strict'; /************** 配置 **************/ // 通道名(随便换成很长的随机串,增加混淆) const CHANNEL = '__DQ_SECURE_V2__'; // HMAC 的密钥以“片段+重组”方式藏在闭包里,页面拿不到;你可以把片段改成你自己的随机串 // 强烈建议自行换成至少 32 字节以上随机 base64 的若干段 const KEY_PARTS = [ 'dW5hcmFuZG9tLWtleS1zZWVkLQ', // 示例片段(请务必替换) 'tZXBsZWFzZS1yZXBsYWNlLW1l', // 示例片段(请务必替换) 'LXdpdGgtYS1wcm9wZXItb25l' // 示例片段(请务必替换) ]; // 允许的时间偏差(ms)与 nonce 存活(ms) const MAX_SKEW = 60_000; // 60s const NONCE_TTL = 10 * 60_000; // 10min // --- 工具:base64 与 HMAC --- const te = new TextEncoder(); const td = new TextDecoder(); function b64ToU8(b64) { // 补 '=' const pad = b64.length % 4 ? (4 - b64.length % 4) : 0; const s = b64 + '='.repeat(pad); const bin = atob(s.replace(/-/g, '+').replace(/_/g, '/')); const u8 = new Uint8Array(bin.length); for (let i = 0; i < bin.length; i++) u8[i] = bin.charCodeAt(i); return u8; } function u8eq(a, b) { if (a.byteLength !== b.byteLength) return false; let v = 0; for (let i = 0; i < a.byteLength; i++) v |= (a[i] ^ b[i]); return v === 0; } async function sha256U8(u8) { const buf = await crypto.subtle.digest('SHA-256', u8); return new Uint8Array(buf); } async function hmacSignRaw(key, u8) { const k = await crypto.subtle.importKey( 'raw', key, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign'] ); const sig = await crypto.subtle.sign('HMAC', k, u8); return new Uint8Array(sig); } const KEY_U8 = (() => { // 简单拼接再 sha256,避免直接把明文 key 出现在脚本文本中 const joined = KEY_PARTS.join(''); const u8 = b64ToU8(joined); return u8; })(); // --- 防重放 --- const seen = new Map(); // nonce -> ts function sweep() { const now = Date.now(); for (const [n, t] of seen) if (now - t > NONCE_TTL) seen.delete(n); } setInterval(sweep, 30_000); async function verifySig(msg) { // msg: {id, ts, nonce, spec, sigB64} if (!msg || typeof msg !== 'object') return false; const { id, ts, nonce, spec, sigB64 } = msg; if (!id || typeof ts !== 'number' || !nonce || !sigB64) return false; const skew = Math.abs(Date.now() - ts); if (skew > MAX_SKEW) return false; if (seen.has(nonce)) return false; // 重放 // 绑定消息体,防止被改内容重放 const specJson = JSON.stringify(spec || {}); const payload = te.encode(id + '\n' + ts + '\n' + nonce + '\n'); const bodyHash = await sha256U8(te.encode(specJson)); const toSign = new Uint8Array(payload.length + bodyHash.length); toSign.set(payload, 0); toSign.set(bodyHash, payload.length); const expect = await hmacSignRaw(KEY_U8, toSign); const got = b64ToU8(sigB64); const ok = u8eq(expect, got); if (ok) { seen.set(nonce, ts); } return ok; } /************** 查询核心(与早先版本一致) **************/ const SHADOW_KEY = Symbol.for('__dq_shadow__'); const isTop = (window === window.top); function safeQueryAll(root, sel) { try { return Array.from(root.querySelectorAll(sel)); } catch { return []; } } function firstByIndex(list, idx) { if (!list || !list.length) return null; return typeof idx === 'number' ? (list[idx] || null) : list[0]; } (function hookAttachShadowEarly() { try { const orig = Element.prototype.attachShadow; if (!orig || orig.__dq_hooked__) return; Object.defineProperty(Element.prototype, 'attachShadow', { configurable: true, enumerable: false, writable: true, value: function (init) { const root = orig.call(this, init); try { Object.defineProperty(this, SHADOW_KEY, { configurable: true, enumerable: false, writable: false, value: root }); } catch {} return root; } }); Element.prototype.attachShadow.__dq_hooked__ = true; } catch {} })(); function ensureOpenShadowReference(host) { try { if (!host) return; if (host[SHADOW_KEY]) return; if (host.shadowRoot) { Object.defineProperty(host, SHADOW_KEY, { configurable: true, enumerable: false, writable: false, value: host.shadowRoot }); } } catch {} } function parseChain(chain) { if (typeof chain === 'string') { const parts = chain.split('>>>').map(s => s.trim()).filter(Boolean); const steps = []; parts.forEach((seg, i) => { if (i === 0) steps.push({ find: seg }); else steps.push({ shadow: true }, { find: seg }); }); return steps; } return (Array.isArray(chain) ? chain : []); } function toPlainRect(r) { return r ? { x: r.x, y: r.y, width: r.width, height: r.height, top: r.top, left: r.left, right: r.right, bottom: r.bottom } : null; } function pickInfo(el, pick = {}) { if (!el) return { ok: false, error: 'ELEMENT_NOT_FOUND' }; const res = { ok: true, tag: el.tagName, exists: true }; if (pick.attr) res.attr = el.getAttribute(pick.attr); if (pick.prop) try { res.prop = el[pick.prop]; } catch { res.prop = undefined; } if (pick.text) res.text = el.textContent; if (pick.html) res.html = el.innerHTML; if (pick.outerHTML) res.outerHTML = el.outerHTML; if (pick.value) res.value = (el.value !== undefined ? el.value : undefined); if (pick.rect) res.rect = toPlainRect(el.getBoundingClientRect ? el.getBoundingClientRect() : null); if (pick.styles && Array.isArray(pick.styles) && pick.styles.length) { const cs = getComputedStyle(el); const map = {}; pick.styles.forEach(k => { map[k] = cs.getPropertyValue(k); }); res.styles = map; } if (pick.dataset) { const dst = {}; (Array.isArray(pick.dataset) ? pick.dataset : [pick.dataset]).forEach(k => { dst[k] = el.dataset ? el.dataset[k] : undefined; }); res.dataset = dst; } return res; } function deepQueryOnce(rootLike, chainSteps) { let root = (rootLike instanceof ShadowRoot || rootLike instanceof Document) ? rootLike : document; let current = root; let lastEl = null; for (const step of chainSteps) { if (step.shadow) { if (!lastEl) return null; ensureOpenShadowReference(lastEl); const sr = lastEl.shadowRoot || lastEl[SHADOW_KEY]; if (!sr) return null; current = sr; continue; } if (step.find) { const idx = (typeof step.index === 'number') ? step.index : null; const list = safeQueryAll(current, step.find); lastEl = firstByIndex(list, idx); if (!lastEl) return null; continue; } return null; } return lastEl; } async function waitForDeepQuery(rootLike, chainSteps, timeout = 0) { const start = Date.now(); const tryOnce = () => deepQueryOnce(rootLike, chainSteps); let el = tryOnce(); if (el || !timeout) return el; return new Promise((resolve) => { const limit = start + timeout; const observer = new MutationObserver(() => { el = tryOnce(); if (el) { observer.disconnect(); resolve(el); } else if (Date.now() > limit) { observer.disconnect(); resolve(null); } }); observer.observe(document, { childList: true, subtree: true, attributes: true }); const t = setTimeout(() => { try { observer.disconnect(); } catch {} resolve(null); }, timeout); const tick = () => { el = tryOnce(); if (el) { clearTimeout(t); try { observer.disconnect(); } catch {} resolve(el); } else if (Date.now() <= limit) requestAnimationFrame(tick); }; requestAnimationFrame(tick); }); } // frame 选择 function findTargetFrames(step) { const cfg = (typeof step === 'string') ? { selector: step } : (step || {}); const sel = cfg.selector || 'iframe'; const all = safeQueryAll(document, sel).filter(n => n && n.tagName === 'IFRAME'); if (!all.length) return []; if (typeof cfg.index === 'number') { const one = all[cfg.index]; return (one && one.contentWindow) ? [one.contentWindow] : []; } return all.map(el => el.contentWindow).filter(Boolean); } /************** 消息收发(带签名) **************/ const pending = new Map(); // id -> resolver function rid() { return (Date.now().toString(36) + Math.random().toString(36).slice(2, 10)).toUpperCase(); } function sendMessage(targetWin, payload) { try { targetWin.postMessage({ [CHANNEL]: payload }, '*'); } catch {} } async function forwardOrExec(msg, sourceWin) { const { id, spec = {} } = msg; const framePath = Array.isArray(spec.framePath) ? spec.framePath : []; if (framePath.length > 0) { const [step, ...rest] = framePath; const targets = findTargetFrames(step); if (!targets.length) { sendMessage(sourceWin || window.parent, { cmd: 'RESP', id, res: { ok: false, error: 'FRAME_NOT_FOUND' } }); return; } // fan-out:向匹配目标逐一转发,取第一个成功的结果 const subResults = await Promise.all(targets.map(t => new Promise(async (resolve) => { const subId = rid(); pending.set(subId, { resolve }); // 用相同的 spec 但缩短 framePath;**重新签名** const subMsg = { cmd: 'REQ', id: subId, ts: Date.now(), nonce: rid() + Math.random().toString(36).slice(2), spec: { ...spec, framePath: rest } }; // 签名 const payload = te.encode(subMsg.id + '\n' + subMsg.ts + '\n' + subMsg.nonce + '\n'); const bodyHash = await sha256U8(te.encode(JSON.stringify(subMsg.spec))); const toSign = new Uint8Array(payload.length + bodyHash.length); toSign.set(payload, 0); toSign.set(bodyHash, payload.length); const sigU8 = await hmacSignRaw(KEY_U8, toSign); const sigB64 = btoa(String.fromCharCode(...sigU8)); sendMessage(t, { ...subMsg, sigB64 }); // 超时保护 setTimeout(() => { if (pending.has(subId)) { pending.delete(subId); resolve({ ok: false, error: 'TIMEOUT_FORWARD' }); } }, typeof spec.timeout === 'number' ? Math.max(200, spec.timeout) : 5000); }))); const ok = subResults.find(r => r && r.ok); const res = ok || subResults[0] || { ok: false, error: 'NO_RESULT' }; sendMessage(sourceWin || window.parent, { cmd: 'RESP', id, res }); return; } // 在本帧执行 try { const chain = parseChain(spec.chain); const el = await waitForDeepQuery(document, chain, typeof spec.timeout === 'number' ? spec.timeout : 0); const res = pickInfo(el, spec.pick || {}); sendMessage(sourceWin || window.parent, { cmd: 'RESP', id, res }); } catch (err) { sendMessage(sourceWin || window.parent, { cmd: 'RESP', id, res: { ok: false, error: 'EXEC_ERROR', message: String(err && err.message || err) } }); } } window.addEventListener('message', async (e) => { const msg = e.data && e.data[CHANNEL]; if (!msg) return; // 响应回传(promise 归还) if (msg.cmd === 'RESP' && msg.id && pending.has(msg.id)) { const { resolve } = pending.get(msg.id); pending.delete(msg.id); resolve(msg.res); return; } // 进入点:必须验签 if (msg.cmd === 'REQ') { const ok = await verifySig(msg); if (!ok) { sendMessage(e.source || window.parent, { cmd: 'RESP', id: msg.id, res: { ok: false, error: 'UNAUTHORIZED' } }); return; } // 验签通过,执行/转发 await forwardOrExec(msg, e.source || window.parent); } }, false); if (isTop) { try { console.debug('[DeepQuery Secure Core] ready. Listening on', CHANNEL); } catch {} } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址