Files
driver-manager/scripts/boot_timing.sh

288 lines
9.7 KiB
Bash
Raw Normal View History

#!/system/bin/sh
# Boot Timing & Verification Evasion
#
# Controls WHEN custom drivers and modifications are applied relative
# to Android's verification checkpoints:
#
# 1. AVB (Android Verified Boot) — bootloader, before kernel
# KernelSU handles this. We don't touch partitions. PASS.
#
# 2. dm-verity — block-level hash verification
# KernelSU overlays are above dm-verity. Stock blocks untouched. PASS.
#
# 3. Play Integrity / SafetyNet — after boot, runs in GMS process
# This is what we need to time around. First check is ~10-30s
# after boot_completed. Periodic re-checks every few hours.
#
# 4. Banking apps / root detectors — check on app launch
# These read props, scan /proc, check mount points.
#
# Strategy:
# - post-fs-data: ONLY stock-safe props. No mods. No spoofs.
# - boot_completed: Wait for first PI attestation to finish
# - Apply mods AFTER attestation window closes
# - Run a watcher that detects PI re-checks and temporarily
# unmounts spoofs + restores stock props during the check
MODDIR="/data/adb/modules/driver-manager"
CONFDIR="$MODDIR/config"
LOGFILE="$MODDIR/driver-manager.log"
mlog() {
echo "$(date '+%Y-%m-%d %H:%M:%S') [boot_timing] $1" >> "$LOGFILE"
}
# =================================================================
# Phase 1: Detect when Play Integrity has completed first check
# =================================================================
# GMS runs attestation via com.google.android.gms.unstable
# DroidGuard collects device state in this window
# We watch for this process to start and finish
wait_for_pi_pass() {
mlog "Waiting for Play Integrity first attestation..."
# Wait for GMS to be fully running
TIMEOUT=120
ELAPSED=0
while [ $ELAPSED -lt $TIMEOUT ]; do
# Check if GMS unstable (DroidGuard) has started
GMS_PID=$(pidof com.google.android.gms.unstable 2>/dev/null)
if [ -n "$GMS_PID" ]; then
mlog "DroidGuard detected (PID $GMS_PID), waiting for completion..."
# Wait for the DroidGuard process to finish its attestation
# It typically runs for 5-15 seconds during initial check
DROID_WAIT=0
while [ $DROID_WAIT -lt 30 ]; do
sleep 1
DROID_WAIT=$((DROID_WAIT + 1))
# Check if it's still actively doing attestation
# DroidGuard CPU usage drops after attestation completes
if [ -d "/proc/$GMS_PID" ]; then
CPU=$(cat /proc/$GMS_PID/stat 2>/dev/null | awk '{print $14+$15}')
if [ -n "$CPU" ] && [ "$CPU" -lt 5 ] && [ $DROID_WAIT -gt 10 ]; then
mlog "DroidGuard idle after ${DROID_WAIT}s — attestation likely complete"
break
fi
else
mlog "DroidGuard process exited after ${DROID_WAIT}s"
break
fi
done
# Extra safety margin
sleep 5
mlog "PI attestation window closed"
return 0
fi
sleep 2
ELAPSED=$((ELAPSED + 2))
done
# If GMS never started (unlikely), just wait a safe fixed time
mlog "GMS not detected after ${TIMEOUT}s — using fixed delay"
sleep 30
return 0
}
# =================================================================
# Phase 2: Apply modifications after PI passes
# =================================================================
apply_after_pi() {
mlog "Applying modifications..."
# Apply driver spoofs
SPOOF_ENABLED=$(cat "$CONFDIR/spoof_enabled" 2>/dev/null || echo "0")
if [ "$SPOOF_ENABLED" = "1" ]; then
sh "$MODDIR/scripts/driver_spoof.sh" apply
mlog "Driver spoofs applied"
fi
# Set non-stock props that we held back during PI window
# These are the props that root detectors look for
resetprop input.gamepad.enabled true
resetprop persist.sys.usb.otg 1
mlog "All modifications applied"
}
# =================================================================
# Phase 3: PI Watcher — monitor for re-attestation and hide
# =================================================================
# Play Integrity can re-check periodically (every few hours) or
# when an app requests it (banking app launch, Google Pay, etc.)
# We watch for DroidGuard activity and temporarily go clean.
PI_WATCHER_PID=""
start_pi_watcher() {
mlog "Starting PI watcher daemon..."
(
while true; do
sleep 10
# Check if DroidGuard is doing a new attestation
GMS_PID=$(pidof com.google.android.gms.unstable 2>/dev/null)
if [ -z "$GMS_PID" ]; then
continue
fi
# Check if it's actively using CPU (attestation in progress)
CPU=$(cat /proc/$GMS_PID/stat 2>/dev/null | awk '{print $14+$15}')
PREV_CPU="$CPU"
sleep 2
CPU2=$(cat /proc/$GMS_PID/stat 2>/dev/null | awk '{print $14+$15}')
if [ -n "$CPU" ] && [ -n "$CPU2" ]; then
DELTA=$((CPU2 - CPU))
if [ "$DELTA" -gt 10 ]; then
# DroidGuard is active — temporarily hide
mlog "PI re-check detected! Temporarily restoring stock..."
hide_for_pi
fi
fi
done
) &
PI_WATCHER_PID=$!
echo "$PI_WATCHER_PID" > "$MODDIR/run/pi_watcher.pid"
mlog "PI watcher started (PID $PI_WATCHER_PID)"
}
hide_for_pi() {
# Temporarily unmount all driver spoofs
sh "$MODDIR/scripts/driver_spoof.sh" restore 2>/dev/null
# Remove non-stock props
resetprop --delete input.gamepad.enabled 2>/dev/null
resetprop --delete persist.sys.usb.otg 2>/dev/null
resetprop --delete vendor.powervr.opencl.allowfp16 2>/dev/null
resetprop --delete vendor.powervr.opencl.profiling 2>/dev/null
resetprop --delete bluetooth.le.no_location_permission_scan 2>/dev/null
# Ensure boot state looks clean
resetprop ro.boot.verifiedbootstate green 2>/dev/null
resetprop ro.boot.flash.locked 1 2>/dev/null
resetprop ro.boot.vbmeta.device_state locked 2>/dev/null
mlog "Hiding for PI check..."
# Wait for DroidGuard to finish
WAIT=0
while [ $WAIT -lt 60 ]; do
sleep 2
WAIT=$((WAIT + 2))
GMS_PID=$(pidof com.google.android.gms.unstable 2>/dev/null)
if [ -z "$GMS_PID" ]; then
break
fi
CPU=$(cat /proc/$GMS_PID/stat 2>/dev/null | awk '{print $14+$15}')
sleep 1
CPU2=$(cat /proc/$GMS_PID/stat 2>/dev/null | awk '{print $14+$15}')
DELTA=$((CPU2 - CPU))
if [ "$DELTA" -lt 5 ]; then
break
fi
done
# Extra safety margin
sleep 5
mlog "PI check finished, re-applying modifications..."
apply_after_pi
}
# =================================================================
# Boot prop spoofing — make boot state look locked/verified
# =================================================================
spoof_boot_props() {
# These props are checked by Play Integrity and root detectors
# They should reflect a locked, verified device
# Verified boot state
resetprop ro.boot.verifiedbootstate green
resetprop ro.boot.flash.locked 1
resetprop ro.boot.vbmeta.device_state locked
resetprop ro.boot.veritymode enforcing
# Remove KernelSU traces from props
resetprop --delete ro.kernelsu.version 2>/dev/null
resetprop --delete ro.kernelsu.versionCode 2>/dev/null
# Stock build fingerprint (don't modify — just ensure it's not overridden)
# resetprop ro.build.fingerprint should already be stock
# Ensure SELinux appears enforcing
resetprop ro.build.selinux 1
mlog "Boot props spoofed (green/locked/enforcing)"
}
# =================================================================
# Main entry point — called from service.sh
# =================================================================
case "$1" in
run)
# Full boot timing sequence
spoof_boot_props
wait_for_pi_pass
apply_after_pi
start_pi_watcher
mlog "Boot timing sequence complete"
;;
hide)
# Manual hide trigger
hide_for_pi
;;
unhide)
# Manual re-apply
apply_after_pi
;;
stop)
# Stop PI watcher
PID=$(cat "$MODDIR/run/pi_watcher.pid" 2>/dev/null)
if [ -n "$PID" ]; then
kill "$PID" 2>/dev/null
rm -f "$MODDIR/run/pi_watcher.pid"
mlog "PI watcher stopped"
fi
;;
status)
PID=$(cat "$MODDIR/run/pi_watcher.pid" 2>/dev/null)
if [ -n "$PID" ] && kill -0 "$PID" 2>/dev/null; then
echo "PI watcher: running (PID $PID)"
else
echo "PI watcher: not running"
fi
# Check boot props
echo "Boot state: $(getprop ro.boot.verifiedbootstate)"
echo "Flash lock: $(getprop ro.boot.flash.locked)"
echo "VBMeta: $(getprop ro.boot.vbmeta.device_state)"
echo "SELinux: $(getenforce 2>/dev/null || echo unknown)"
# Check for KSU prop leaks
KSU_VER=$(getprop ro.kernelsu.version 2>/dev/null)
if [ -n "$KSU_VER" ]; then
echo "WARNING: KernelSU version visible: $KSU_VER"
else
echo "KernelSU props: hidden"
fi
;;
*)
echo "Usage: boot_timing.sh {run|hide|unhide|stop|status}"
echo ""
echo " run Full boot sequence (wait for PI, apply mods, start watcher)"
echo " hide Temporarily hide all mods (for manual PI trigger)"
echo " unhide Re-apply all mods"
echo " stop Stop PI watcher daemon"
echo " status Show current state"
;;
esac