Add driver spoofing + stealth system
Driver spoof: mount namespace isolation keeps stock files visible to verification (dm-verity, Play Integrity, hash checks) while custom drivers load into target processes (surfaceflinger, wpa_supplicant, bluetooth). SELinux context, timestamps, perms, ownership all cloned from stock. Per-process or global modes. Configurable driver map for GPU, WiFi firmware, BT firmware. Stealth: process name masking (rtl_tcp->mediastream, etc), non-stock prop removal, MAC randomization (WiFi+BT), USB device permission tightening, log purging, logcat suppression. Full mode combines all stealth features. WebUI panels for both spoof and stealth control.
This commit is contained in:
@@ -357,6 +357,68 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Driver Spoofing -->
|
||||
<div class="card">
|
||||
<div class="card-title"><span class="dot" id="spoofDot"></span> Driver Spoofing</div>
|
||||
<div class="row">
|
||||
<div>
|
||||
<div class="row-label">Spoof Engine</div>
|
||||
<div class="row-desc">Mount namespace isolation — stock hashes preserved</div>
|
||||
</div>
|
||||
<select class="sel" id="spoofEnabled" onchange="setConf('spoof_enabled', this.value)">
|
||||
<option value="0">Disabled</option>
|
||||
<option value="1">Enabled</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div><div class="row-label">Active Spoofs</div></div>
|
||||
<div class="row-value" id="spoofStatus">—</div>
|
||||
</div>
|
||||
<div class="btn-row">
|
||||
<button class="btn" onclick="spoofAction('apply')">Apply Spoofs</button>
|
||||
<button class="btn" onclick="spoofAction('restore')">Restore Stock</button>
|
||||
<button class="btn" onclick="spoofAction('status')">Check Status</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stealth -->
|
||||
<div class="card">
|
||||
<div class="card-title"><span class="dot" id="stealthDot"></span> Stealth</div>
|
||||
<div class="row">
|
||||
<div>
|
||||
<div class="row-label">Stealth Mode</div>
|
||||
<div class="row-desc">Hide module, mask processes, clean traces</div>
|
||||
</div>
|
||||
<select class="sel" id="stealthMode" onchange="setStealthMode(this.value)">
|
||||
<option value="off">Off</option>
|
||||
<option value="hide_module">Hide Module</option>
|
||||
<option value="mask_procs">Mask Processes</option>
|
||||
<option value="hide_props">Hide Props</option>
|
||||
<option value="mac_random">MAC Randomization</option>
|
||||
<option value="hide_usb">Hide USB Devices</option>
|
||||
<option value="clean_logs">Clean Logs</option>
|
||||
<option value="full">Full Stealth</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div>
|
||||
<div class="row-label">Stealth Status</div>
|
||||
<div class="row-desc" id="stealthStatus">Inactive</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div>
|
||||
<div class="row-label">MAC Randomization</div>
|
||||
<div class="row-desc">WiFi + Bluetooth address randomization</div>
|
||||
</div>
|
||||
<div class="row-value" id="macStatus">—</div>
|
||||
</div>
|
||||
<div class="btn-row">
|
||||
<button class="btn" onclick="purgeTraces()">Purge All Traces</button>
|
||||
<button class="btn btn-primary" onclick="applyStealthNow()">Apply Now</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Log -->
|
||||
<div class="card">
|
||||
<div class="card-title">Log</div>
|
||||
@@ -431,6 +493,101 @@
|
||||
if (fmFreq) document.getElementById('fmFreq').value = fmFreq;
|
||||
}
|
||||
|
||||
async function spoofAction(action) {
|
||||
log('Spoof: ' + action);
|
||||
const r = await exec('sh ' + MODDIR + '/scripts/driver_spoof.sh ' + action);
|
||||
const out = r.stdout.trim();
|
||||
if (out) {
|
||||
document.getElementById('spoofStatus').textContent = out.split('\n').filter(l => l.includes('ACTIVE') || l.includes('INACTIVE')).join(' | ') || out.substring(0, 80);
|
||||
log(out);
|
||||
}
|
||||
await loadSpoofStatus();
|
||||
}
|
||||
|
||||
async function loadSpoofStatus() {
|
||||
const enabled = (await exec('cat ' + MODDIR + '/config/spoof_enabled 2>/dev/null')).stdout.trim();
|
||||
document.getElementById('spoofEnabled').value = enabled || '0';
|
||||
|
||||
const dot = document.getElementById('spoofDot');
|
||||
if (enabled === '1') {
|
||||
const r = await exec('mount | grep /data/adb/modules/driver-manager/drivers | wc -l');
|
||||
const count = r.stdout.trim();
|
||||
dot.className = 'dot' + (count > 0 ? '' : ' warn');
|
||||
document.getElementById('spoofStatus').textContent = count > 0 ? count + ' active bind mount(s)' : 'Enabled, not yet applied';
|
||||
} else {
|
||||
dot.className = 'dot off';
|
||||
document.getElementById('spoofStatus').textContent = 'Disabled';
|
||||
}
|
||||
}
|
||||
|
||||
async function setStealthMode(mode) {
|
||||
log('Setting stealth: ' + mode);
|
||||
await exec('echo "' + mode + '" > ' + MODDIR + '/config/stealth_mode');
|
||||
log('Stealth mode set to: ' + mode + '. Apply or reboot to activate.');
|
||||
await loadStealthStatus();
|
||||
}
|
||||
|
||||
async function applyStealthNow() {
|
||||
log('Applying stealth...');
|
||||
await exec('sh ' + MODDIR + '/service.sh &');
|
||||
setTimeout(async () => {
|
||||
await loadStealthStatus();
|
||||
log('Stealth applied');
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
async function purgeTraces() {
|
||||
log('Purging all traces...');
|
||||
// Clear module logs
|
||||
await exec('echo "" > ' + MODDIR + '/driver-manager.log');
|
||||
// Clear logcat entries from our tags
|
||||
await exec('logcat -b all -c 2>/dev/null');
|
||||
// Remove stealth wrappers (recreated on next apply)
|
||||
await exec('rm -rf ' + MODDIR + '/.wrappers');
|
||||
// Clear run state
|
||||
await exec('rm -f ' + MODDIR + '/run/*.pid');
|
||||
// Clear stream data
|
||||
await exec('rm -f ' + MODDIR + '/streams/*');
|
||||
// Clear spectrum/adsb output
|
||||
await exec('rm -f ' + MODDIR + '/spectrum_data.csv ' + MODDIR + '/adsb_output.txt');
|
||||
document.getElementById('logArea').textContent = 'Traces purged.';
|
||||
log('All traces purged');
|
||||
await loadStealthStatus();
|
||||
}
|
||||
|
||||
async function loadStealthStatus() {
|
||||
const mode = (await exec('cat ' + MODDIR + '/config/stealth_mode 2>/dev/null')).stdout.trim();
|
||||
if (mode) document.getElementById('stealthMode').value = mode;
|
||||
|
||||
const dot = document.getElementById('stealthDot');
|
||||
const status = document.getElementById('stealthStatus');
|
||||
|
||||
if (mode === 'full') {
|
||||
dot.className = 'dot';
|
||||
status.textContent = 'Full stealth active — logs disabled, processes masked, props hidden';
|
||||
} else if (mode && mode !== 'off') {
|
||||
dot.className = 'dot warn';
|
||||
status.textContent = 'Partial: ' + mode;
|
||||
} else {
|
||||
dot.className = 'dot off';
|
||||
status.textContent = 'Inactive';
|
||||
}
|
||||
|
||||
// MAC randomization status
|
||||
const wifiMac = (await exec('settings get global wifi_connected_mac_randomization_enabled 2>/dev/null')).stdout.trim();
|
||||
const btMac = (await exec('settings get global bluetooth_addr_randomization_enabled 2>/dev/null')).stdout.trim();
|
||||
const macEl = document.getElementById('macStatus');
|
||||
if (wifiMac === '1' && btMac === '1') {
|
||||
macEl.textContent = 'WiFi + BT';
|
||||
} else if (wifiMac === '1') {
|
||||
macEl.textContent = 'WiFi only';
|
||||
} else if (btMac === '1') {
|
||||
macEl.textContent = 'BT only';
|
||||
} else {
|
||||
macEl.textContent = 'off';
|
||||
}
|
||||
}
|
||||
|
||||
async function setMode(file, value) {
|
||||
log('Setting ' + file + ' = ' + value);
|
||||
await exec('echo "' + value + '" > ' + MODDIR + '/config/' + file);
|
||||
@@ -519,6 +676,8 @@
|
||||
await loadSdrInfo();
|
||||
await loadControllerInfo();
|
||||
await loadRtlStatus();
|
||||
await loadSpoofStatus();
|
||||
await loadStealthStatus();
|
||||
log('Done');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user