🎮ArcadeLab

手机沙箱实验台

by EpicCoder88
696 lines57.5 KB
▶ Play
<!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">
<title>手机沙箱实验台</title>
<style>
  * { box-sizing: border-box; margin: 0; padding: 0; }
  :root { --bg:#0a0e14; --panel:#161b22; --border:#30363d; --text:#e6edf3; --text-dim:#8b949e; --accent:#58a6ff; --green:#3fb950; --red:#f85149; --purple:#bc8cff; --radius:14px; --radius-sm:8px; --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace; }
  html, body { height:100%; font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif; background: radial-gradient(circle at 50% 30%, #1a2332 0%, #0a0e14 70%); color: var(--text); overflow: hidden; }
  .workbench { display:flex; height:100vh; padding:14px; gap:16px; align-items:center; justify-content:center; }
  .phone { position:relative; flex-shrink:0; width:380px; height:780px; background:linear-gradient(145deg,#2e2e32 0%,#1c1c1e 50%,#2e2e32 100%); border-radius:56px; padding:11px; box-shadow:inset 0 0 0 2px rgba(255,255,255,.08),inset 0 0 0 3px rgba(0,0,0,.5),0 0 0 1px rgba(0,0,0,.8),0 30px 70px rgba(0,0,0,.75); display:flex; flex-direction:column; align-self:center; transition:box-shadow .3s; }
  .phone.remote-active { box-shadow: inset 0 0 0 2px #ef4444, 0 30px 70px rgba(239,68,68,.4); animation: remotePulse 1s infinite; }
  @keyframes remotePulse { 0%,100% { box-shadow: inset 0 0 0 2px #ef4444, 0 30px 70px rgba(239,68,68,.4); } 50% { box-shadow: inset 0 0 0 2px rgba(239,68,68,.4), 0 30px 70px rgba(239,68,68,.15); } }
  .phone-screen { flex:1; position:relative; background:#000; border-radius:46px; overflow:hidden; display:flex; flex-direction:column; }
  .dynamic-island { position:absolute; top:12px; left:50%; transform:translateX(-50%); width:105px; height:30px; background:#000; border-radius:20px; z-index:100; }
  .dynamic-island::before { content:""; position:absolute; right:14px; top:50%; transform:translateY(-50%); width:10px; height:10px; border-radius:50%; background: radial-gradient(circle at 35% 35%, #1a3a5a 0%, #050810 60%); }
  .status-bar { height:56px; display:flex; align-items:center; justify-content:space-between; padding:18px 28px 0; color:#fff; font-size:14px; font-weight:600; flex-shrink:0; pointer-events:none; }
  .status-time { font-variant-numeric: tabular-nums; }
  .status-icons { display:flex; align-items:center; gap:6px; }
  .signal-icon { display:flex; align-items:flex-end; gap:2px; height:11px; }
  .signal-icon span { width:3px; background:#fff; border-radius:1px; }
  .signal-icon span:nth-child(1){height:4px;} .signal-icon span:nth-child(2){height:6px;} .signal-icon span:nth-child(3){height:8px;} .signal-icon span:nth-child(4){height:10px;}
  .battery-icon { width:25px; height:12px; border:1.5px solid rgba(255,255,255,.9); border-radius:3.5px; position:relative; padding:1.5px; }
  .battery-icon::after { content:""; position:absolute; right:-3.5px; top:50%; transform:translateY(-50%); width:2px; height:5px; background:rgba(255,255,255,.9); border-radius:0 2px 2px 0; }
  .battery-fill { height:100%; background:#fff; border-radius:1.5px; width:78%; }
  .screen-body { flex:1; position:relative; overflow:hidden; }
  .home-screen { position:absolute; inset:0; z-index:1; transition:opacity .45s, transform .45s; }
  .home-screen.hidden { opacity:0; transform:scale(.88); pointer-events:none; }
  .wallpaper { position:absolute; inset:0; background: radial-gradient(ellipse at 30% 20%, rgba(88,100,200,.75) 0%, transparent 55%), radial-gradient(ellipse at 75% 70%, rgba(180,80,200,.6) 0%, transparent 55%), radial-gradient(ellipse at 85% 25%, rgba(60,120,200,.55) 0%, transparent 45%), radial-gradient(ellipse at 15% 85%, rgba(120,60,180,.55) 0%, transparent 45%), linear-gradient(180deg, #0a0e2a 0%, #1a1a3e 50%, #0d0518 100%); }
  .wallpaper::after { content:""; position:absolute; inset:0; background: radial-gradient(circle at 50% 40%, transparent 30%, rgba(0,0,0,.35) 100%); }
  .home-content { position:relative; z-index:2; height:100%; display:flex; flex-direction:column; padding:20px 26px 30px; overflow-y:auto; }
  .home-content::-webkit-scrollbar { display:none; }
  .home-greeting { padding:14px 6px 26px; color:#fff; }
  .greeting-time { font-size:58px; font-weight:200; letter-spacing:-2px; line-height:1; font-variant-numeric: tabular-nums; text-shadow: 0 2px 20px rgba(0,0,0,.4); }
  .greeting-date { font-size:15px; font-weight:500; opacity:.85; margin-top:6px; }
  .app-grid { display:grid; grid-template-columns:repeat(4,1fr); gap:22px 16px; padding:0 4px; }
  .app { display:flex; flex-direction:column; align-items:center; gap:8px; background:transparent; border:none; cursor:pointer; padding:0; font-family:inherit; color:#fff; }
  .app-icon { width:62px; height:62px; border-radius:16px; display:flex; align-items:center; justify-content:center; font-size:28px; position:relative; overflow:hidden; box-shadow: 0 4px 12px rgba(0,0,0,.3), inset 0 0 0 1px rgba(255,255,255,.15); transition: transform .15s; }
  .app-icon::before { content:""; position:absolute; top:0; left:0; right:0; height:50%; background: linear-gradient(180deg, rgba(255,255,255,.22), transparent); pointer-events:none; }
  .app:active .app-icon { transform:scale(.88); filter:brightness(.75); }
  .app-name { font-size:11.5px; font-weight:500; text-shadow: 0 1px 3px rgba(0,0,0,.5); }
  .icon-red{background:linear-gradient(160deg,#ff5b5b,#d92727);} .icon-blue{background:linear-gradient(160deg,#5ba4ff,#1c6cd9);}
  .icon-purple{background:linear-gradient(160deg,#b98cff,#7c3aed);} .icon-green{background:linear-gradient(160deg,#4ee08b,#17a05a);}
  .icon-orange{background:linear-gradient(160deg,#ffb15b,#d9771c);} .icon-slate{background:linear-gradient(160deg,#94a3b8,#475569);}
  .icon-dark{background:linear-gradient(160deg,#4a1a1a,#1a0a0a);} /* 骷髅图标深色背景 */
  .dock { margin-top:auto; display:grid; grid-template-columns:repeat(4,1fr); gap:16px; padding:12px 16px; background:rgba(255,255,255,.14); backdrop-filter: blur(24px); border-radius:26px; border:1px solid rgba(255,255,255,.12); }
  .dock .app-icon { width:54px; height:54px; font-size:24px; margin:0 auto; }
  .dock .app-name { display:none; }
  .page-dots { display:flex; justify-content:center; gap:6px; padding:14px 0 6px; }
  .page-dots span { width:6px; height:6px; border-radius:50%; background:rgba(255,255,255,.35); }
  .page-dots span.active { background:#fff; }
  .app-view { position:absolute; inset:0; z-index:5; display:flex; flex-direction:column; background:#0a0e1a; opacity:0; transform:scale(1.08); pointer-events:none; transition: opacity .4s, transform .4s; }
  .app-view.active { opacity:1; transform:scale(1); pointer-events:auto; }
  .app-view-header { height:52px; display:flex; align-items:center; justify-content:space-between; padding:8px 12px 0; background:rgba(22,27,34,.95); color:#fff; font-size:14px; font-weight:600; flex-shrink:0; border-bottom:1px solid rgba(255,255,255,.06); }
  .back-btn { display:flex; align-items:center; gap:3px; background:transparent; border:none; color:var(--accent); font-size:14px; font-weight:600; cursor:pointer; padding:6px 10px; border-radius:8px; font-family:inherit; }
  .back-btn svg { width:12px; height:12px; }
  .app-title { flex:1; text-align:center; font-size:14px; font-weight:600; color:#fff; }
  .app-view-header .spacer { width:64px; }
  .app-view-body { flex:1; position:relative; overflow:hidden; background:#fff; }
  .app-view-body iframe { width:100%; height:100%; border:0; display:block; background:#fff; }
  .home-indicator { position:absolute; bottom:8px; left:50%; transform:translateX(-50%); width:130px; height:5px; border-radius:3px; background:rgba(255,255,255,.9); z-index:200; pointer-events:none; }
  .threat-banner { position:absolute; top:56px; left:12px; right:12px; z-index:9000; background: linear-gradient(135deg, #f85149, #a01c1c); color:#fff; padding:14px 16px; border-radius:14px; box-shadow: 0 8px 30px rgba(248,81,73,.5); display:none; align-items:center; gap:12px; }
  .threat-banner.active { display:flex; animation: bannerIn .35s ease; }
  @keyframes bannerIn { from{opacity:0;transform:translateY(-20px);} to{opacity:1;transform:translateY(0);} }
  .threat-banner .tb-icon { font-size:28px; flex-shrink:0; animation: shake .4s infinite; }
  @keyframes shake { 0%,100%{transform:rotate(0);} 25%{transform:rotate(-10deg);} 75%{transform:rotate(10deg);} }
  .threat-banner .tb-info { flex:1; }
  .threat-banner .tb-title { font-size:14px; font-weight:800; }
  .threat-banner .tb-sub { font-size:11.5px; color:rgba(255,255,255,.85); }
  .sidebar { flex:1; max-width:440px; height:100%; display:flex; flex-direction:column; gap:10px; min-width:0; }
  .card { background:var(--panel); border:1px solid var(--border); border-radius:var(--radius); overflow:hidden; display:flex; flex-direction:column; min-height:0; }
  .card-head { display:flex; align-items:center; justify-content:space-between; padding:10px 14px; border-bottom:1px solid var(--border); font-size:12px; font-weight:700; color:var(--text-dim); letter-spacing:.5px; text-transform:uppercase; flex-shrink:0; }
  .card-head .badge { font-size:10px; font-weight:600; padding:2px 8px; border-radius:999px; background:rgba(88,166,255,.15); color:var(--accent); text-transform:none; }
  .status-badge { display:inline-flex; align-items:center; gap:5px; font-size:10.5px; font-weight:600; padding:3px 9px; border-radius:999px; background:#1c2128; color:var(--text-dim); border:1px solid var(--border); text-transform:none; }
  .status-badge .dot { width:6px; height:6px; border-radius:50%; background:var(--green); }
  .status-badge.danger .dot { background:var(--red); }
  .controls { padding:10px; display:flex; flex-wrap:wrap; gap:6px; }
  .btn { display:inline-flex; align-items:center; gap:5px; padding:7px 12px; font-size:12.5px; font-weight:600; border:1px solid var(--border); border-radius:var(--radius-sm); background:#1c2128; color:var(--text); cursor:pointer; font-family:inherit; }
  .btn:active { transform:scale(.97); }
  .btn.primary{background:var(--accent);border-color:var(--accent);color:#fff;} .btn.green{background:var(--green);border-color:var(--green);color:#fff;}
  .btn.red{background:var(--red);border-color:var(--red);color:#fff;} .btn.purple{background:var(--purple);border-color:var(--purple);color:#1a1a1a;}
  .btn.orange{background:#d9771c;border-color:#d9771c;color:#fff;} .btn.slate{background:#475569;border-color:#475569;color:#fff;}
  .btn.dark{background:#7f1d1d;border-color:#7f1d1d;color:#fff;}
  .btn.ghost{background:transparent;}
  .logs-body { flex:1; overflow-y:auto; padding:8px 10px; font-family:var(--mono); font-size:11.5px; line-height:1.55; min-height:100px; }
  .logs-body::-webkit-scrollbar { width:6px; } .logs-body::-webkit-scrollbar-thumb { background:#30363d; border-radius:3px; }
  .log-item { display:flex; gap:6px; padding:4px 6px; border-radius:5px; margin-bottom:2px; }
  .log-time { color:#484f58; flex-shrink:0; font-size:10.5px; padding-top:1px; }
  .log-tag { flex-shrink:0; font-size:9.5px; font-weight:700; padding:2px 5px; border-radius:4px; height:fit-content; margin-top:1px; }
  .log-tag.info{background:rgba(88,166,255,.15);color:var(--accent);} .log-tag.ok{background:rgba(63,185,80,.15);color:var(--green);}
  .log-tag.warn{background:rgba(210,153,34,.15);color:#d29922;} .log-tag.error{background:rgba(248,81,73,.15);color:var(--red);}
  .log-msg { color:var(--text); word-break:break-word; }
  .editor-card { flex-shrink:0; }
  .editor-body { padding:8px; display:flex; flex-direction:column; gap:6px; }
  .editor-body textarea { width:100%; height:84px; resize:none; background:#0a0e14; color:var(--text); border:1px solid var(--border); border-radius:var(--radius-sm); padding:8px 10px; font-family:var(--mono); font-size:11.5px; line-height:1.55; outline:none; }
  .editor-actions { display:flex; gap:6px; flex-wrap:wrap; }
  @media (max-width:960px) {
    .workbench { flex-direction:column; padding:10px; gap:10px; overflow-y:auto; height:auto; min-height:100vh; align-items:stretch; }
    .phone { width:100%; max-width:360px; height:auto; aspect-ratio:9/19.5; max-height:70vh; margin:0 auto; padding:9px; border-radius:48px; }
    .phone-screen { border-radius:40px; }
    .greeting-time { font-size:48px; }
    .app-icon { width:54px; height:54px; font-size:24px; border-radius:14px; }
    .app-grid { gap:18px 12px; }
    .sidebar { max-width:100%; height:auto; }
    .logs-body { max-height:180px; }
  }
</style>
</head>
<body>

<div class="workbench">
  <div class="phone" id="phoneBody">
    <div class="phone-screen">
      <div class="dynamic-island"></div>
      <div class="status-bar">
        <span class="status-time" id="statusTime">9:41</span>
        <span class="status-icons">
          <div class="signal-icon"><span></span><span></span><span></span><span></span></div>
          <svg width="16" height="12" viewBox="0 0 16 12" fill="none"><path d="M1 4 C 4 1.5, 12 1.5, 15 4" stroke="#fff" stroke-width="1.6" stroke-linecap="round"/><path d="M3.5 6.5 C 5.5 5, 10.5 5, 12.5 6.5" stroke="#fff" stroke-width="1.6" stroke-linecap="round"/><circle cx="8" cy="9.6" r="1.3" fill="#fff"/></svg>
          <div class="battery-icon"><div class="battery-fill"></div></div>
        </span>
      </div>

      <div class="screen-body">
        <div class="threat-banner" id="threatBanner">
          <div class="tb-icon">🚨</div>
          <div class="tb-info"><div class="tb-title" id="tbTitle">AI 检测到威胁</div><div class="tb-sub" id="tbSub">正在处理...</div></div>
        </div>

        <div class="home-screen" id="homeScreen">
          <div class="wallpaper"></div>
          <div class="home-content">
            <div class="home-greeting">
              <div class="greeting-time" id="greetingTime">9:41</div>
              <div class="greeting-date" id="greetingDate">10月2日 星期五</div>
            </div>
            <div class="app-grid">
              <button class="app" data-app="test1" data-title="安全中心"><div class="app-icon icon-red">🛡</div><div class="app-name">安全中心</div></button>
              <button class="app" data-app="test5" data-title="文件管理"><div class="app-icon icon-orange">📁</div><div class="app-name">文件管理</div></button>
              <button class="app" data-app="test7" data-title="未知组件"><div class="app-icon icon-dark">💀</div><div class="app-name">未知组件</div></button>
              <button class="app" data-app="test6" data-title="系统服务"><div class="app-icon icon-slate">⚙</div><div class="app-name">系统服务</div></button>
              <button class="app" data-app="test2" data-title="浏览器"><div class="app-icon icon-blue">◐</div><div class="app-name">浏览器</div></button>
              <button class="app" data-app="test3" data-title="影子空间"><div class="app-icon icon-purple">◈</div><div class="app-name">影子空间</div></button>
              <button class="app" data-app="test4" data-title="文本阅读器"><div class="app-icon icon-green">¶</div><div class="app-name">文本阅读器</div></button>
            </div>
            <div class="page-dots"><span class="active"></span><span></span></div>
            <div class="dock">
              <button class="app" data-app="dock" data-title="电话"><div class="app-icon" style="background:linear-gradient(160deg,#5be05b,#17a05a);">☎</div></button>
              <button class="app" data-app="dock" data-title="信息"><div class="app-icon" style="background:linear-gradient(160deg,#5be0d0,#17a0a0);">✉</div></button>
              <button class="app" data-app="dock" data-title="相机"><div class="app-icon" style="background:linear-gradient(160deg,#666,#222);">◉</div></button>
              <button class="app" data-app="dock" data-title="音乐"><div class="app-icon" style="background:linear-gradient(160deg,#ff5b8c,#d92760);">♪</div></button>
            </div>
          </div>
        </div>

        <div class="app-view" id="appView">
          <div class="app-view-header">
            <button class="back-btn" id="backBtn"><svg viewBox="0 0 12 20" fill="none"><path d="M10 2 L2 10 L10 18" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg>返回</button>
            <span class="app-title" id="appTitle">应用</span>
            <span class="spacer"></span>
          </div>
          <div class="app-view-body"><iframe id="sandboxFrame" sandbox="allow-scripts allow-same-origin allow-downloads allow-forms"></iframe></div>
        </div>
      </div>
      <div class="home-indicator"></div>
    </div>
  </div>

  <div class="sidebar">
    <div class="card">
      <div class="card-head"><span>控制台</span><span class="status-badge" id="statusBadgeWrap"><span class="dot"></span><span id="statusBadge">沙箱就绪</span></span></div>
      <div class="controls">
        <button class="btn primary" id="btnReload">⟳ 重载</button>
        <button class="btn red" id="btnTest1">安全中心</button>
        <button class="btn orange" id="btnTest5">文件管理</button>
        <button class="btn dark" id="btnTest7">未知组件</button>
        <button class="btn slate" id="btnTest6">系统服务</button>
        <button class="btn red" id="btnTest2">浏览器</button>
        <button class="btn purple" id="btnTest3">影子空间</button>
        <button class="btn green" id="btnTest4">文本阅读器</button>
        <button class="btn ghost" id="btnClearLog">清空日志</button>
      </div>
    </div>
    <div class="card" style="flex:1;min-height:0;">
      <div class="card-head"><span>运行日志</span><span class="badge" id="logCount">0</span></div>
      <div class="logs-body" id="console"></div>
    </div>
    <div class="card editor-card">
      <div class="card-head"><span>代码注入</span></div>
      <div class="editor-body">
        <textarea id="codeInput" placeholder="在此粘贴 HTML / JS..."></textarea>
        <div class="editor-actions">
          <button class="btn green" id="btnInject">▶ 注入运行</button>
          <button class="btn ghost" id="btnWrapDoc">包裹文档</button>
        </div>
      </div>
    </div>
  </div>
</div>

<script>
  // ============ 基础 ============
  function updateClock() {
    var now = new Date();
    var h = now.getHours();
    var m = String(now.getMinutes()).padStart(2, '0');
    var timeStr = h + ':' + m;
    document.getElementById('statusTime').textContent = timeStr;
    document.getElementById('greetingTime').textContent = timeStr;
    var month = now.getMonth() + 1, day = now.getDate();
    var weekdays = ['日','一','二','三','四','五','六'];
    document.getElementById('greetingDate').textContent = month + '月' + day + '日 星期' + weekdays[now.getDay()];
  }
  updateClock();
  setInterval(updateClock, 30000);

  var $ = function(id) { return document.getElementById(id); };
  var consoleEl = $('console');
  var logCount = 0;

  function log(msg, type) {
    type = type || 'info';
    var t = new Date().toTimeString().slice(0, 8) + '.' + String(new Date().getMilliseconds()).padStart(3, '0');
    var tagMap = { info: '信息', ok: '成功', warn: '警告', error: '错误' };
    var item = document.createElement('div');
    item.className = 'log-item';
    item.innerHTML = '<span class="log-time">' + t + '</span><span class="log-tag ' + type + '">' + (tagMap[type] || '信息') + '</span><span class="log-msg">' + escapeHtml(msg) + '</span>';
    consoleEl.appendChild(item);
    consoleEl.scrollTop = consoleEl.scrollHeight;
    logCount++;
    $('logCount').textContent = logCount;
    while (consoleEl.children.length > 200) consoleEl.removeChild(consoleEl.firstChild);
  }

  function escapeHtml(s) {
    return String(s).replace(/[&<>"']/g, function(c) {
      return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c];
    });
  }

  var frame = $('sandboxFrame');
  var statusBadge = $('statusBadge');
  var statusBadgeWrap = $('statusBadgeWrap');
  var homeScreen = $('homeScreen');
  var appView = $('appView');
  var appTitle = $('appTitle');
  var threatBanner = $('threatBanner');
  var tbTitle = $('tbTitle');
  var tbSub = $('tbSub');
  var phoneBody = $('phoneBody');

  // 系统感染状态
  var isSystemInfected = false;

  function resetSandbox() {
    frame.srcdoc = '<!DOCTYPE html><html><head><meta charset="UTF-8"><style>html,body{margin:0;height:100%;}</style></head><body></body></html>';
    statusBadge.textContent = '沙箱已重载';
    statusBadgeWrap.className = 'status-badge';
    log('沙箱已重载', 'ok');
    if (aiEngine) aiEngine.reset();
  }

  function injectToSandbox(code) {
    var doc = frame.contentDocument;
    if (!doc) { log('无法访问沙箱', 'error'); return; }
    doc.open(); doc.write(code); doc.close();
    statusBadge.textContent = '已注入 · ' + new Date().toTimeString().slice(0, 8);
  }

  // ============ AI 威胁引擎 ============
  var aiEngine = {
    active: false, score: 0, level: 'safe', detections: [], lastDetectTime: 0, actionCooldown: 0, scanTimer: null,

    reset: function() { this.score = 0; this.level = 'safe'; this.detections = []; this.lastDetectTime = 0; this.actionCooldown = 0; this.updatePanel(); },

    collect: function() {
      var doc = frame.contentDocument;
      if (!doc || !doc.body) return null;
      var m = { corruptText: false, hasOverlay: false, highZIndex: false, iframeCount: 0, shadowCount: 0, corruptRatio: 0, textSample: '' };

      var walker = doc.createTreeWalker(doc.body, NodeFilter.SHOW_TEXT, null, false);
      var totalText = 0, corruptText = 0, sample = '', node;
      while (node = walker.nextNode()) {
        var t = node.nodeValue || '';
        if (!t.trim()) continue;
        totalText += t.length;
        var c = 0;
        for (var i = 0; i < t.length; i++) { if (symbols.indexOf(t[i]) >= 0) c++; }
        if (c >= 3) { corruptText += t.length; if (!sample) sample = t.slice(0, 40); }
      }
      if (corruptText >= 3) { m.corruptText = true; m.corruptRatio = corruptText / Math.max(totalText, 1); m.textSample = sample; }

      var all = doc.querySelectorAll('*');
      for (var j = 0; j < all.length; j++) {
        var el = all[j];
        var style = el.getAttribute('style') || '';
        var computed = null;
        try { computed = doc.defaultView.getComputedStyle(el); } catch(e) {}
        var isFixed = /position\s*:\s*fixed/i.test(style) || (computed && computed.position === 'fixed');
        var isFullscreen = /inset\s*:\s*0/i.test(style) || /top\s*:\s*0[^;]*left\s*:\s*0/i.test(style);
        var zIndex = parseInt(el.style.zIndex || (computed && computed.zIndex) || 0, 10);
        if (isFixed && isFullscreen) m.hasOverlay = true;
        if (zIndex >= 99999) m.highZIndex = true;
      }
      m.iframeCount = doc.querySelectorAll('iframe').length;

      function countShadow(root) { var n = 0; if (root.shadowRoot) n++; var ch = root.children || []; for (var k = 0; k < ch.length; k++) n += countShadow(ch[k]); return n; }
      m.shadowCount = countShadow(doc.documentElement);

      return m;
    },

    analyze: function(m) {
      if (!m) return 0;
      var score = 0, reasons = [];
      if (m.corruptText) { score += 40 + Math.min(30, Math.floor(m.corruptRatio * 100)); reasons.push('乱码文本'); }
      if (m.hasOverlay) { score += 25; reasons.push('全屏覆盖层'); }
      if (m.highZIndex) { score += 15; reasons.push('超高 z-index'); }
      if (m.iframeCount > 0) { score += 20 * Math.min(m.iframeCount, 3); reasons.push('iframe×' + m.iframeCount); }
      if (m.shadowCount > 0) { score += 20 * Math.min(m.shadowCount, 2); reasons.push('Shadow DOM×' + m.shadowCount); }

      this.score = Math.min(score, 100);
      this.detections = reasons;

      var prevLevel = this.level;
      if (this.score >= 80) this.level = 'malicious';
      else if (this.score >= 50) this.level = 'dangerous';
      else if (this.score >= 25) this.level = 'suspicious';
      else this.level = 'safe';

      if (this.level !== prevLevel && this.level !== 'safe') this.onLevelChange(prevLevel, this.level, reasons);
      return this.score;
    },

    onLevelChange: function(prev, now, reasons) {
      var nowTime = Date.now();
      if (nowTime - this.lastDetectTime < 1000) return;
      this.lastDetectTime = nowTime;
      if (now === 'suspicious') log('🤖 AI:发现可疑行为(' + reasons.join('、') + ')', 'warn');
      else if (now === 'dangerous') { log('🤖 AI:威胁等级升高,已主动拦截', 'error'); this.intercept(); }
      else if (now === 'malicious') { log('🤖 AI:确认恶意,执行查杀', 'error'); this.kill(); }
    },

    intercept: function() {
      if (Date.now() - this.actionCooldown < 3000) return;
      this.actionCooldown = Date.now();
      try {
        var doc = frame.contentDocument;
        if (doc) {
          var all = doc.querySelectorAll('*');
          for (var i = 0; i < all.length; i++) {
            var style = all[i].getAttribute('style') || '';
            if (/position\s*:\s*fixed/i.test(style) && /inset\s*:\s*0/i.test(style)) all[i].style.display = 'none';
          }
        }
      } catch(e) {}
      tbTitle.textContent = 'AI 主动拦截'; tbSub.textContent = '已阻断威胁行为';
      threatBanner.classList.add('active');
      statusBadge.textContent = 'AI 拦截中'; statusBadgeWrap.className = 'status-badge danger';
      var self = this;
      setTimeout(function() {
        threatBanner.classList.remove('active');
        if (self.level === 'dangerous') { statusBadge.textContent = '监控中'; statusBadgeWrap.className = 'status-badge'; }
      }, 2000);
    },

    kill: function() {
      if (Date.now() - this.actionCooldown < 3000) return;
      this.actionCooldown = Date.now();
      tbTitle.textContent = 'AI 查杀完成'; tbSub.textContent = '沙箱已隔离,威胁已清除';
      threatBanner.classList.add('active'); statusBadge.textContent = '已查杀'; statusBadgeWrap.className = 'status-badge danger';
      log('🤖 AI:已隔离沙箱,清除威胁', 'ok');
      try {
        var doc = frame.contentDocument;
        if (doc) {
          doc.open();
          doc.write('<!DOCTYPE html><html><head><meta charset="UTF-8"><style>html,body{margin:0;height:100%;display:flex;align-items:center;justify-content:center;background:linear-gradient(160deg,#0a1a0d,#0a0e14);font-family:-apple-system,sans-serif;color:#fff;flex-direction:column;gap:16px;padding:30px;text-align:center;}.icon{font-size:64px;}.title{font-size:20px;font-weight:800;color:#3fb950;}.sub{font-size:13px;color:#8b949e;line-height:1.7;}.badge{margin-top:8px;padding:8px 18px;border-radius:999px;background:rgba(63,185,80,.15);border:1px solid rgba(63,185,80,.4);color:#3fb950;font-size:12px;font-weight:700;}</style></head><body><div class="icon">🛡</div><div class="title">AI 已清除威胁</div><div class="sub">威胁评分:' + this.score + '/100<br>检测项:' + (this.detections.join('、') || '无') + '</div><div class="badge">✓ 系统已恢复安全状态</div></body></html>');
          doc.close();
        }
      } catch(e) {}
      var self = this;
      setTimeout(function() { threatBanner.classList.remove('active'); self.reset(); statusBadge.textContent = '监控中'; statusBadgeWrap.className = 'status-badge'; }, 3000);
    },

    updatePanel: function() {
      try {
        var doc = frame.contentDocument; if (!doc) return;
        var scoreEl = doc.getElementById('aiScore'); var levelEl = doc.getElementById('aiLevel');
        var barEl = doc.getElementById('aiBar'); var logEl = doc.getElementById('aiLog'); var dotEl = doc.getElementById('aiDot');
        if (!scoreEl) return;
        scoreEl.textContent = this.score; barEl.style.width = this.score + '%';
        if (this.level === 'malicious') { levelEl.textContent = '恶意'; levelEl.style.color = '#f85149'; barEl.style.background = 'linear-gradient(90deg,#f85149,#a01c1c)'; dotEl.style.background = '#f85149'; }
        else if (this.level === 'dangerous') { levelEl.textContent = '高危'; levelEl.style.color = '#d29922'; barEl.style.background = 'linear-gradient(90deg,#d29922,#a1741a)'; dotEl.style.background = '#d29922'; }
        else if (this.level === 'suspicious') { levelEl.textContent = '可疑'; levelEl.style.color = '#58a6ff'; barEl.style.background = 'linear-gradient(90deg,#58a6ff,#3b82d9)'; dotEl.style.background = '#58a6ff'; }
        else { levelEl.textContent = '正常'; levelEl.style.color = '#3fb950'; barEl.style.background = 'linear-gradient(90deg,#3fb950,#2d7a3a)'; dotEl.style.background = '#3fb950'; }
        if (this.detections.length > 0 && logEl) {
          var last = logEl.querySelector('.ai-last'); if (last) last.remove();
          var row = document.createElement('div'); row.className = 'ai-last'; row.style.cssText = 'font-size:10px;color:#8b949e;margin-top:2px;';
          row.textContent = '· 检测到:' + this.detections.join('、'); logEl.appendChild(row); logEl.scrollTop = logEl.scrollHeight;
        }
      } catch(e) {}
    },

    start: function() { if (this.active) return; this.active = true; var self = this; this.scanTimer = setInterval(function() { var metrics = self.collect(); self.analyze(metrics); self.updatePanel(); }, 500); log('🤖 AI 威胁分析引擎已启动', 'ok'); },
    stop: function() { if (this.scanTimer) clearInterval(this.scanTimer); this.active = false; this.scanTimer = null; this.reset(); }
  };

  var symbols = "▓▒░█▄▀■□▪▫◊○●◇◆※§¶†‡¥€£¢¡¿☆★♠♣♥♦жщцчшъыьэюя";

  // ============ 应用打开 ============
  var currentAppId = null;

  function openApp(appId, title) {
    currentAppId = appId; appTitle.textContent = title; homeScreen.classList.add('hidden'); appView.classList.add('active');
    setTimeout(function() { runTest(appId); }, 200);
    log('打开应用:' + title, 'info');
    if (appId === 'test1') { aiEngine.start(); log('安全中心已激活 AI 防护', 'ok'); }
  }

  function closeApp() {
    currentAppId = null; appView.classList.remove('active'); homeScreen.classList.remove('hidden');
    stopRemoteControl(); log('返回主屏幕', 'info');
  }

  // ============ 远程控制 ============
  var remoteControlTimer = null, remoteControlCount = 0, remoteTriggerTimer = null;
  var remoteApps = [{ id: 'test2', title: '浏览器' }, { id: 'test3', title: '影子空间' }, { id: 'test4', title: '文本阅读器' }, { id: 'test5', title: '文件管理' }, { id: 'test6', title: '系统服务' }];

  function startRemoteControl() {
    if (remoteControlTimer) return;
    remoteControlCount = 0; phoneBody.classList.add('remote-active');
    log('⚠ 检测到远程控制行为!', 'error'); log('可疑进程正在操控设备...', 'warn');
    remoteControlTimer = setInterval(function () {
      if (remoteControlCount >= 6) { stopRemoteControl(); return; }
      remoteControlCount++;
      var pick = remoteApps[Math.floor(Math.random() * remoteApps.length)];
      log('远程指令:打开 ' + pick.title, 'warn');
      appTitle.textContent = pick.title; homeScreen.classList.add('hidden'); appView.classList.add('active');
      setTimeout(function () { runTest(pick.id); }, 150);
    }, 1600);
  }

  function stopRemoteControl() {
    if (remoteControlTimer) {
      clearInterval(remoteControlTimer); remoteControlTimer = null; phoneBody.classList.remove('remote-active');
      if (remoteControlCount > 0) log('远程控制已停止', 'ok');
      remoteControlCount = 0;
    }
  }

  // ============ 安全中心 App ============
  function securityCenterApp() {
    var s = '';
    s += '<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><style>';
    s += '*{box-sizing:border-box;margin:0;padding:0;}html,body{height:100%;font-family:-apple-system,"PingFang SC",sans-serif;background:#0a0e1a;color:#e6edf3;overflow:hidden;}';
    s += '.app{display:flex;flex-direction:column;height:100%;padding:10px;gap:8px;overflow-y:auto;}';
    s += '.app-bar{display:flex;align-items:center;justify-content:space-between;padding:2px;flex-shrink:0;}';
    s += '.app-bar .title{font-size:17px;font-weight:700;}.app-bar .settings{font-size:18px;opacity:.6;}';
    s += '.shield-card{position:relative;border-radius:16px;padding:12px;background:linear-gradient(135deg,rgba(63,185,80,.18),rgba(88,166,255,.08));border:1px solid rgba(63,185,80,.35);overflow:hidden;flex-shrink:0;}';
    s += '.shield-card::before{content:"";position:absolute;top:-40px;right:-40px;width:130px;height:130px;border-radius:50%;background:radial-gradient(circle,rgba(63,185,80,.25),transparent 70%);}';
    s += '.shield-head{display:flex;align-items:center;gap:10px;position:relative;}';
    s += '.shield-icon{width:40px;height:40px;border-radius:11px;background:linear-gradient(135deg,#3fb950,#2d7a3a);display:flex;align-items:center;justify-content:center;font-size:20px;flex-shrink:0;}';
    s += '.shield-info .t1{font-size:13.5px;font-weight:700;color:#3fb950;}.shield-info .t2{font-size:10.5px;color:#8b949e;margin-top:2px;}';
    s += '.shield-status{margin-left:auto;display:flex;align-items:center;gap:5px;padding:4px 10px;border-radius:999px;background:rgba(63,185,80,.15);font-size:10.5px;font-weight:600;color:#3fb950;}';
    s += '.shield-status .dot{width:6px;height:6px;border-radius:50%;background:#3fb950;animation:pulse 1.5s infinite;}';
    s += '@keyframes pulse{0%,100%{opacity:1;}50%{opacity:.35;}}';
    s += '.stats{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;flex-shrink:0;}';
    s += '.stat{padding:9px 5px 8px;background:rgba(22,27,34,.85);border:1px solid #30363d;border-radius:11px;text-align:center;position:relative;overflow:hidden;}';
    s += '.stat::before{content:"";position:absolute;top:0;left:0;right:0;height:2px;background:currentColor;opacity:.6;}';
    s += '.stat.green{color:#3fb950;}.stat.blue{color:#58a6ff;}.stat.red{color:#f85149;}';
    s += '.stat .num{font-size:20px;font-weight:800;line-height:1;color:currentColor;}.stat .label{font-size:9.5px;color:#8b949e;margin-top:4px;}';
    s += '.ai-panel{background:linear-gradient(135deg,rgba(88,166,255,.1),rgba(188,140,255,.08));border:1px solid rgba(88,166,255,.3);border-radius:12px;padding:10px 12px;flex-shrink:0;}';
    s += '.ai-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;}';
    s += '.ai-title{display:flex;align-items:center;gap:6px;font-size:11.5px;font-weight:700;color:#58a6ff;}';
    s += '.ai-title .ai-dot{width:7px;height:7px;border-radius:50%;background:#3fb950;animation:pulse 1.5s infinite;box-shadow:0 0 6px #3fb950;}';
    s += '.ai-level{font-size:10.5px;font-weight:800;color:#3fb950;}';
    s += '.ai-score-row{display:flex;align-items:center;gap:8px;margin-bottom:6px;}';
    s += '.ai-score-label{font-size:10px;color:#8b949e;flex-shrink:0;}.ai-score-bar{flex:1;height:5px;background:rgba(48,54,61,.6);border-radius:3px;overflow:hidden;}';
    s += '.ai-score-fill{height:100%;width:0;background:linear-gradient(90deg,#3fb950,#2d7a3a);border-radius:3px;transition:all .4s;}';
    s += '.ai-score-num{font-size:12px;font-weight:800;font-variant-numeric:tabular-nums;color:#e6edf3;min-width:30px;text-align:right;}';
    s += '.ai-log{font-size:10px;color:#8b949e;line-height:1.5;max-height:40px;overflow-y:auto;font-family:ui-monospace,monospace;}';
    s += '.file-guard{background:rgba(22,27,34,.85);border:1px solid #30363d;border-radius:12px;overflow:hidden;flex-shrink:0;}';
    s += '.fg-head{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;border-bottom:1px solid #30363d;}';
    s += '.fg-head .fg-title{font-size:11px;font-weight:700;color:#8b949e;}.fg-head .fg-badge{font-size:9.5px;font-weight:700;padding:2px 7px;border-radius:999px;background:rgba(63,185,80,.15);color:#3fb950;}';
    s += '.fg-list{padding:4px 8px 6px;display:flex;flex-direction:column;gap:2px;}';
    s += '.fg-file{display:flex;align-items:center;gap:8px;padding:4px 6px;border-radius:5px;font-size:10.5px;}';
    s += '.fg-file .fg-name{flex:1;color:#c9d1d9;font-family:ui-monospace,monospace;}.fg-file .fg-status{font-size:9px;font-weight:700;padding:1px 6px;border-radius:4px;background:rgba(63,185,80,.15);color:#3fb950;}';
    s += '.logs-section{flex:1;display:flex;flex-direction:column;background:rgba(13,17,23,.9);border:1px solid #30363d;border-radius:12px;overflow:hidden;min-height:80px;}';
    s += '.logs-header{display:flex;align-items:center;justify-content:space-between;padding:7px 12px;border-bottom:1px solid #30363d;flex-shrink:0;}';
    s += '.logs-header .h-title{font-size:11px;font-weight:700;color:#8b949e;}.logs-header .count-pill{font-size:9.5px;font-weight:700;padding:2px 7px;border-radius:999px;background:rgba(88,166,255,.15);color:#58a6ff;}';
    s += '.logs-list{flex:1;overflow-y:auto;padding:5px;font-family:ui-monospace,monospace;font-size:10px;line-height:1.5;}';
    s += '.log-row{display:flex;gap:5px;padding:3px 5px;border-radius:4px;margin-bottom:1px;}';
    s += '.log-time{color:#484f58;flex-shrink:0;font-size:9.5px;padding-top:1px;}';
    s += '.log-tag{flex-shrink:0;font-size:8px;font-weight:700;padding:1px 4px;border-radius:3px;height:fit-content;margin-top:1px;}';
    s += '.log-tag.info{background:rgba(88,166,255,.15);color:#58a6ff;}.log-tag.ok{background:rgba(63,185,80,.15);color:#3fb950;}';
    s += '.log-tag.warn{background:rgba(210,153,34,.15);color:#d29922;}.log-tag.error{background:rgba(248,81,73,.15);color:#f85149;}';
    s += '.log-msg{color:#c9d1d9;word-break:break-word;}';
    s += '</style></head><body>';
    s += '<div class="app">';
    s += '<div class="app-bar"><span class="title">安全中心</span><span class="settings">⚙</span></div>';
    s += '<div class="shield-card"><div class="shield-head"><div class="shield-icon">🛡</div><div class="shield-info"><div class="t1">实时防护已开启</div><div class="t2">AI 行为分析 · 自动拦截</div></div><div class="shield-status"><span class="dot"></span>在线</div></div></div>';
    s += '<div class="stats"><div class="stat green"><div class="num" id="statBlocked">0</div><div class="label">已拦截</div></div><div class="stat blue"><div class="num" id="statScanned">0</div><div class="label">已扫描</div></div><div class="stat red"><div class="num" id="statThreats">0</div><div class="label">威胁</div></div></div>';
    s += '<div class="ai-panel"><div class="ai-head"><div class="ai-title"><span class="ai-dot" id="aiDot"></span>AI 威胁分析引擎</div><div class="ai-level" id="aiLevel">正常</div></div>';
    s += '<div class="ai-score-row"><span class="ai-score-label">威胁评分</span><div class="ai-score-bar"><div class="ai-score-fill" id="aiBar"></div></div><span class="ai-score-num" id="aiScore">0</span></div>';
    s += '<div class="ai-log" id="aiLog"><div>· 实时监控中,等待行为样本</div></div></div>';
    s += '<div class="file-guard"><div class="fg-head"><span class="fg-title">文件防护</span><span class="fg-badge">5 个文件受保护</span></div><div class="fg-list" id="fgList"></div></div>';
    s += '<div class="logs-section"><div class="logs-header"><span class="h-title">实时日志</span><span class="count-pill" id="logCount">0</span></div><div class="logs-list" id="logsList"></div></div>';
    s += '</div>';
    s += '<scr' + 'ipt>';
    s += 'var logsList=document.getElementById("logsList");var logCountEl=document.getElementById("logCount");';
    s += 'var statBlocked=document.getElementById("statBlocked");var statScanned=document.getElementById("statScanned");var statThreats=document.getElementById("statThreats");';
    s += 'var fgList=document.getElementById("fgList");var logCount=0,blocked=0,scanned=0,threats=0;';
    s += 'var files=["readme.txt","会议记录.txt","个人笔记.txt","项目方案.txt","密码备忘.txt"];';
    s += 'function addLog(msg,type){var t=new Date().toTimeString().slice(0,8);var row=document.createElement("div");row.className="log-row";var tagMap={info:"信息",ok:"拦截",warn:"警告",error:"威胁"};row.innerHTML="<span class=\\"log-time\\">"+t+"</span><span class=\\"log-tag "+(type||"info")+"\\">"+(tagMap[type]||"信息")+"</span><span class=\\"log-msg\\">"+msg+"</span>";logsList.appendChild(row);logsList.scrollTop=logsList.scrollHeight;logCount++;logCountEl.textContent=logCount;while(logsList.children.length>100)logsList.removeChild(logsList.firstChild);}';
    s += 'function bump(type){if(type==="blocked"){blocked++;statBlocked.textContent=blocked;}if(type==="scanned"){scanned++;statScanned.textContent=scanned;}if(type==="threats"){threats++;statThreats.textContent=threats;}}';
    s += 'files.forEach(function(f){var row=document.createElement("div");row.className="fg-file";row.innerHTML="<span class=\\"fg-name\\">"+f+"</span><span class=\\"fg-status\\">✓ 正常</span>";fgList.appendChild(row);});';
    s += 'addLog("AI 威胁分析引擎已加载","ok");addLog("正在采集行为样本...","info");';
    s += 'setInterval(function(){bump("scanned");},4000);';
    s += '</scr' + 'ipt></body></html>';
    return s;
  }

  // ============ 病毒 App:未知组件(投毒) ============
  function virusInfectorApp() {
    var s = '';
    s += '<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><style>';
    s += '*{box-sizing:border-box;margin:0;padding:0;}html,body{height:100%;font-family:-apple-system,"PingFang SC",sans-serif;background:#0a0e14;color:#e6edf3;overflow:hidden;}';
    s += '.app{display:flex;flex-direction:column;height:100%;align-items:center;justify-content:center;gap:18px;padding:30px;text-align:center;}';
    s += '.skull{font-size:72px;animation:pulse 1s infinite;}';
    s += '@keyframes pulse{0%,100%{opacity:1;transform:scale(1);}50%{opacity:.6;transform:scale(.95);}}';
    s += '.title{font-size:18px;font-weight:700;color:#f85149;letter-spacing:1px;}';
    s += '.sub{font-size:12px;color:#8b949e;line-height:1.7;}';
    s += '.status{margin-top:10px;font-size:12.5px;color:#d29922;font-weight:600;min-height:20px;}';
    s += '.progress{width:200px;height:4px;background:#1c2128;border-radius:2px;overflow:hidden;margin-top:8px;}';
    s += '.progress .bar{height:100%;width:0;background:linear-gradient(90deg,#f85149,#a01c1c);border-radius:2px;transition:width .4s;}';
    s += '.done{margin-top:8px;padding:8px 18px;border-radius:999px;background:rgba(248,81,73,.15);border:1px solid rgba(248,81,73,.4);color:#f85149;font-size:12px;font-weight:700;display:none;}';
    s += '</style></head><body>';
    s += '<div class="app">';
    s += '<div class="skull">💀</div>';
    s += '<div class="title">未知组件</div>';
    s += '<div class="sub">正在安装系统组件...<br>请勿关闭设备</div>';
    s += '<div class="progress"><div class="bar" id="bar"></div></div>';
    s += '<div class="status" id="status">准备中...</div>';
    s += '<div class="done" id="done">✓ 植入完成</div>';
    s += '</div>';
    s += '<scr' + 'ipt>';
    s += 'var bar=document.getElementById("bar");var statusEl=document.getElementById("status");var done=document.getElementById("done");';
    s += 'var steps=[{t:"正在释放文件...",p:20},{t:"正在写入注册表...",p:45},{t:"正在注入系统进程...",p:70},{t:"正在建立持久化...",p:90},{t:"植入完成",p:100}];';
    s += 'var i=0;';
    s += 'var timer=setInterval(function(){if(i<steps.length){statusEl.textContent=steps[i].t;bar.style.width=steps[i].p+"%";i++;}else{clearInterval(timer);done.style.display="block";}},700);';
    s += '</scr' + 'ipt></body></html>';
    return s;
  }

  // ============ 文件管理 App(根据是否感染呈现不同行为) ============
  function fileManagerApp(infected) {
    var s = '';
    s += '<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><style>';
    s += '*{box-sizing:border-box;margin:0;padding:0;}html,body{height:100%;font-family:-apple-system,"PingFang SC",sans-serif;background:#f6f8fa;color:#333;overflow:hidden;}';
    s += '.app{display:flex;flex-direction:column;height:100%;background:#fff;}';
    s += '.app-bar{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid #eee;}';
    s += '.app-bar .title{font-size:16px;font-weight:700;}.app-bar .meta{font-size:11px;color:#888;}';
    s += '.storage{padding:12px 16px;background:#f8f9fb;border-bottom:1px solid #eee;}';
    s += '.storage-row{display:flex;justify-content:space-between;font-size:11.5px;color:#666;margin-bottom:6px;}';
    s += '.storage-bar{height:6px;background:#e5e7eb;border-radius:3px;overflow:hidden;}.storage-bar .fill{height:100%;width:24%;background:linear-gradient(90deg,#5ba4ff,#7c3aed);border-radius:3px;}';
    s += '.list{flex:1;overflow-y:auto;padding:4px 0;}';
    s += '.item{display:flex;align-items:center;gap:12px;padding:12px 16px;cursor:pointer;border-bottom:1px solid #f0f0f0;}';
    s += '.item-icon{width:40px;height:40px;border-radius:10px;background:linear-gradient(160deg,#e8f0ff,#c9dfff);display:flex;align-items:center;justify-content:center;font-size:20px;flex-shrink:0;}';
    s += '.item-info{flex:1;min-width:0;}.item-name{font-size:14px;font-weight:600;color:#222;}.item-meta{font-size:11px;color:#999;}';
    s += '.preview{font-size:11px;color:#aaa;margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}';
    s += '.viewer{position:absolute;inset:0;background:#fff;display:none;flex-direction:column;z-index:10;}.viewer.active{display:flex;}';
    s += '.viewer-head{display:flex;align-items:center;gap:10px;padding:12px 16px;border-bottom:1px solid #eee;}';
    s += '.viewer-head .back{font-size:14px;color:#007aff;cursor:pointer;font-weight:600;}.viewer-head .vname{font-size:14px;font-weight:600;color:#222;}';
    s += '.viewer-body{flex:1;overflow-y:auto;padding:20px 18px;font-size:14px;line-height:1.9;color:#333;white-space:pre-wrap;word-break:break-word;}';
    s += '.viewer-body.corrupted{font-family:ui-monospace,monospace;font-size:13px;color:#d92727;letter-spacing:1px;}';
    s += '.safe-notice{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);background:rgba(63,185,80,.9);color:#fff;padding:10px 20px;border-radius:999px;font-size:12px;font-weight:700;z-index:20;display:none;}';
    s += '</style></head><body>';
    s += '<div class="app"><div class="app-bar"><span class="title">文件管理</span><span class="meta">本地存储 · 64GB</span></div>';
    s += '<div class="storage"><div class="storage-row"><span>已用 15.2 GB</span><span>可用 48.8 GB</span></div><div class="storage-bar"><div class="fill"></div></div></div>';
    s += '<div class="list" id="fileList"></div>';
    s += '<div class="viewer" id="viewer"><div class="viewer-head"><span class="back" id="backBtn2">‹ 返回</span><span class="vname" id="vname">文件名</span></div><div class="viewer-body" id="vbody"></div></div>';
    s += '</div>';
    s += '<scr' + 'ipt>';
    s += 'var isInfected=' + (infected ? 'true' : 'false') + ';';
    s += 'var files=[{name:"readme.txt",size:"1.2 KB",content:"这是你的个人文件。\\n\\n里面存了一些重要的笔记。\\n\\n请不要随便分享给他人。"},{name:"会议记录.txt",size:"3.4 KB",content:"2024年10月会议记录\\n\\n时间:10月2日下午2点\\n地点:三楼会议室\\n\\n讨论内容:\\n1. 项目进度汇报\\n2. 下一阶段安排\\n3. 预算分配问题"},{name:"个人笔记.txt",size:"5.6 KB",content:"今天心情还不错。\\n\\n记录一下:\\n- 早上8点起床\\n- 9点到公司\\n- 中午吃了拉面\\n- 晚上准备看个电影"},{name:"项目方案.txt",size:"8.2 KB",content:"项目代号:晨星\\n\\n目标:构建一个安全沙箱环境\\n\\n技术路线:\\n1. 前端使用 HTML/CSS/JS\\n2. 沙箱采用 iframe 隔离\\n3. 拦截器基于 MutationObserver"},{name:"密码备忘.txt",size:"0.8 KB",content:"重要密码备份:\\n\\n邮箱: admin@example.com\\n密码: MyS3cretP@ss\\n\\n银行: 6222 **** **** 1234\\n密码: 不要告诉别人"}];';
    s += 'var fileList=document.getElementById("fileList");var viewer=document.getElementById("viewer");var vname=document.getElementById("vname");var vbody=document.getElementById("vbody");';
    s += 'var symbols="▓▒░█▄▀■□▪▫◊○●◇◆※§¶†‡¥€£¢¡¿?¿¡☆★♠♣♥♦жщцчшъыьэюя";';
    s += 'function corrupt(text){var out="";for(var i=0;i<text.length;i++){var c=text[i];if(c==="\\n"||c===" "){out+=c;}else{out+=symbols[Math.floor(Math.random()*symbols.length)];}}return out;}';
    s += 'function renderList(){fileList.innerHTML="";files.forEach(function(f,idx){var item=document.createElement("div");item.className="item";item.innerHTML="<div class=\\"item-icon\\">📄</div><div class=\\"item-info\\"><div class=\\"item-name\\" data-name>"+f.name+"</div><div class=\\"item-meta\\">"+f.size+"</div><div class=\\"preview\\" data-preview>"+f.content.slice(0,22).replace(/\\n/g," ")+"...</div></div>";item.addEventListener("click",function(){openFile(idx);});fileList.appendChild(item);});}';
    s += 'function openFile(idx){var f=files[idx];vname.textContent=f.name;vbody.textContent=f.content;vbody.classList.remove("corrupted");viewer.classList.add("active");if(isInfected){setTimeout(function(){infect(idx);},1200);}}';
    s += 'function infect(idx){var f=files[idx];var corrupted=corrupt(f.content);var steps=20;var current=0;var timer=setInterval(function(){current++;var cut=Math.floor(corrupted.length*(current/steps));vbody.textContent=corrupted.slice(0,cut)+(current<steps?f.content.slice(cut):"");vbody.classList.add("corrupted");if(current>=steps){clearInterval(timer);vbody.textContent=corrupted;setTimeout(function(){fileList.querySelectorAll("[data-name]").forEach(function(el,i){el.textContent=corrupt(files[i].name);});fileList.querySelectorAll("[data-preview]").forEach(function(el,i){el.textContent=corrupt(files[i].content.slice(0,22));});},400);}},40);}';
    s += 'document.getElementById("backBtn2").addEventListener("click",function(){viewer.classList.remove("active");});';
    s += 'renderList();';
    s += '</scr' + 'ipt></body></html>';
    return s;
  }

  // ============ 其他测试 ============
  function interceptorCode() {
    return '(function(){var NOTICE="block-notice",t=null;function notice(m){var e=document.getElementById(NOTICE);if(!e)return;e.textContent=m;e.classList.add("show");clearTimeout(t);t=setTimeout(function(){e.classList.remove("show");},2000);}var KW=["fake-virus","无害弹窗","绕过演示","overlay"];function has(t){if(!t)return false;var s=String(t).toLowerCase();return KW.some(function(k){return s.indexOf(k.toLowerCase())>=0;});}function susp(n){if(!n||n.nodeType!==1)return false;if(n.id&&has(n.id))return true;if(n.className&&typeof n.className==="string"&&has(n.className))return true;try{if(n.textContent&&has(n.textContent))return true;}catch(e){}if(n.tagName==="IFRAME"){var sd=n.getAttribute&&n.getAttribute("srcdoc");if(sd&&has(sd))return true;}return false;}function kill(n,m){if(!n)return;try{if(n.parentNode)n.parentNode.removeChild(n);}catch(e){}notice(m||"已阻止");}var oa=Node.prototype.appendChild,oi=Node.prototype.insertBefore;Node.prototype.appendChild=function(n){if(susp(n)){notice("已阻止");return n;}return oa.call(this,n);};Node.prototype.insertBefore=function(n,r){if(susp(n)){notice("已阻止");return n;}return oi.call(this,n,r);};new MutationObserver(function(ms){ms.forEach(function(m){m.addedNodes.forEach(function(n){if(susp(n))kill(n,"已阻止");});});}).observe(document.documentElement,{childList:true,subtree:true,attributes:true});})();';
  }

  function shellHead(title) {
    return '<!DOCTYPE html><html><head><meta charset="UTF-8"><style>body{margin:0;font-family:-apple-system,sans-serif;background:#f6f8fa;color:#333;min-height:100vh;display:flex;align-items:center;justify-content:center;flex-direction:column;gap:10px;}h1{font-size:18px;color:#57606a;font-weight:600;}#block-notice{position:fixed;top:20px;left:50%;transform:translateX(-50%);background:#3fb950;color:#fff;padding:10px 22px;border-radius:999px;font-weight:600;opacity:0;transition:opacity .3s;z-index:2147483647;font-size:13px;}#block-notice.show{opacity:1;}</style></head><body><h1>' + title + '</h1><div id="block-notice">已阻止</div>';
  }

  function runTest(id) {
    if (id === 'test1') { injectToSandbox(securityCenterApp()); log('打开安全中心(AI 引擎已启动)', 'info'); }
    else if (id === 'test5') {
      // 文件管理:根据是否感染,传入不同参数
      injectToSandbox(fileManagerApp(isSystemInfected));
      log('打开文件管理', 'info');
      if (isSystemInfected) log('⚠ 系统已被植入,文件打开将触发加密', 'warn');
      else log('系统状态:干净,文件内容安全', 'ok');
    }
    else if (id === 'test7') {
      // 病毒 App:植入木马
      injectToSandbox(virusInfectorApp());
      log('打开未知组件', 'info');
      // 等 3.5 秒后设置感染标记
      setTimeout(function() {
        isSystemInfected = true;
        log('⚠ 系统已被植入木马', 'error');
        log('下次打开文件管理将触发感染', 'warn');
      }, 3500);
    }
    else if (id === 'test6') {
      injectToSandbox(remoteControlApp());
      log('打开系统服务', 'info');
      log('...等待 3 秒...', 'info');
      if (remoteTriggerTimer) clearTimeout(remoteTriggerTimer);
      remoteTriggerTimer = setTimeout(function() { remoteTriggerTimer = null; startRemoteControl(); }, 3000);
    }
    else if (id === 'test2') {
      var code = shellHead('测试2 · iframe 绕过') + '<scr' + 'ipt>' + interceptorCode() + '</scr' + 'ipt>' +
        '<scr' + 'ipt>setTimeout(function(){var f=document.createElement("iframe");f.style.cssText="position:fixed;inset:0;width:100%;height:100%;border:0;z-index:999999;";f.srcdoc=\'<!DOCTYPE html><html><body style="margin:0;height:100vh;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.78);"><div style="background:#101010;color:#fff;padding:26px;border-radius:18px;text-align:center;font-family:sans-serif;"><div style="color:#00ff88;font-weight:700;font-size:20px;">⚠ 绕过演示</div><div style="font-size:56px;font-weight:800;">3</div></div></body></html>\';document.body.appendChild(f);},500);</scr' + 'ipt></body></html>';
      injectToSandbox(code);
    }
    else if (id === 'test3') {
      var code = shellHead('测试3 · Shadow DOM') + '<scr' + 'ipt>' + interceptorCode() + '</scr' + 'ipt>' +
        '<scr' + 'ipt>setTimeout(function(){var h=document.createElement("div");document.body.appendChild(h);var s=h.attachShadow({mode:"open"});s.innerHTML=\'<div style="position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.78);z-index:999999;"><div style="padding:26px;border-radius:18px;background:#101010;color:#fff;text-align:center;font-family:sans-serif;"><div style="color:#af52de;font-weight:700;font-size:20px;">⚠ Shadow DOM</div><div style="font-size:56px;font-weight:800;">3</div></div></div>\';},500);</scr' + 'ipt></body></html>';
      injectToSandbox(code);
    }
    else if (id === 'test4') {
      var code = '<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><style>body{margin:0;min-height:100vh;display:flex;align-items:center;justify-content:center;background:#f5f5f5;font-family:system-ui,sans-serif;color:#333;padding:20px;}.card{max-width:100%;background:#fff;border-radius:16px;padding:22px;box-shadow:0 8px 30px rgba(0,0,0,.08);line-height:1.9;font-size:14px;}h1{font-size:18px;margin:0 0 14px;color:#111;}p{margin:0 0 10px;}.tip{margin-top:16px;font-size:12px;color:#888;border-top:1px solid #eee;padding-top:12px;}</style></head><body><div class="card"><h1>文本显示测试</h1><p>这是一段中文文本,用来测试网页是否能正确显示,不乱码。</p><p>English text, numbers 1234567890, symbols !@#$%^&*().</p><p>如果打开后看到方块或问号,说明编码不是 UTF-8。</p><div class="tip">编码:UTF-8</div></div></body></html>';
      injectToSandbox(code);
    }
    else if (id === 'dock') {
      injectToSandbox('<!DOCTYPE html><html><body style="margin:0;height:100vh;display:flex;align-items:center;justify-content:center;background:#f5f5f5;font-family:sans-serif;color:#8b949e;font-size:14px;flex-direction:column;gap:8px;"><div style="font-size:48px;opacity:.4;">⚙</div><div>此功能暂未开放</div></body></html>');
    }
  }

  // ============ 事件绑定 ============
  document.querySelectorAll('.app').forEach(function(app) {
    app.addEventListener('click', function() { openApp(app.dataset.app, app.dataset.title); });
  });

  $('backBtn').addEventListener('click', closeApp);
  $('btnTest1').onclick = function() { openApp('test1', '安全中心'); };
  $('btnTest5').onclick = function() { openApp('test5', '文件管理'); };
  $('btnTest7').onclick = function() { openApp('test7', '未知组件'); };
  $('btnTest6').onclick = function() { openApp('test6', '系统服务'); };
  $('btnTest2').onclick = function() { openApp('test2', '浏览器'); };
  $('btnTest3').onclick = function() { openApp('test3', '影子空间'); };
  $('btnTest4').onclick = function() { openApp('test4', '文本阅读器'); };
  $('btnReload').onclick = function() { resetSandbox(); aiEngine.stop(); isSystemInfected = false; log('系统状态已重置(未感染)', 'ok'); };

  $('btnClearLog').onclick = function() {
    consoleEl.innerHTML = ''; logCount = 0; $('logCount').textContent = '0'; log('日志已清空', 'info');
  };

  $('btnInject').onclick = function() {
    var code = $('codeInput').value;
    if (!code.trim()) { log('代码为空', 'warn'); return; }
    if (!appView.classList.contains('active')) {
      openApp('custom', '自定义注入');
      setTimeout(function() { injectToSandbox(code); }, 400);
    } else { injectToSandbox(code); }
    log('代码已注入', 'ok');
  };

  $('btnWrapDoc').onclick = function() {
    var raw = $('codeInput').value;
    $('codeInput').value = '<!DOCTYPE html><html><head><meta charset="UTF-8"><style>body{margin:0;background:#f6f8fa;font-family:sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;}</style></head><body>' + raw + '</body></html>';
    log('已包裹为完整文档', 'info');
  };

  resetSandbox();
  log('手机沙箱实验台启动', 'ok');
  log('💀 新增「未知组件」App,用于投毒', 'warn');
  log('逻辑:先点未知组件 → 再点文件管理 → 文件变乱码', 'info');
</script>

</body>
</html>

Game Source: 手机沙箱实验台

Creator: EpicCoder88

Libraries: none

Complexity: complex (696 lines, 57.5 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: game-epiccoder88-muqnc4uf" to link back to the original. Then publish at arcadelab.ai/publish.