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:
298
scripts/driver_spoof.sh
Executable file
298
scripts/driver_spoof.sh
Executable file
@@ -0,0 +1,298 @@
|
||||
#!/system/bin/sh
|
||||
# Driver Spoofing System
|
||||
#
|
||||
# Makes Android think stock drivers are loaded while custom drivers
|
||||
# are actually running. Uses mount namespace isolation so:
|
||||
#
|
||||
# - Verification tools see: stock file (original hash, signature, SELinux context)
|
||||
# - Driver loader sees: custom file (our patched/modified driver)
|
||||
#
|
||||
# How it works:
|
||||
# 1. Stock driver stays at /vendor/lib64/... untouched (dm-verity happy)
|
||||
# 2. Custom driver lives in /data/adb/modules/driver-manager/drivers/
|
||||
# 3. We clone the stock file's metadata (timestamps, SELinux context, owner, perms)
|
||||
# onto the custom driver
|
||||
# 4. We bind-mount the custom driver over the stock path ONLY in the mount
|
||||
# namespace of the process that loads it (e.g. surfaceflinger, wpa_supplicant)
|
||||
# 5. All other processes (Play Integrity, banking apps, SafetyNet) see the
|
||||
# stock file at the original path with the original hash
|
||||
#
|
||||
# This is NOT file replacement. The stock file is never modified.
|
||||
# dm-verity remains intact. Verified boot passes.
|
||||
|
||||
MODDIR="/data/adb/modules/driver-manager"
|
||||
CONFDIR="$MODDIR/config"
|
||||
LOGFILE="$MODDIR/driver-manager.log"
|
||||
DRIVERDIR="$MODDIR/drivers"
|
||||
STOCKDIR="$MODDIR/drivers/.stock_meta"
|
||||
|
||||
mkdir -p "$DRIVERDIR" "$STOCKDIR"
|
||||
|
||||
mlog() {
|
||||
STEALTH=$(cat "$CONFDIR/stealth_mode" 2>/dev/null || echo "off")
|
||||
[ "$STEALTH" = "full" ] && return
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') [spoof] $1" >> "$LOGFILE"
|
||||
}
|
||||
|
||||
# =================================================================
|
||||
# Clone stock file metadata onto custom driver
|
||||
# =================================================================
|
||||
# Copies: SELinux context, ownership, permissions, timestamps
|
||||
# Does NOT copy file contents — that's the whole point
|
||||
clone_metadata() {
|
||||
STOCK_PATH="$1"
|
||||
CUSTOM_PATH="$2"
|
||||
|
||||
if [ ! -f "$STOCK_PATH" ] || [ ! -f "$CUSTOM_PATH" ]; then
|
||||
mlog "ERROR: clone_metadata missing file: $STOCK_PATH or $CUSTOM_PATH"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Save stock metadata for verification
|
||||
METAFILE="$STOCKDIR/$(echo "$STOCK_PATH" | tr '/' '_')"
|
||||
ls -laZ "$STOCK_PATH" > "$METAFILE" 2>/dev/null
|
||||
sha256sum "$STOCK_PATH" >> "$METAFILE" 2>/dev/null
|
||||
|
||||
# Clone SELinux context
|
||||
CONTEXT=$(ls -Z "$STOCK_PATH" 2>/dev/null | awk '{print $1}')
|
||||
if [ -n "$CONTEXT" ]; then
|
||||
chcon "$CONTEXT" "$CUSTOM_PATH" 2>/dev/null
|
||||
mlog "SELinux context: $CONTEXT -> $(basename "$CUSTOM_PATH")"
|
||||
fi
|
||||
|
||||
# Clone ownership
|
||||
OWNER=$(stat -c '%u:%g' "$STOCK_PATH" 2>/dev/null)
|
||||
if [ -n "$OWNER" ]; then
|
||||
chown "$OWNER" "$CUSTOM_PATH" 2>/dev/null
|
||||
fi
|
||||
|
||||
# Clone permissions
|
||||
PERMS=$(stat -c '%a' "$STOCK_PATH" 2>/dev/null)
|
||||
if [ -n "$PERMS" ]; then
|
||||
chmod "$PERMS" "$CUSTOM_PATH" 2>/dev/null
|
||||
fi
|
||||
|
||||
# Clone timestamps (access + modify)
|
||||
touch -r "$STOCK_PATH" "$CUSTOM_PATH" 2>/dev/null
|
||||
|
||||
mlog "Metadata cloned: $STOCK_PATH -> $CUSTOM_PATH"
|
||||
}
|
||||
|
||||
# =================================================================
|
||||
# Bind mount custom driver over stock path in a specific process
|
||||
# =================================================================
|
||||
# Uses nsenter to enter the target process's mount namespace
|
||||
# and bind-mount the custom file over the stock path.
|
||||
# Only that process (and its children) see the custom file.
|
||||
spoof_for_process() {
|
||||
PROCESS_NAME="$1"
|
||||
STOCK_PATH="$2"
|
||||
CUSTOM_PATH="$3"
|
||||
|
||||
# Find the PID of the target process
|
||||
PID=$(pidof "$PROCESS_NAME" 2>/dev/null)
|
||||
if [ -z "$PID" ]; then
|
||||
mlog "Process not running: $PROCESS_NAME"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Clone metadata first
|
||||
clone_metadata "$STOCK_PATH" "$CUSTOM_PATH"
|
||||
|
||||
# Enter the process's mount namespace and bind-mount
|
||||
nsenter -t "$PID" -m -- mount --bind "$CUSTOM_PATH" "$STOCK_PATH" 2>/dev/null
|
||||
RET=$?
|
||||
|
||||
if [ $RET -eq 0 ]; then
|
||||
mlog "Spoofed: $PROCESS_NAME (PID $PID) sees $CUSTOM_PATH at $STOCK_PATH"
|
||||
else
|
||||
mlog "nsenter failed for $PROCESS_NAME — falling back to global mount"
|
||||
# Fallback: global bind mount (less stealthy but works)
|
||||
mount --bind "$CUSTOM_PATH" "$STOCK_PATH" 2>/dev/null
|
||||
mlog "Global bind mount: $CUSTOM_PATH -> $STOCK_PATH"
|
||||
fi
|
||||
}
|
||||
|
||||
# =================================================================
|
||||
# Global spoof — bind mount for ALL processes
|
||||
# =================================================================
|
||||
# Less stealthy but simpler. Use when you don't care about
|
||||
# hiding from verification tools (e.g. custom ROM, no banking apps)
|
||||
spoof_global() {
|
||||
STOCK_PATH="$1"
|
||||
CUSTOM_PATH="$2"
|
||||
|
||||
clone_metadata "$STOCK_PATH" "$CUSTOM_PATH"
|
||||
mount --bind "$CUSTOM_PATH" "$STOCK_PATH" 2>/dev/null
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
mlog "Global spoof: $CUSTOM_PATH -> $STOCK_PATH"
|
||||
else
|
||||
mlog "ERROR: global mount failed for $STOCK_PATH"
|
||||
fi
|
||||
}
|
||||
|
||||
# =================================================================
|
||||
# Restore stock driver (unmount bind)
|
||||
# =================================================================
|
||||
restore_stock() {
|
||||
STOCK_PATH="$1"
|
||||
umount "$STOCK_PATH" 2>/dev/null
|
||||
mlog "Restored stock: $STOCK_PATH"
|
||||
}
|
||||
|
||||
# =================================================================
|
||||
# Verify spoof is active
|
||||
# =================================================================
|
||||
# Checks if the file at the stock path is actually our custom driver
|
||||
verify_spoof() {
|
||||
STOCK_PATH="$1"
|
||||
CUSTOM_PATH="$2"
|
||||
|
||||
STOCK_HASH=$(sha256sum "$STOCK_PATH" 2>/dev/null | awk '{print $1}')
|
||||
CUSTOM_HASH=$(sha256sum "$CUSTOM_PATH" 2>/dev/null | awk '{print $1}')
|
||||
|
||||
if [ "$STOCK_HASH" = "$CUSTOM_HASH" ]; then
|
||||
echo "ACTIVE — custom driver loaded at $STOCK_PATH"
|
||||
else
|
||||
echo "INACTIVE — stock driver at $STOCK_PATH"
|
||||
fi
|
||||
}
|
||||
|
||||
# =================================================================
|
||||
# Driver mapping configuration
|
||||
# =================================================================
|
||||
# Format: stock_path|custom_filename|target_process
|
||||
# Custom files go in /data/adb/modules/driver-manager/drivers/
|
||||
DRIVER_MAP="$CONFDIR/driver_map.conf"
|
||||
|
||||
load_driver_map() {
|
||||
if [ ! -f "$DRIVER_MAP" ]; then
|
||||
cat > "$DRIVER_MAP" << 'MAP'
|
||||
# Driver Spoof Map
|
||||
# Format: stock_path|custom_filename|target_process|spoof_type
|
||||
# spoof_type: process (per-process ns) or global (all processes)
|
||||
#
|
||||
# GPU — PowerVR DXT-48-1536
|
||||
# Place custom GPU driver as: drivers/libGLES_powervr_custom.so
|
||||
#/vendor/lib64/egl/libGLES_powervr.so|libGLES_powervr_custom.so|surfaceflinger|process
|
||||
#/vendor/lib64/libPVROCL.so|libPVROCL_custom.so|surfaceflinger|process
|
||||
#
|
||||
# WiFi — BCM4390 firmware
|
||||
# Place custom firmware as: drivers/fw_bcm4390_custom.bin
|
||||
#/vendor/firmware/fw_bcmdhd4390.bin|fw_bcm4390_custom.bin|wpa_supplicant|process
|
||||
#
|
||||
# Bluetooth — QCA firmware
|
||||
#/vendor/firmware/qca/nvm_00440200.bin|nvm_custom.bin|bluetooth|process
|
||||
#
|
||||
# Uncomment and edit lines above to activate spoofing for each driver.
|
||||
# The stock file is NEVER modified. Custom files must be placed in:
|
||||
# /data/adb/modules/driver-manager/drivers/
|
||||
MAP
|
||||
mlog "Created default driver map at $DRIVER_MAP"
|
||||
fi
|
||||
}
|
||||
|
||||
# =================================================================
|
||||
# Apply all configured spoofs
|
||||
# =================================================================
|
||||
apply_all() {
|
||||
load_driver_map
|
||||
|
||||
while IFS='|' read -r STOCK_PATH CUSTOM_FILE TARGET_PROC SPOOF_TYPE; do
|
||||
# Skip comments and empty lines
|
||||
case "$STOCK_PATH" in
|
||||
\#*|"") continue ;;
|
||||
esac
|
||||
|
||||
CUSTOM_PATH="$DRIVERDIR/$CUSTOM_FILE"
|
||||
|
||||
if [ ! -f "$CUSTOM_PATH" ]; then
|
||||
mlog "SKIP: custom driver not found: $CUSTOM_PATH"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ ! -f "$STOCK_PATH" ]; then
|
||||
mlog "SKIP: stock path not found: $STOCK_PATH"
|
||||
continue
|
||||
fi
|
||||
|
||||
case "$SPOOF_TYPE" in
|
||||
process)
|
||||
spoof_for_process "$TARGET_PROC" "$STOCK_PATH" "$CUSTOM_PATH"
|
||||
;;
|
||||
global)
|
||||
spoof_global "$STOCK_PATH" "$CUSTOM_PATH"
|
||||
;;
|
||||
*)
|
||||
mlog "Unknown spoof type: $SPOOF_TYPE for $STOCK_PATH"
|
||||
;;
|
||||
esac
|
||||
done < "$DRIVER_MAP"
|
||||
}
|
||||
|
||||
# =================================================================
|
||||
# Status — show all active spoofs
|
||||
# =================================================================
|
||||
show_status() {
|
||||
load_driver_map
|
||||
echo "=== Driver Spoof Status ==="
|
||||
|
||||
while IFS='|' read -r STOCK_PATH CUSTOM_FILE TARGET_PROC SPOOF_TYPE; do
|
||||
case "$STOCK_PATH" in
|
||||
\#*|"") continue ;;
|
||||
esac
|
||||
CUSTOM_PATH="$DRIVERDIR/$CUSTOM_FILE"
|
||||
STATUS=$(verify_spoof "$STOCK_PATH" "$CUSTOM_PATH")
|
||||
echo " $STOCK_PATH -> $CUSTOM_FILE [$TARGET_PROC] $STATUS"
|
||||
done < "$DRIVER_MAP"
|
||||
|
||||
echo ""
|
||||
echo "=== Mount binds ==="
|
||||
mount | grep "$DRIVERDIR" 2>/dev/null || echo " (none active)"
|
||||
}
|
||||
|
||||
# =================================================================
|
||||
# Main
|
||||
# =================================================================
|
||||
case "$1" in
|
||||
apply)
|
||||
apply_all
|
||||
;;
|
||||
restore)
|
||||
if [ -n "$2" ]; then
|
||||
restore_stock "$2"
|
||||
else
|
||||
# Restore all
|
||||
load_driver_map
|
||||
while IFS='|' read -r STOCK_PATH CUSTOM_FILE TARGET_PROC SPOOF_TYPE; do
|
||||
case "$STOCK_PATH" in
|
||||
\#*|"") continue ;;
|
||||
esac
|
||||
restore_stock "$STOCK_PATH"
|
||||
done < "$DRIVER_MAP"
|
||||
fi
|
||||
;;
|
||||
status)
|
||||
show_status
|
||||
;;
|
||||
clone)
|
||||
# Clone metadata only: driver_spoof.sh clone /vendor/path /custom/path
|
||||
clone_metadata "$2" "$3"
|
||||
;;
|
||||
verify)
|
||||
verify_spoof "$2" "$3"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: driver_spoof.sh {apply|restore|status|clone|verify}"
|
||||
echo ""
|
||||
echo " apply Apply all driver spoofs from driver_map.conf"
|
||||
echo " restore [path] Restore stock driver(s)"
|
||||
echo " status Show active spoofs"
|
||||
echo " clone src dst Clone file metadata (SELinux, perms, timestamps)"
|
||||
echo " verify stock cust Check if spoof is active"
|
||||
echo ""
|
||||
echo "Driver map: $DRIVER_MAP"
|
||||
echo "Custom drivers: $DRIVERDIR/"
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user