#!/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() { STEALTH=$(cat "$CONFDIR/stealth_mode" 2>/dev/null || echo "off") [ "$STEALTH" = "full" ] && return 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 # Apply stealth STEALTH_MODE=$(cat "$CONFDIR/stealth_mode" 2>/dev/null || echo "off") if [ "$STEALTH_MODE" != "off" ]; then mlog "Stealth mode active: $STEALTH_MODE" 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