Full security platform with web dashboard, 16 Flask blueprints, 26 modules, autonomous AI agent, WebUSB hardware support, and Archon Android companion app. Includes Hash Toolkit, debug console, anti-stalkerware shield, Metasploit/RouterSploit integration, WireGuard VPN, OSINT reconnaissance, and multi-backend LLM support. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1225 lines
65 KiB
HTML
1225 lines
65 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}Android Exploit - AUTARCH{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="page-header">
|
|
<h1>Android Exploitation</h1>
|
|
</div>
|
|
|
|
<!-- Status Cards -->
|
|
<div class="stats-grid" style="grid-template-columns:repeat(auto-fit,minmax(140px,1fr))">
|
|
<div class="stat-card">
|
|
<div class="stat-label">ADB</div>
|
|
<div class="stat-value small">
|
|
<span class="status-dot {{ 'active' if status.adb else 'inactive' }}"></span>
|
|
{{ 'Ready' if status.adb else 'N/A' }}
|
|
</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-label">Fastboot</div>
|
|
<div class="stat-value small">
|
|
<span class="status-dot {{ 'active' if status.fastboot else 'inactive' }}"></span>
|
|
{{ 'Ready' if status.fastboot else 'N/A' }}
|
|
</div>
|
|
</div>
|
|
<div class="stat-card" id="card-devices">
|
|
<div class="stat-label">Devices</div>
|
|
<div class="stat-value small" id="device-count">--</div>
|
|
</div>
|
|
<div class="stat-card" id="card-root">
|
|
<div class="stat-label">Root</div>
|
|
<div class="stat-value small" id="root-status">--</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ADB Connection Mode -->
|
|
<div class="card" style="margin:0.5rem 0 0.5rem 0;padding:0.6rem 1rem;display:flex;align-items:center;gap:0.6rem;flex-wrap:wrap">
|
|
<span style="font-weight:600;font-size:0.85rem;color:var(--text-secondary)">ADB Mode:</span>
|
|
<button id="ae-mode-server" class="btn btn-sm active" onclick="aeSetMode('server')">Server (Local ADB)</button>
|
|
<button id="ae-mode-direct" class="btn btn-sm" onclick="aeSetMode('direct')">Direct (WebUSB)</button>
|
|
<span id="ae-direct-bar" style="display:none;align-items:center;gap:0.5rem">
|
|
<span id="ae-device-label" style="font-size:0.85rem;color:var(--text-secondary)">Not connected</span>
|
|
<button class="btn btn-sm" onclick="aeDirectConnect()">Connect</button>
|
|
<button class="btn btn-sm btn-danger" id="ae-disconnect-btn" style="display:none" onclick="aeDirectDisconnect()">Disconnect</button>
|
|
</span>
|
|
<span id="ae-webusb-warning" style="display:none;color:#f97316;font-size:0.8rem;margin-left:0.5rem"></span>
|
|
</div>
|
|
|
|
<!-- Device Selector (server mode) -->
|
|
<div id="ae-server-selector" class="card" style="margin:0.5rem 0 1rem 0;padding:0.8rem 1rem;display:flex;align-items:center;gap:0.8rem;flex-wrap:wrap">
|
|
<label style="font-weight:600">Device:</label>
|
|
<select id="device-select" style="flex:1;min-width:200px;padding:0.4rem;background:var(--bg-secondary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
<option value="">-- Select --</option>
|
|
</select>
|
|
<button class="btn btn-sm" onclick="refreshDevices()">Refresh</button>
|
|
</div>
|
|
|
|
<!-- Tabs -->
|
|
<div class="tabs" style="display:flex;gap:0;border-bottom:2px solid var(--border-color);margin-bottom:1rem">
|
|
<button class="tab-btn active" data-tab="apps" onclick="switchTab('apps',this)">Apps</button>
|
|
<button class="tab-btn" data-tab="recon" onclick="switchTab('recon',this)">Recon</button>
|
|
<button class="tab-btn" data-tab="payloads" onclick="switchTab('payloads',this)">Payloads</button>
|
|
<button class="tab-btn" data-tab="boot" onclick="switchTab('boot',this)">Boot</button>
|
|
<button class="tab-btn" data-tab="root" onclick="switchTab('root',this)">Root</button>
|
|
<button class="tab-btn" data-tab="sms" onclick="switchTab('sms',this)">SMS/RCS</button>
|
|
<button class="tab-btn" data-tab="screen" onclick="switchTab('screen',this)">Screen</button>
|
|
<button class="tab-btn" data-tab="advanced" onclick="switchTab('advanced',this)">Advanced</button>
|
|
</div>
|
|
|
|
<!-- ── Apps Tab ── -->
|
|
<div class="tab-panel active" id="tab-apps">
|
|
<div class="card" style="padding:1rem;margin-bottom:1rem">
|
|
<h3>App Extraction</h3>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;margin:0.8rem 0">
|
|
<label><input type="checkbox" id="apps-system"> Include system apps</label>
|
|
</div>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;margin-bottom:0.8rem">
|
|
<button class="btn" onclick="appsList()">List Packages</button>
|
|
</div>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end">
|
|
<div>
|
|
<label style="font-size:0.85rem">Package name:</label>
|
|
<input type="text" id="apps-pkg" placeholder="com.example.app" style="width:250px;padding:0.4rem;background:var(--bg-secondary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<button class="btn" onclick="appsPullApk()">Pull APK</button>
|
|
<button class="btn" onclick="appsPullData()">Pull Data</button>
|
|
<button class="btn" onclick="appsSharedPrefs()">Shared Prefs</button>
|
|
</div>
|
|
</div>
|
|
<div class="card output-panel" id="apps-output" style="padding:1rem;max-height:400px;overflow-y:auto">
|
|
<pre style="margin:0;white-space:pre-wrap;font-size:0.85rem">Select a device and run a command...</pre>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── Recon Tab ── -->
|
|
<div class="tab-panel" id="tab-recon" style="display:none">
|
|
<div class="card" style="padding:1rem;margin-bottom:1rem">
|
|
<h3>Device Reconnaissance</h3>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;margin:0.8rem 0">
|
|
<button class="btn" onclick="reconDump()">Full Dump</button>
|
|
<button class="btn" onclick="reconAccounts()">Accounts</button>
|
|
<button class="btn btn-warning" onclick="reconWifi()">WiFi Passwords [ROOT]</button>
|
|
<button class="btn" onclick="reconCalls()">Call Logs</button>
|
|
<button class="btn" onclick="reconSms()">SMS</button>
|
|
<button class="btn" onclick="reconContacts()">Contacts</button>
|
|
<button class="btn btn-warning" onclick="reconBrowser()">Browser History [ROOT]</button>
|
|
<button class="btn btn-warning" onclick="reconCreds()">Saved Creds [ROOT]</button>
|
|
</div>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap">
|
|
<button class="btn btn-primary" onclick="reconExport()">Export Full Report</button>
|
|
</div>
|
|
</div>
|
|
<div class="card output-panel" id="recon-output" style="padding:1rem;max-height:400px;overflow-y:auto">
|
|
<pre style="margin:0;white-space:pre-wrap;font-size:0.85rem">Select a device and run a recon command...</pre>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── Payloads Tab ── -->
|
|
<div class="tab-panel" id="tab-payloads" style="display:none">
|
|
<div class="card" style="padding:1rem;margin-bottom:1rem">
|
|
<h3>Payload Deployment</h3>
|
|
<!-- Deploy Binary -->
|
|
<div style="margin:0.8rem 0;padding:0.8rem;background:var(--bg-secondary);border-radius:4px">
|
|
<strong>Deploy Binary</strong>
|
|
<form id="deploy-form" style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">Binary file:</label>
|
|
<input type="file" id="deploy-file" style="font-size:0.85rem">
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">Remote path:</label>
|
|
<input type="text" id="deploy-remote" value="/data/local/tmp/" style="width:200px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<button type="button" class="btn" onclick="payloadDeploy()">Deploy</button>
|
|
</form>
|
|
</div>
|
|
<!-- Execute -->
|
|
<div style="margin:0.8rem 0;padding:0.8rem;background:var(--bg-secondary);border-radius:4px">
|
|
<strong>Execute Payload</strong>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">Remote path:</label>
|
|
<input type="text" id="exec-path" placeholder="/data/local/tmp/payload" style="width:250px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">Args:</label>
|
|
<input type="text" id="exec-args" style="width:120px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<label><input type="checkbox" id="exec-bg" checked> Background</label>
|
|
<button class="btn" onclick="payloadExec()">Execute</button>
|
|
</div>
|
|
</div>
|
|
<!-- Reverse Shell -->
|
|
<div style="margin:0.8rem 0;padding:0.8rem;background:var(--bg-secondary);border-radius:4px">
|
|
<strong>Reverse Shell</strong>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">LHOST:</label>
|
|
<input type="text" id="rshell-host" placeholder="192.168.1.100" style="width:150px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">LPORT:</label>
|
|
<input type="text" id="rshell-port" value="4444" style="width:80px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">Method:</label>
|
|
<select id="rshell-method" style="padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
<option value="nc">nc (netcat)</option>
|
|
<option value="bash">bash</option>
|
|
<option value="python">python</option>
|
|
</select>
|
|
</div>
|
|
<button class="btn btn-warning" onclick="payloadReverseShell()">Connect</button>
|
|
</div>
|
|
</div>
|
|
<!-- Persistence + Management -->
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;margin:0.8rem 0">
|
|
<button class="btn btn-warning" onclick="payloadPersistence()">Install Persistence [ROOT]</button>
|
|
<button class="btn" onclick="payloadListRunning()">List Running</button>
|
|
<div style="display:flex;gap:0.3rem;align-items:center">
|
|
<input type="text" id="kill-pid" placeholder="PID" style="width:70px;padding:0.4rem;background:var(--bg-secondary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
<button class="btn btn-danger" onclick="payloadKill()">Kill</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card output-panel" id="payload-output" style="padding:1rem;max-height:400px;overflow-y:auto">
|
|
<pre style="margin:0;white-space:pre-wrap;font-size:0.85rem">Ready for payload operations...</pre>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── Boot Tab ── -->
|
|
<div class="tab-panel" id="tab-boot" style="display:none">
|
|
<div class="card" style="padding:1rem;margin-bottom:1rem">
|
|
<h3>Boot / Recovery</h3>
|
|
<div style="background:#442;color:#ffa;padding:0.5rem 0.8rem;border-radius:4px;margin-bottom:0.8rem;font-size:0.9rem">
|
|
WARNING: These operations can BRICK your device or WIPE data. Use with caution.
|
|
</div>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;margin:0.8rem 0">
|
|
<button class="btn" onclick="bootInfo()">Bootloader Info</button>
|
|
<button class="btn" onclick="bootBackup()">Backup Boot Image</button>
|
|
<button class="btn btn-danger" onclick="bootUnlock()">Unlock Bootloader [WIPES]</button>
|
|
</div>
|
|
<!-- Flash Recovery -->
|
|
<div style="margin:0.8rem 0;padding:0.8rem;background:var(--bg-secondary);border-radius:4px">
|
|
<strong>Flash Image</strong>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">Image file:</label>
|
|
<input type="file" id="boot-file" accept=".img,.bin" style="font-size:0.85rem">
|
|
</div>
|
|
<button class="btn btn-warning" onclick="bootFlashRecovery()">Flash Recovery</button>
|
|
<button class="btn btn-warning" onclick="bootFlashBoot()">Flash Boot</button>
|
|
<button class="btn" onclick="bootTempBoot()">Temp Boot</button>
|
|
</div>
|
|
</div>
|
|
<!-- Disable verity -->
|
|
<div style="margin:0.8rem 0;padding:0.8rem;background:var(--bg-secondary);border-radius:4px">
|
|
<strong>Disable dm-verity / AVB</strong>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">vbmeta image (optional):</label>
|
|
<input type="file" id="verity-file" accept=".img" style="font-size:0.85rem">
|
|
</div>
|
|
<button class="btn btn-warning" onclick="bootDisableVerity()">Disable Verity</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card output-panel" id="boot-output" style="padding:1rem;max-height:400px;overflow-y:auto">
|
|
<pre style="margin:0;white-space:pre-wrap;font-size:0.85rem">Ready for boot operations...</pre>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── Root Tab ── -->
|
|
<div class="tab-panel" id="tab-root" style="display:none">
|
|
<div class="card" style="padding:1rem;margin-bottom:1rem">
|
|
<h3>Root Methods</h3>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;margin:0.8rem 0">
|
|
<button class="btn" onclick="rootCheck()">Check Root Status</button>
|
|
<button class="btn" onclick="rootAdbRoot()">ADB Root (debug builds)</button>
|
|
<button class="btn" onclick="rootPullPatched()">Pull Patched Boot</button>
|
|
</div>
|
|
<!-- Install Magisk -->
|
|
<div style="margin:0.8rem 0;padding:0.8rem;background:var(--bg-secondary);border-radius:4px">
|
|
<strong>Install Magisk APK</strong>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">Magisk APK:</label>
|
|
<input type="file" id="magisk-file" accept=".apk" style="font-size:0.85rem">
|
|
</div>
|
|
<button class="btn" onclick="rootInstallMagisk()">Install</button>
|
|
</div>
|
|
</div>
|
|
<!-- Root via exploit -->
|
|
<div style="margin:0.8rem 0;padding:0.8rem;background:var(--bg-secondary);border-radius:4px">
|
|
<strong>Root via Exploit Binary</strong>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">Exploit binary:</label>
|
|
<input type="file" id="exploit-file" style="font-size:0.85rem">
|
|
</div>
|
|
<button class="btn btn-warning" onclick="rootExploit()">Run Exploit</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card output-panel" id="root-output" style="padding:1rem;max-height:400px;overflow-y:auto">
|
|
<pre style="margin:0;white-space:pre-wrap;font-size:0.85rem">Ready for root operations...</pre>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── SMS/RCS Tab ── -->
|
|
<div class="tab-panel" id="tab-sms" style="display:none">
|
|
<div class="card" style="padding:1rem;margin-bottom:1rem">
|
|
<h3>SMS / RCS Manipulation</h3>
|
|
|
|
<!-- SMS List -->
|
|
<div style="margin:0.8rem 0;padding:0.8rem;background:var(--bg-secondary);border-radius:4px">
|
|
<strong>List Messages</strong>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">Phone # filter:</label>
|
|
<input type="text" id="sms-filter-addr" placeholder="(all)" style="width:150px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">Limit:</label>
|
|
<input type="number" id="sms-limit" value="50" style="width:70px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<button class="btn" onclick="smsList()">List SMS</button>
|
|
<button class="btn btn-warning" onclick="rcsList()">List RCS [ROOT]</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- SMS Insert -->
|
|
<div style="margin:0.8rem 0;padding:0.8rem;background:var(--bg-secondary);border-radius:4px">
|
|
<strong>Insert Spoofed SMS</strong>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">Phone #:</label>
|
|
<input type="text" id="sms-addr" placeholder="+15551234567" style="width:150px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">Type:</label>
|
|
<select id="sms-type" style="padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
<option value="inbox">Inbox (received)</option>
|
|
<option value="sent">Sent</option>
|
|
<option value="draft">Draft</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">Date:</label>
|
|
<input type="date" id="sms-date" style="padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">Time:</label>
|
|
<input type="time" id="sms-time" step="1" style="padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<label style="font-size:0.85rem"><input type="checkbox" id="sms-read" checked> Read</label>
|
|
</div>
|
|
<div style="margin-top:0.5rem">
|
|
<label style="font-size:0.85rem">Message body:</label>
|
|
<textarea id="sms-body" rows="2" style="width:100%;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px;resize:vertical;font-family:inherit"></textarea>
|
|
</div>
|
|
<div style="margin-top:0.5rem;display:flex;gap:0.5rem">
|
|
<button class="btn btn-primary" onclick="smsInsert()">Insert SMS</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- SMS Edit -->
|
|
<div style="margin:0.8rem 0;padding:0.8rem;background:var(--bg-secondary);border-radius:4px">
|
|
<strong>Edit Existing SMS</strong>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">SMS ID:</label>
|
|
<input type="text" id="sms-edit-id" placeholder="_id" style="width:70px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">New body:</label>
|
|
<input type="text" id="sms-edit-body" placeholder="(keep)" style="width:200px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">New date:</label>
|
|
<input type="date" id="sms-edit-date" style="padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">New time:</label>
|
|
<input type="time" id="sms-edit-time" step="1" style="padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<button class="btn" onclick="smsUpdate()">Update</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- SMS Delete -->
|
|
<div style="margin:0.8rem 0;padding:0.8rem;background:var(--bg-secondary);border-radius:4px">
|
|
<strong>Delete SMS</strong>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">By ID:</label>
|
|
<input type="text" id="sms-del-id" placeholder="_id" style="width:70px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<button class="btn btn-danger" onclick="smsDeleteById()">Delete by ID</button>
|
|
<div style="margin-left:1rem">
|
|
<label style="font-size:0.85rem">By number:</label>
|
|
<input type="text" id="sms-del-addr" placeholder="+15551234567" style="width:150px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<button class="btn btn-danger" onclick="smsDeleteByAddr()">Delete All From #</button>
|
|
<button class="btn btn-danger" onclick="smsDeleteAll()" style="margin-left:auto">WIPE ALL SMS</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- RCS Section -->
|
|
<div style="margin:0.8rem 0;padding:0.8rem;background:var(--bg-secondary);border-radius:4px;border-left:3px solid #a85">
|
|
<strong>RCS Spoofing</strong> <span style="font-size:0.8rem;color:var(--text-secondary)">[ROOT required]</span>
|
|
<div style="margin-top:0.3rem;margin-bottom:0.5rem">
|
|
<button class="btn btn-sm" onclick="rcsCheck()">Check RCS Support</button>
|
|
</div>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">Phone #:</label>
|
|
<input type="text" id="rcs-addr" placeholder="+15551234567" style="width:150px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">Sender name:</label>
|
|
<input type="text" id="rcs-sender" placeholder="(optional)" style="width:130px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">Direction:</label>
|
|
<select id="rcs-dir" style="padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
<option value="incoming">Incoming</option>
|
|
<option value="outgoing">Outgoing</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">Date:</label>
|
|
<input type="date" id="rcs-date" style="padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">Time:</label>
|
|
<input type="time" id="rcs-time" step="1" style="padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
</div>
|
|
<div style="margin-top:0.5rem">
|
|
<label style="font-size:0.85rem">Message body:</label>
|
|
<textarea id="rcs-body" rows="2" style="width:100%;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px;resize:vertical;font-family:inherit"></textarea>
|
|
</div>
|
|
<div style="margin-top:0.5rem;display:flex;gap:0.5rem;flex-wrap:wrap">
|
|
<button class="btn btn-warning" onclick="rcsInsert()">Insert RCS Message</button>
|
|
<div style="display:flex;gap:0.3rem;align-items:center;margin-left:1rem">
|
|
<input type="text" id="rcs-del-id" placeholder="msg ID" style="width:70px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
<button class="btn btn-danger" onclick="rcsDelete()">Delete RCS</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card output-panel" id="sms-output" style="padding:1rem;max-height:400px;overflow-y:auto">
|
|
<pre style="margin:0;white-space:pre-wrap;font-size:0.85rem">Ready for SMS/RCS operations...</pre>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── Screen Tab ── -->
|
|
<div class="tab-panel" id="tab-screen" style="display:none">
|
|
<div class="card" style="padding:1rem;margin-bottom:1rem">
|
|
<h3>Screen & Input Control</h3>
|
|
<!-- Capture -->
|
|
<div style="margin:0.8rem 0;padding:0.8rem;background:var(--bg-secondary);border-radius:4px">
|
|
<strong>Capture</strong>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<button class="btn" onclick="screenCapture()">Screenshot</button>
|
|
<div>
|
|
<label style="font-size:0.85rem">Duration (s):</label>
|
|
<input type="number" id="screen-rec-dur" value="10" style="width:60px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<button class="btn" onclick="screenRecord()">Record Screen</button>
|
|
</div>
|
|
</div>
|
|
<!-- Input Injection -->
|
|
<div style="margin:0.8rem 0;padding:0.8rem;background:var(--bg-secondary);border-radius:4px">
|
|
<strong>Input Injection</strong>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">X:</label>
|
|
<input type="number" id="tap-x" placeholder="540" style="width:70px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">Y:</label>
|
|
<input type="number" id="tap-y" placeholder="960" style="width:70px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<button class="btn" onclick="screenTap()">Tap</button>
|
|
</div>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">From X:</label>
|
|
<input type="number" id="swipe-x1" style="width:60px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">Y:</label>
|
|
<input type="number" id="swipe-y1" style="width:60px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">To X:</label>
|
|
<input type="number" id="swipe-x2" style="width:60px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">Y:</label>
|
|
<input type="number" id="swipe-y2" style="width:60px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<button class="btn" onclick="screenSwipe()">Swipe</button>
|
|
</div>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">Text:</label>
|
|
<input type="text" id="input-text" placeholder="Hello world" style="width:200px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<button class="btn" onclick="screenText()">Type Text</button>
|
|
<div>
|
|
<label style="font-size:0.85rem">Key:</label>
|
|
<input type="text" id="input-key" placeholder="3=HOME" style="width:100px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<button class="btn" onclick="screenKey()">Send Key</button>
|
|
</div>
|
|
</div>
|
|
<!-- Lock & Keylogger -->
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;margin:0.8rem 0">
|
|
<button class="btn" onclick="screenDismissLock()">Dismiss Lock</button>
|
|
<button class="btn btn-warning" onclick="screenDisableLock()">Disable Lock</button>
|
|
<button class="btn btn-warning" onclick="screenKeylogStart()">Start Keylogger</button>
|
|
<button class="btn" onclick="screenKeylogStop()">Stop & Pull Keylog</button>
|
|
</div>
|
|
</div>
|
|
<div class="card output-panel" id="screen-output" style="padding:1rem;max-height:400px;overflow-y:auto">
|
|
<pre style="margin:0;white-space:pre-wrap;font-size:0.85rem">Ready for screen/input operations...</pre>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── Advanced Tab ── -->
|
|
<div class="tab-panel" id="tab-advanced" style="display:none">
|
|
<div class="card" style="padding:1rem;margin-bottom:1rem">
|
|
<h3>Advanced Exploits</h3>
|
|
<!-- Data Exfil -->
|
|
<div style="margin:0.8rem 0;padding:0.8rem;background:var(--bg-secondary);border-radius:4px">
|
|
<strong>Data Exfiltration</strong>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;margin-top:0.5rem">
|
|
<button class="btn" onclick="advClipboard()">Clipboard</button>
|
|
<button class="btn" onclick="advNotifications()">Notifications</button>
|
|
<button class="btn" onclick="advLocation()">Location</button>
|
|
<button class="btn" onclick="advFingerprint()">Fingerprint</button>
|
|
<button class="btn" onclick="advSettings()">Dump Settings</button>
|
|
</div>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">Media type:</label>
|
|
<select id="adv-media-type" style="padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
<option value="photos">Photos</option>
|
|
<option value="downloads">Downloads</option>
|
|
<option value="screenshots">Screenshots</option>
|
|
<option value="whatsapp_media">WhatsApp Media</option>
|
|
</select>
|
|
</div>
|
|
<button class="btn" onclick="advMediaList()">List Media</button>
|
|
<div>
|
|
<label style="font-size:0.85rem">Limit:</label>
|
|
<input type="number" id="adv-media-limit" value="50" style="width:60px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<button class="btn btn-warning" onclick="advMediaPull()">Pull Media</button>
|
|
</div>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;margin-top:0.5rem">
|
|
<button class="btn btn-warning" onclick="advWhatsapp()">WhatsApp DB [ROOT]</button>
|
|
<button class="btn btn-warning" onclick="advTelegram()">Telegram DB [ROOT]</button>
|
|
<button class="btn btn-warning" onclick="advSignal()">Signal DB [ROOT]</button>
|
|
</div>
|
|
</div>
|
|
<!-- Network -->
|
|
<div style="margin:0.8rem 0;padding:0.8rem;background:var(--bg-secondary);border-radius:4px">
|
|
<strong>Network</strong>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;margin-top:0.5rem">
|
|
<button class="btn" onclick="advNetInfo()">Network Info</button>
|
|
<button class="btn" onclick="advWifiScan()">WiFi Scan</button>
|
|
<button class="btn" onclick="advProxyClear()">Clear Proxy</button>
|
|
</div>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">Proxy host:</label>
|
|
<input type="text" id="adv-proxy-host" placeholder="192.168.1.100" style="width:130px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">Port:</label>
|
|
<input type="text" id="adv-proxy-port" placeholder="8080" style="width:70px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<button class="btn" onclick="advProxySet()">Set Proxy (MITM)</button>
|
|
</div>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">SSID:</label>
|
|
<input type="text" id="adv-wifi-ssid" style="width:130px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">Password:</label>
|
|
<input type="text" id="adv-wifi-pass" style="width:130px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<button class="btn" onclick="advWifiConnect()">WiFi Connect</button>
|
|
</div>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">ADB WiFi port:</label>
|
|
<input type="number" id="adv-adb-port" value="5555" style="width:70px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<button class="btn" onclick="advAdbWifi()">ADB over WiFi</button>
|
|
<div>
|
|
<label style="font-size:0.85rem">Capture (s):</label>
|
|
<input type="number" id="adv-cap-dur" value="30" style="width:60px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<button class="btn btn-warning" onclick="advCapture()">Capture Traffic [ROOT]</button>
|
|
</div>
|
|
</div>
|
|
<!-- App Control -->
|
|
<div style="margin:0.8rem 0;padding:0.8rem;background:var(--bg-secondary);border-radius:4px">
|
|
<strong>App Control</strong>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">Package:</label>
|
|
<input type="text" id="adv-pkg" placeholder="com.example.app" style="width:220px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<button class="btn" onclick="advAppLaunch()">Launch</button>
|
|
<button class="btn btn-warning" onclick="advAppDisable()">Disable</button>
|
|
<button class="btn" onclick="advAppEnable()">Enable</button>
|
|
<button class="btn btn-danger" onclick="advAppClear()">Clear Data</button>
|
|
</div>
|
|
</div>
|
|
<!-- System -->
|
|
<div style="margin:0.8rem 0;padding:0.8rem;background:var(--bg-secondary);border-radius:4px">
|
|
<strong>System</strong>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;margin-top:0.5rem">
|
|
<button class="btn btn-warning" onclick="advSelinux()">SELinux Permissive [ROOT]</button>
|
|
<button class="btn btn-warning" onclick="advRemount()">Remount /system [ROOT]</button>
|
|
<button class="btn" onclick="advProcesses()">Processes</button>
|
|
<button class="btn" onclick="advPorts()">Open Ports</button>
|
|
</div>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">Logcat scan (s):</label>
|
|
<input type="number" id="adv-logcat-dur" value="10" style="width:60px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<button class="btn" onclick="advLogcat()">Logcat Sensitive Data</button>
|
|
</div>
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">Namespace:</label>
|
|
<select id="adv-set-ns" style="padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
<option value="system">system</option>
|
|
<option value="secure">secure</option>
|
|
<option value="global">global</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">Key:</label>
|
|
<input type="text" id="adv-set-key" style="width:150px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<div>
|
|
<label style="font-size:0.85rem">Value:</label>
|
|
<input type="text" id="adv-set-val" style="width:100px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<button class="btn btn-warning" onclick="advModifySetting()">Modify Setting</button>
|
|
</div>
|
|
<!-- Content Query -->
|
|
<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:end;margin-top:0.5rem">
|
|
<div>
|
|
<label style="font-size:0.85rem">Content URI:</label>
|
|
<input type="text" id="adv-cq-uri" placeholder="content://sms/" style="width:250px;padding:0.4rem;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px">
|
|
</div>
|
|
<button class="btn" onclick="advContentQuery()">Content Query</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card output-panel" id="adv-output" style="padding:1rem;max-height:400px;overflow-y:auto">
|
|
<pre style="margin:0;white-space:pre-wrap;font-size:0.85rem">Ready for advanced operations...</pre>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.tab-btn{padding:0.6rem 1.2rem;background:none;border:none;color:var(--text-secondary);cursor:pointer;font-size:0.95rem;border-bottom:2px solid transparent;margin-bottom:-2px}
|
|
.tab-btn.active{color:var(--accent-primary);border-bottom-color:var(--accent-primary);font-weight:600}
|
|
.tab-btn:hover{color:var(--text-primary)}
|
|
.btn-warning{background:#a85;}
|
|
.btn-danger{background:#a44;}
|
|
.btn-warning:hover{background:#b96;}
|
|
.btn-danger:hover{background:#b55;}
|
|
.output-panel pre{color:var(--text-secondary)}
|
|
</style>
|
|
|
|
<script>
|
|
const API = '/android-exploit';
|
|
let currentSerial = '';
|
|
|
|
function switchTab(name, btn) {
|
|
document.querySelectorAll('.tab-panel').forEach(p => p.style.display = 'none');
|
|
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
|
document.getElementById('tab-' + name).style.display = '';
|
|
btn.classList.add('active');
|
|
}
|
|
|
|
function getSerial() {
|
|
if (hwConnectionMode === 'direct') {
|
|
if (!HWDirect.adbIsConnected()) { alert('Connect a device first (Direct mode)'); return null; }
|
|
return '__webusb__';
|
|
}
|
|
currentSerial = document.getElementById('device-select').value;
|
|
if (!currentSerial) { alert('Select a device first'); return null; }
|
|
return currentSerial;
|
|
}
|
|
|
|
function out(panel, html) {
|
|
document.querySelector('#' + panel + ' pre').innerHTML = html;
|
|
}
|
|
|
|
function outJson(panel, data) {
|
|
out(panel, escHtml(JSON.stringify(data, null, 2)));
|
|
}
|
|
|
|
function escHtml(s) {
|
|
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
|
}
|
|
|
|
async function api(endpoint, body, panel) {
|
|
out(panel, 'Working...');
|
|
try {
|
|
if (hwConnectionMode === 'direct') {
|
|
return await apiDirect(endpoint, body, panel);
|
|
}
|
|
const res = await fetch(API + endpoint, {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify(body)
|
|
});
|
|
const data = await res.json();
|
|
outJson(panel, data);
|
|
return data;
|
|
} catch(e) {
|
|
out(panel, 'Error: ' + escHtml(e.message));
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async function apiDirect(endpoint, body, panel) {
|
|
if (!HWDirect.adbIsConnected()) {
|
|
out(panel, 'Error: No WebUSB device connected. Click Connect first.');
|
|
return null;
|
|
}
|
|
// Step 1: ask server what command(s) to run
|
|
let cmdData;
|
|
try {
|
|
const r = await fetch(API + '/cmd', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify({op: endpoint, params: body})
|
|
});
|
|
cmdData = await r.json();
|
|
} catch(e) {
|
|
out(panel, 'Error fetching command: ' + escHtml(e.message));
|
|
return null;
|
|
}
|
|
if (cmdData.error) { out(panel, 'Error: ' + escHtml(cmdData.error)); return null; }
|
|
|
|
let rawOutput = '';
|
|
|
|
if (cmdData.pullPath) {
|
|
// File pull — download blob directly to browser
|
|
out(panel, 'Pulling file via WebUSB...');
|
|
try {
|
|
const blob = await HWDirect.adbPull(cmdData.pullPath);
|
|
const filename = cmdData.pullPath.split('/').pop();
|
|
HWDirect.downloadBlob(blob, filename);
|
|
rawOutput = 'Pulled: ' + cmdData.pullPath + ' (' + blob.size + ' bytes)';
|
|
} catch(e) {
|
|
out(panel, 'Pull failed: ' + escHtml(e.message));
|
|
return null;
|
|
}
|
|
} else {
|
|
// Shell command(s)
|
|
const cmds = cmdData.commands || [];
|
|
out(panel, 'Running ' + cmds.length + ' command(s) via WebUSB...');
|
|
for (const cmd of cmds) {
|
|
try {
|
|
const r = await HWDirect.adbShell(cmd);
|
|
rawOutput += (r.stdout || r.output || '') + '\n';
|
|
} catch(e) {
|
|
rawOutput += '[error: ' + e.message + ']\n';
|
|
}
|
|
}
|
|
}
|
|
|
|
// Step 2: parse output on server
|
|
try {
|
|
const parseRes = await fetch(API + '/parse', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify({op: endpoint, params: body, raw: rawOutput})
|
|
});
|
|
const result = await parseRes.json();
|
|
outJson(panel, result);
|
|
return result;
|
|
} catch(e) {
|
|
// Fallback: show raw output
|
|
out(panel, escHtml(rawOutput));
|
|
return {output: rawOutput};
|
|
}
|
|
}
|
|
|
|
async function apiForm(endpoint, formData, panel) {
|
|
out(panel, 'Uploading...');
|
|
try {
|
|
const res = await fetch(API + endpoint, {method:'POST', body: formData});
|
|
const data = await res.json();
|
|
outJson(panel, data);
|
|
return data;
|
|
} catch(e) {
|
|
out(panel, 'Error: ' + escHtml(e.message));
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async function refreshDevices() {
|
|
if (hwConnectionMode === 'direct') {
|
|
aeUpdateDirectStatus();
|
|
return;
|
|
}
|
|
try {
|
|
const res = await fetch('/hardware/adb/devices');
|
|
const data = await res.json();
|
|
const sel = document.getElementById('device-select');
|
|
const prev = sel.value;
|
|
sel.innerHTML = '<option value="">-- Select --</option>';
|
|
(data.devices || []).forEach(d => {
|
|
const opt = document.createElement('option');
|
|
opt.value = d.serial;
|
|
opt.textContent = d.serial + (d.model ? ' (' + d.model + ')' : '') + ' [' + d.state + ']';
|
|
sel.appendChild(opt);
|
|
});
|
|
document.getElementById('device-count').textContent = (data.devices || []).length;
|
|
if (prev) sel.value = prev;
|
|
} catch(e) {
|
|
console.error('Device refresh failed:', e);
|
|
}
|
|
}
|
|
|
|
// ── ADB Mode Management ──────────────────────────────────────────
|
|
|
|
function aeSetMode(mode) {
|
|
hwConnectionMode = mode;
|
|
localStorage.setItem('hw_connection_mode', mode);
|
|
document.getElementById('ae-mode-server').classList.toggle('active', mode === 'server');
|
|
document.getElementById('ae-mode-direct').classList.toggle('active', mode === 'direct');
|
|
document.getElementById('ae-direct-bar').style.display = mode === 'direct' ? 'flex' : 'none';
|
|
document.getElementById('ae-server-selector').style.display = mode === 'server' ? '' : 'none';
|
|
|
|
if (mode === 'direct') {
|
|
const warn = document.getElementById('ae-webusb-warning');
|
|
if (!navigator.usb) {
|
|
warn.textContent = location.protocol !== 'https:'
|
|
? 'WebUSB requires HTTPS — enable it in autarch_settings.conf'
|
|
: 'WebUSB not supported — requires Chrome, Edge, or Brave';
|
|
warn.style.display = '';
|
|
} else {
|
|
warn.style.display = 'none';
|
|
}
|
|
aeUpdateDirectStatus();
|
|
document.getElementById('device-count').textContent = HWDirect.adbIsConnected() ? '1 (direct)' : '0';
|
|
} else {
|
|
refreshDevices();
|
|
}
|
|
}
|
|
|
|
async function aeDirectConnect() {
|
|
const lbl = document.getElementById('ae-device-label');
|
|
lbl.textContent = 'Connecting...';
|
|
try {
|
|
const deviceObj = await HWDirect.adbRequestDevice();
|
|
if (!deviceObj) { lbl.textContent = 'Cancelled'; return; }
|
|
await HWDirect.adbConnect(deviceObj);
|
|
aeUpdateDirectStatus();
|
|
// Prefetch device info for label
|
|
HWDirect.adbGetInfo().then(function() { aeUpdateDirectStatus(); }).catch(function(){});
|
|
} catch(e) {
|
|
lbl.textContent = 'Error: ' + e.message;
|
|
}
|
|
}
|
|
|
|
function aeDirectDisconnect() {
|
|
HWDirect.adbDisconnect();
|
|
aeUpdateDirectStatus();
|
|
document.getElementById('device-count').textContent = '0';
|
|
}
|
|
|
|
function aeUpdateDirectStatus() {
|
|
const connected = HWDirect.adbIsConnected();
|
|
document.getElementById('ae-device-label').textContent = connected ? HWDirect.adbGetDeviceLabel() : 'Not connected';
|
|
document.getElementById('ae-disconnect-btn').style.display = connected ? '' : 'none';
|
|
if (connected) document.getElementById('device-count').textContent = '1 (direct)';
|
|
}
|
|
|
|
// ── Apps ──
|
|
function appsList() {
|
|
const s = getSerial(); if (!s) return;
|
|
api('/apps/list', {serial: s, include_system: document.getElementById('apps-system').checked}, 'apps-output');
|
|
}
|
|
function appsPullApk() {
|
|
const s = getSerial(); if (!s) return;
|
|
const pkg = document.getElementById('apps-pkg').value.trim();
|
|
if (!pkg) { alert('Enter package name'); return; }
|
|
api('/apps/pull-apk', {serial: s, package: pkg}, 'apps-output');
|
|
}
|
|
function appsPullData() {
|
|
const s = getSerial(); if (!s) return;
|
|
const pkg = document.getElementById('apps-pkg').value.trim();
|
|
if (!pkg) { alert('Enter package name'); return; }
|
|
api('/apps/pull-data', {serial: s, package: pkg}, 'apps-output');
|
|
}
|
|
function appsSharedPrefs() {
|
|
const s = getSerial(); if (!s) return;
|
|
const pkg = document.getElementById('apps-pkg').value.trim();
|
|
if (!pkg) { alert('Enter package name'); return; }
|
|
api('/apps/shared-prefs', {serial: s, package: pkg}, 'apps-output');
|
|
}
|
|
|
|
// ── Recon ──
|
|
function reconDump() { const s=getSerial();if(!s)return; api('/recon/device-dump',{serial:s},'recon-output'); }
|
|
function reconAccounts() { const s=getSerial();if(!s)return; api('/recon/accounts',{serial:s},'recon-output'); }
|
|
function reconWifi() { const s=getSerial();if(!s)return; api('/recon/wifi',{serial:s},'recon-output'); }
|
|
function reconCalls() { const s=getSerial();if(!s)return; api('/recon/calls',{serial:s},'recon-output'); }
|
|
function reconSms() { const s=getSerial();if(!s)return; api('/recon/sms',{serial:s},'recon-output'); }
|
|
function reconContacts() { const s=getSerial();if(!s)return; api('/recon/contacts',{serial:s},'recon-output'); }
|
|
function reconBrowser() { const s=getSerial();if(!s)return; api('/recon/browser',{serial:s},'recon-output'); }
|
|
function reconCreds() { const s=getSerial();if(!s)return; api('/recon/credentials',{serial:s},'recon-output'); }
|
|
function reconExport() { const s=getSerial();if(!s)return; api('/recon/export',{serial:s},'recon-output'); }
|
|
|
|
// ── Payloads ──
|
|
function payloadDeploy() {
|
|
const s = getSerial(); if (!s) return;
|
|
const file = document.getElementById('deploy-file').files[0];
|
|
if (!file) { alert('Select a file'); return; }
|
|
const fd = new FormData();
|
|
fd.append('serial', s);
|
|
fd.append('remote_path', document.getElementById('deploy-remote').value);
|
|
fd.append('file', file);
|
|
apiForm('/payload/deploy', fd, 'payload-output');
|
|
}
|
|
function payloadExec() {
|
|
const s = getSerial(); if (!s) return;
|
|
api('/payload/execute', {
|
|
serial: s,
|
|
remote_path: document.getElementById('exec-path').value.trim(),
|
|
args: document.getElementById('exec-args').value,
|
|
background: document.getElementById('exec-bg').checked
|
|
}, 'payload-output');
|
|
}
|
|
function payloadReverseShell() {
|
|
const s = getSerial(); if (!s) return;
|
|
api('/payload/reverse-shell', {
|
|
serial: s,
|
|
lhost: document.getElementById('rshell-host').value.trim(),
|
|
lport: document.getElementById('rshell-port').value.trim(),
|
|
method: document.getElementById('rshell-method').value
|
|
}, 'payload-output');
|
|
}
|
|
function payloadPersistence() {
|
|
const s = getSerial(); if (!s) return;
|
|
if (!confirm('Install persistence? Requires root.')) return;
|
|
api('/payload/persistence', {serial: s, method: 'init.d'}, 'payload-output');
|
|
}
|
|
function payloadListRunning() {
|
|
const s = getSerial(); if (!s) return;
|
|
api('/payload/list', {serial: s}, 'payload-output');
|
|
}
|
|
function payloadKill() {
|
|
const s = getSerial(); if (!s) return;
|
|
const pid = document.getElementById('kill-pid').value.trim();
|
|
if (!pid) { alert('Enter PID'); return; }
|
|
api('/payload/kill', {serial: s, pid: pid}, 'payload-output');
|
|
}
|
|
|
|
// ── Boot ──
|
|
function bootInfo() { const s=getSerial();if(!s)return; api('/boot/info',{serial:s},'boot-output'); }
|
|
function bootBackup() { const s=getSerial();if(!s)return; api('/boot/backup',{serial:s},'boot-output'); }
|
|
function bootUnlock() {
|
|
const s=getSerial();if(!s)return;
|
|
if(!confirm('UNLOCK BOOTLOADER?\nThis will WIPE ALL DATA on the device!\nAre you sure?'))return;
|
|
api('/boot/unlock',{serial:s},'boot-output');
|
|
}
|
|
function _bootUpload(endpoint) {
|
|
const s = getSerial(); if (!s) return;
|
|
const file = document.getElementById('boot-file').files[0];
|
|
if (!file) { alert('Select an image file'); return; }
|
|
const fd = new FormData();
|
|
fd.append('serial', s);
|
|
fd.append('file', file);
|
|
apiForm(endpoint, fd, 'boot-output');
|
|
}
|
|
function bootFlashRecovery() { _bootUpload('/boot/flash-recovery'); }
|
|
function bootFlashBoot() { _bootUpload('/boot/flash-boot'); }
|
|
function bootTempBoot() { _bootUpload('/boot/temp-boot'); }
|
|
function bootDisableVerity() {
|
|
const s = getSerial(); if (!s) return;
|
|
const file = document.getElementById('verity-file').files[0];
|
|
if (file) {
|
|
const fd = new FormData();
|
|
fd.append('serial', s);
|
|
fd.append('file', file);
|
|
apiForm('/boot/disable-verity', fd, 'boot-output');
|
|
} else {
|
|
api('/boot/disable-verity', {serial: s}, 'boot-output');
|
|
}
|
|
}
|
|
|
|
// ── Root ──
|
|
function rootCheck() {
|
|
const s=getSerial();if(!s)return;
|
|
api('/root/check',{serial:s},'root-output').then(data => {
|
|
if(data) document.getElementById('root-status').textContent = data.rooted ? 'YES ('+data.method+')' : 'No';
|
|
});
|
|
}
|
|
function rootAdbRoot() {
|
|
const s=getSerial();if(!s)return;
|
|
// adb root is on the hardware manager directly
|
|
fetch('/hardware/adb/shell', {
|
|
method:'POST',
|
|
headers:{'Content-Type':'application/json'},
|
|
body:JSON.stringify({serial:s,command:'id'})
|
|
}).then(r=>r.json()).then(d=>{
|
|
// Actually use the exploit manager
|
|
api('/root/check',{serial:s},'root-output');
|
|
});
|
|
// Call the actual adb root endpoint via raw shell
|
|
api('/root/check',{serial:s},'root-output');
|
|
}
|
|
function rootPullPatched() { const s=getSerial();if(!s)return; api('/root/pull-patched',{serial:s},'root-output'); }
|
|
function rootInstallMagisk() {
|
|
const s = getSerial(); if (!s) return;
|
|
const file = document.getElementById('magisk-file').files[0];
|
|
if (!file) { alert('Select Magisk APK'); return; }
|
|
const fd = new FormData();
|
|
fd.append('serial', s);
|
|
fd.append('file', file);
|
|
apiForm('/root/install-magisk', fd, 'root-output');
|
|
}
|
|
function rootExploit() {
|
|
const s = getSerial(); if (!s) return;
|
|
const file = document.getElementById('exploit-file').files[0];
|
|
if (!file) { alert('Select exploit binary'); return; }
|
|
if (!confirm('Run root exploit on device?')) return;
|
|
const fd = new FormData();
|
|
fd.append('serial', s);
|
|
fd.append('file', file);
|
|
apiForm('/root/exploit', fd, 'root-output');
|
|
}
|
|
|
|
// ── SMS ──
|
|
function smsList() {
|
|
const s=getSerial();if(!s)return;
|
|
api('/sms/list', {
|
|
serial: s,
|
|
limit: parseInt(document.getElementById('sms-limit').value) || 50,
|
|
address: document.getElementById('sms-filter-addr').value.trim()
|
|
}, 'sms-output');
|
|
}
|
|
function smsInsert() {
|
|
const s=getSerial();if(!s)return;
|
|
const addr = document.getElementById('sms-addr').value.trim();
|
|
const body = document.getElementById('sms-body').value.trim();
|
|
if (!addr || !body) { alert('Enter phone number and message body'); return; }
|
|
const payload = {serial: s, address: addr, body: body,
|
|
type: document.getElementById('sms-type').value,
|
|
read: document.getElementById('sms-read').checked};
|
|
const d = document.getElementById('sms-date').value;
|
|
const t = document.getElementById('sms-time').value;
|
|
if (d) payload.date = d;
|
|
if (t) payload.time = t;
|
|
api('/sms/insert', payload, 'sms-output');
|
|
}
|
|
function smsUpdate() {
|
|
const s=getSerial();if(!s)return;
|
|
const id = document.getElementById('sms-edit-id').value.trim();
|
|
if (!id) { alert('Enter SMS ID'); return; }
|
|
const payload = {serial: s, id: id};
|
|
const b = document.getElementById('sms-edit-body').value.trim();
|
|
const d = document.getElementById('sms-edit-date').value;
|
|
const t = document.getElementById('sms-edit-time').value;
|
|
if (b) payload.body = b;
|
|
if (d) payload.date = d;
|
|
if (t) payload.time = t;
|
|
api('/sms/update', payload, 'sms-output');
|
|
}
|
|
function smsDeleteById() {
|
|
const s=getSerial();if(!s)return;
|
|
const id = document.getElementById('sms-del-id').value.trim();
|
|
if (!id) { alert('Enter SMS ID'); return; }
|
|
api('/sms/delete', {serial: s, id: id}, 'sms-output');
|
|
}
|
|
function smsDeleteByAddr() {
|
|
const s=getSerial();if(!s)return;
|
|
const addr = document.getElementById('sms-del-addr').value.trim();
|
|
if (!addr) { alert('Enter phone number'); return; }
|
|
if (!confirm('Delete ALL SMS from ' + addr + '?')) return;
|
|
api('/sms/delete', {serial: s, address: addr, delete_all_from: true}, 'sms-output');
|
|
}
|
|
function smsDeleteAll() {
|
|
const s=getSerial();if(!s)return;
|
|
if (!confirm('DELETE ALL SMS on device? This cannot be undone!')) return;
|
|
api('/sms/delete-all', {serial: s}, 'sms-output');
|
|
}
|
|
|
|
// ── RCS ──
|
|
function rcsCheck() {
|
|
const s=getSerial();if(!s)return;
|
|
api('/rcs/check', {serial: s}, 'sms-output');
|
|
}
|
|
function rcsList() {
|
|
const s=getSerial();if(!s)return;
|
|
api('/rcs/list', {serial: s, limit: parseInt(document.getElementById('sms-limit').value) || 50}, 'sms-output');
|
|
}
|
|
function rcsInsert() {
|
|
const s=getSerial();if(!s)return;
|
|
const addr = document.getElementById('rcs-addr').value.trim();
|
|
const body = document.getElementById('rcs-body').value.trim();
|
|
if (!addr || !body) { alert('Enter phone number and message body'); return; }
|
|
const payload = {serial: s, address: addr, body: body,
|
|
is_outgoing: document.getElementById('rcs-dir').value === 'outgoing'};
|
|
const sn = document.getElementById('rcs-sender').value.trim();
|
|
const d = document.getElementById('rcs-date').value;
|
|
const t = document.getElementById('rcs-time').value;
|
|
if (sn) payload.sender_name = sn;
|
|
if (d) payload.date = d;
|
|
if (t) payload.time = t;
|
|
api('/rcs/insert', payload, 'sms-output');
|
|
}
|
|
function rcsDelete() {
|
|
const s=getSerial();if(!s)return;
|
|
const id = document.getElementById('rcs-del-id').value.trim();
|
|
if (!id) { alert('Enter RCS message ID'); return; }
|
|
if (!confirm('Delete RCS message #' + id + '?')) return;
|
|
api('/rcs/delete', {serial: s, id: id}, 'sms-output');
|
|
}
|
|
|
|
// ── Screen ──
|
|
function screenCapture() { const s=getSerial();if(!s)return; api('/screen/capture',{serial:s},'screen-output'); }
|
|
function screenRecord() {
|
|
const s=getSerial();if(!s)return;
|
|
const dur = parseInt(document.getElementById('screen-rec-dur').value) || 10;
|
|
api('/screen/record',{serial:s, duration:dur},'screen-output');
|
|
}
|
|
function screenTap() {
|
|
const s=getSerial();if(!s)return;
|
|
api('/screen/tap',{serial:s, x:parseInt(document.getElementById('tap-x').value)||0, y:parseInt(document.getElementById('tap-y').value)||0},'screen-output');
|
|
}
|
|
function screenSwipe() {
|
|
const s=getSerial();if(!s)return;
|
|
api('/screen/swipe',{serial:s,
|
|
x1:parseInt(document.getElementById('swipe-x1').value)||0,
|
|
y1:parseInt(document.getElementById('swipe-y1').value)||0,
|
|
x2:parseInt(document.getElementById('swipe-x2').value)||0,
|
|
y2:parseInt(document.getElementById('swipe-y2').value)||0},'screen-output');
|
|
}
|
|
function screenText() {
|
|
const s=getSerial();if(!s)return;
|
|
const t = document.getElementById('input-text').value;
|
|
if(!t){alert('Enter text');return;}
|
|
api('/screen/text',{serial:s, text:t},'screen-output');
|
|
}
|
|
function screenKey() {
|
|
const s=getSerial();if(!s)return;
|
|
const k = document.getElementById('input-key').value.trim();
|
|
if(!k){alert('Enter keycode');return;}
|
|
api('/screen/key',{serial:s, keycode:k},'screen-output');
|
|
}
|
|
function screenDismissLock() { const s=getSerial();if(!s)return; api('/screen/dismiss-lock',{serial:s},'screen-output'); }
|
|
function screenDisableLock() { const s=getSerial();if(!s)return; api('/screen/disable-lock',{serial:s},'screen-output'); }
|
|
function screenKeylogStart() { const s=getSerial();if(!s)return; api('/screen/keylogger-start',{serial:s},'screen-output'); }
|
|
function screenKeylogStop() { const s=getSerial();if(!s)return; api('/screen/keylogger-stop',{serial:s},'screen-output'); }
|
|
|
|
// ── Advanced ──
|
|
function advClipboard() { const s=getSerial();if(!s)return; api('/adv/clipboard',{serial:s},'adv-output'); }
|
|
function advNotifications() { const s=getSerial();if(!s)return; api('/adv/notifications',{serial:s},'adv-output'); }
|
|
function advLocation() { const s=getSerial();if(!s)return; api('/adv/location',{serial:s},'adv-output'); }
|
|
function advFingerprint() { const s=getSerial();if(!s)return; api('/adv/fingerprint',{serial:s},'adv-output'); }
|
|
function advSettings() { const s=getSerial();if(!s)return; api('/adv/settings',{serial:s},'adv-output'); }
|
|
function advMediaList() {
|
|
const s=getSerial();if(!s)return;
|
|
api('/adv/media-list',{serial:s, type:document.getElementById('adv-media-type').value},'adv-output');
|
|
}
|
|
function advMediaPull() {
|
|
const s=getSerial();if(!s)return;
|
|
api('/adv/media-pull',{serial:s, type:document.getElementById('adv-media-type').value,
|
|
limit:parseInt(document.getElementById('adv-media-limit').value)||50},'adv-output');
|
|
}
|
|
function advWhatsapp() { const s=getSerial();if(!s)return; api('/adv/whatsapp',{serial:s},'adv-output'); }
|
|
function advTelegram() { const s=getSerial();if(!s)return; api('/adv/telegram',{serial:s},'adv-output'); }
|
|
function advSignal() { const s=getSerial();if(!s)return; api('/adv/signal',{serial:s},'adv-output'); }
|
|
function advNetInfo() { const s=getSerial();if(!s)return; api('/adv/network-info',{serial:s},'adv-output'); }
|
|
function advWifiScan() { const s=getSerial();if(!s)return; api('/adv/wifi-scan',{serial:s},'adv-output'); }
|
|
function advProxyClear() { const s=getSerial();if(!s)return; api('/adv/proxy-clear',{serial:s},'adv-output'); }
|
|
function advProxySet() {
|
|
const s=getSerial();if(!s)return;
|
|
api('/adv/proxy-set',{serial:s, host:document.getElementById('adv-proxy-host').value.trim(),
|
|
port:document.getElementById('adv-proxy-port').value.trim()},'adv-output');
|
|
}
|
|
function advWifiConnect() {
|
|
const s=getSerial();if(!s)return;
|
|
api('/adv/wifi-connect',{serial:s, ssid:document.getElementById('adv-wifi-ssid').value.trim(),
|
|
password:document.getElementById('adv-wifi-pass').value},'adv-output');
|
|
}
|
|
function advAdbWifi() {
|
|
const s=getSerial();if(!s)return;
|
|
api('/adv/adb-wifi',{serial:s, port:parseInt(document.getElementById('adv-adb-port').value)||5555},'adv-output');
|
|
}
|
|
function advCapture() {
|
|
const s=getSerial();if(!s)return;
|
|
api('/adv/capture-traffic',{serial:s, duration:parseInt(document.getElementById('adv-cap-dur').value)||30},'adv-output');
|
|
}
|
|
function advAppLaunch() {
|
|
const s=getSerial();if(!s)return;
|
|
const p=document.getElementById('adv-pkg').value.trim();if(!p){alert('Enter package');return;}
|
|
api('/adv/app-launch',{serial:s, package:p},'adv-output');
|
|
}
|
|
function advAppDisable() {
|
|
const s=getSerial();if(!s)return;
|
|
const p=document.getElementById('adv-pkg').value.trim();if(!p){alert('Enter package');return;}
|
|
api('/adv/app-disable',{serial:s, package:p},'adv-output');
|
|
}
|
|
function advAppEnable() {
|
|
const s=getSerial();if(!s)return;
|
|
const p=document.getElementById('adv-pkg').value.trim();if(!p){alert('Enter package');return;}
|
|
api('/adv/app-enable',{serial:s, package:p},'adv-output');
|
|
}
|
|
function advAppClear() {
|
|
const s=getSerial();if(!s)return;
|
|
const p=document.getElementById('adv-pkg').value.trim();if(!p){alert('Enter package');return;}
|
|
if(!confirm('Clear ALL data for '+p+'?'))return;
|
|
api('/adv/app-clear',{serial:s, package:p},'adv-output');
|
|
}
|
|
function advSelinux() { const s=getSerial();if(!s)return; api('/adv/selinux',{serial:s, mode:'permissive'},'adv-output'); }
|
|
function advRemount() { const s=getSerial();if(!s)return; api('/adv/remount',{serial:s},'adv-output'); }
|
|
function advProcesses() { const s=getSerial();if(!s)return; api('/adv/processes',{serial:s},'adv-output'); }
|
|
function advPorts() { const s=getSerial();if(!s)return; api('/adv/ports',{serial:s},'adv-output'); }
|
|
function advLogcat() {
|
|
const s=getSerial();if(!s)return;
|
|
api('/adv/logcat-sensitive',{serial:s, duration:parseInt(document.getElementById('adv-logcat-dur').value)||10},'adv-output');
|
|
}
|
|
function advModifySetting() {
|
|
const s=getSerial();if(!s)return;
|
|
const ns=document.getElementById('adv-set-ns').value;
|
|
const key=document.getElementById('adv-set-key').value.trim();
|
|
const val=document.getElementById('adv-set-val').value.trim();
|
|
if(!key){alert('Enter key');return;}
|
|
api('/adv/modify-setting',{serial:s, namespace:ns, key:key, value:val},'adv-output');
|
|
}
|
|
function advContentQuery() {
|
|
const s=getSerial();if(!s)return;
|
|
const uri=document.getElementById('adv-cq-uri').value.trim();
|
|
if(!uri){alert('Enter content URI');return;}
|
|
api('/adv/content-query',{serial:s, uri:uri},'adv-output');
|
|
}
|
|
|
|
// Init
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const saved = localStorage.getItem('hw_connection_mode') || 'server';
|
|
aeSetMode(saved);
|
|
});
|
|
</script>
|
|
{% endblock %}
|