v0.2.0: Deep forensic scanner, honeypots, duress system, anti-forensics hardening

New modules:
- Deep forensic scanner (MVT-style): background + on-demand full analysis
  SMS/call log/browser/dumpsys/battery/cert store/logcat/data usage
- Anti-forensics hardening: 15 measures (USB, ADB, logging, memory, TRIM)
- Duress/panic trigger: power button sequence, duress PIN, CLI panic
- SMS honeypot: fake GPS location spoofing on silent SMS detection
- App permissions honeypot: audit dangerous combos, revoke, sandbox,
  feed fake data to spyware apps
- IOC auto-updater: scheduled updates from backend or git sources (WIP)

Fixes:
- Removed SKIPUNZIP=1 (fixes module.prop OS error 2)
- Deferred FrostGuard baseline to first boot (no more install hang)
- Added volume key selection for FrostGuard and initial scan during install
This commit is contained in:
sssnake
2026-03-31 07:19:36 -07:00
parent cf00838b6d
commit 58aa5d6fe6
11 changed files with 2394 additions and 54 deletions

View File

@@ -3,7 +3,41 @@
# KernelSU-Next Module Installation Script # KernelSU-Next Module Installation Script
# (c) Setec Labs # (c) Setec Labs
SKIPUNZIP=1 # Let KernelSU/Magisk handle extraction (MODPATH is set by the framework)
# ── Volume key selector ──
# Reads volume key press: returns 0 for Vol+, 1 for Vol-
# Timeout returns the default ($1: 0=yes, 1=no)
keycheck() {
local default="${1:-0}"
local timeout="${2:-5}"
local start=$(date +%s)
# Find input devices for volume keys
local KEYCHECK=""
for d in /dev/input/event*; do
[ -e "$d" ] && KEYCHECK="$d"
done
while true; do
local now=$(date +%s)
local elapsed=$((now - start))
local remaining=$((timeout - elapsed))
if [ $remaining -le 0 ]; then
return $default
fi
# Try to read a key event with timeout
local key=$(timeout 1 getevent -lc 1 2>/dev/null | grep -oE 'KEY_VOLUME(UP|DOWN)' | head -1)
if [ "$key" = "KEY_VOLUMEUP" ]; then
return 0
elif [ "$key" = "KEY_VOLUMEDOWN" ]; then
return 1
fi
done
}
ui_print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" ui_print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
ui_print " Vigil — Anti-Surveillance Shield v0.1.0" ui_print " Vigil — Anti-Surveillance Shield v0.1.0"
@@ -14,13 +48,10 @@ ui_print ""
# Detect environment # Detect environment
if [ "$KSU" = "true" ]; then if [ "$KSU" = "true" ]; then
ui_print "[*] KernelSU detected (version: $KSU_VER_CODE)" ui_print "[*] KernelSU detected (version: $KSU_VER_CODE)"
MODPATH="/data/adb/modules/vigil"
elif [ "$APATCH" = "true" ]; then elif [ "$APATCH" = "true" ]; then
ui_print "[*] APatch detected" ui_print "[*] APatch detected"
MODPATH="/data/adb/modules/vigil"
else else
ui_print "[*] Magisk detected (version: $MAGISK_VER_CODE)" ui_print "[*] Magisk detected (version: $MAGISK_VER_CODE)"
MODPATH="/data/adb/modules/vigil"
fi fi
# Check Android version # Check Android version
@@ -35,14 +66,8 @@ ui_print "[*] Android API: $API"
ARCH=$(getprop ro.product.cpu.abi) ARCH=$(getprop ro.product.cpu.abi)
ui_print "[*] Architecture: $ARCH" ui_print "[*] Architecture: $ARCH"
# Extract module files # Set permissions on executables
ui_print "[*] Extracting module files..."
mkdir -p "$MODPATH"
unzip -o "$ZIPFILE" -d "$MODPATH" >&2
# Set permissions
ui_print "[*] Setting permissions..." ui_print "[*] Setting permissions..."
set_perm_recursive "$MODPATH" 0 0 0755 0644
set_perm_recursive "$MODPATH/vigil/bin" 0 0 0755 0755 set_perm_recursive "$MODPATH/vigil/bin" 0 0 0755 0755
set_perm_recursive "$MODPATH/vigil/lib" 0 0 0755 0755 set_perm_recursive "$MODPATH/vigil/lib" 0 0 0755 0755
@@ -64,9 +89,66 @@ fi
ui_print "[*] Installing threat indicator database..." ui_print "[*] Installing threat indicator database..."
cp -r "$MODPATH/vigil/ioc/"* /data/adb/vigil/ 2>/dev/null cp -r "$MODPATH/vigil/ioc/"* /data/adb/vigil/ 2>/dev/null
# Generate initial file integrity baseline # ── FrostGuard: File Integrity Selection ──
ui_print "[*] Generating file integrity baseline..." ui_print ""
"$MODPATH/vigil/lib/integrity.sh" baseline 2>/dev/null ui_print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
ui_print " FrostGuard — File Integrity Monitor"
ui_print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
ui_print ""
ui_print " FrostGuard hashes all system files to"
ui_print " detect unauthorized modifications."
ui_print ""
ui_print " WARNING: This can take 5-10 minutes on"
ui_print " first boot while it builds the baseline."
ui_print ""
ui_print " Vol UP = ENABLE (recommended)"
ui_print " Vol DOWN = DISABLE"
ui_print ""
ui_print -n " Waiting 5 seconds... "
keycheck 0 5
if [ $? -eq 0 ]; then
ui_print "ENABLED"
touch /data/adb/vigil/.needs_baseline
sed -i 's/^FROSTGUARD_ENABLED=.*/FROSTGUARD_ENABLED=1/' /data/adb/vigil/vigil.conf 2>/dev/null
ui_print "[*] Baseline will generate on first boot (5-10 min)"
else
ui_print "DISABLED"
rm -f /data/adb/vigil/.needs_baseline
sed -i 's/^FROSTGUARD_ENABLED=.*/FROSTGUARD_ENABLED=0/' /data/adb/vigil/vigil.conf 2>/dev/null
ui_print "[*] FrostGuard disabled — enable later with vigil.conf"
fi
# ── Threat Scan Selection ──
ui_print ""
ui_print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
ui_print " Initial Threat Scan"
ui_print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
ui_print ""
ui_print " Scan installed apps against 11,000+"
ui_print " threat indicators (stalkerware, spyware,"
ui_print " Pegasus, government surveillance tools)."
ui_print ""
ui_print " Vol UP = SCAN NOW (during install)"
ui_print " Vol DOWN = SCAN ON NEXT BOOT"
ui_print ""
ui_print -n " Waiting 5 seconds... "
keycheck 1 5
if [ $? -eq 0 ]; then
ui_print "SCANNING NOW"
ui_print ""
ui_print "[*] Running threat scan..."
# Quick scan: packages + processes (fastest useful scan)
VIGIL_DATA="/data/adb/vigil" "$MODPATH/vigil/lib/scanner.sh" quick 2>/dev/null | while read -r line; do
ui_print " $line"
done
ui_print "[*] Scan complete"
else
ui_print "DEFERRED TO BOOT"
touch /data/adb/vigil/.needs_scan
ui_print "[*] Scan will run automatically on next boot"
fi
ui_print "" ui_print ""
ui_print "[✓] Vigil installed successfully." ui_print "[✓] Vigil installed successfully."

View File

@@ -36,6 +36,26 @@ WRAPPER
chmod 755 /data/local/tmp/vigil chmod 755 /data/local/tmp/vigil
} }
# Generate file integrity baseline if needed (deferred from install)
if [ -f "$VIGIL_DATA/.needs_baseline" ]; then
log_vigil "Generating file integrity baseline in background..."
(
"$MODDIR/vigil/lib/integrity.sh" baseline >> "$VIGIL_LOG" 2>&1
rm -f "$VIGIL_DATA/.needs_baseline"
log_vigil "File integrity baseline complete"
) &
fi
# Run deferred threat scan if requested during install
if [ -f "$VIGIL_DATA/.needs_scan" ]; then
log_vigil "Running deferred threat scan in background..."
(
"$MODDIR/vigil/lib/scanner.sh" quick >> "$VIGIL_LOG" 2>&1
rm -f "$VIGIL_DATA/.needs_scan"
log_vigil "Deferred threat scan complete"
) &
fi
# Start the main daemon # Start the main daemon
log_vigil "Starting vigild daemon" log_vigil "Starting vigild daemon"
nohup "$VIGIL_BIN/vigild" >> "$VIGIL_LOG" 2>&1 & nohup "$VIGIL_BIN/vigild" >> "$VIGIL_LOG" 2>&1 &

View File

@@ -186,29 +186,7 @@ cmd_alerts() {
cmd_update_ioc() { cmd_update_ioc() {
check_module check_module
echo "Updating threat indicators..." "$VIGIL_LIB/ioc_updater.sh" update
if [ -n "$VIGIL_BACKEND_URL" ]; then
# Download from backend
for f in packages.txt certificates.txt domains.txt ips.txt hashes.txt hosts.txt cellebrite_hashes.txt; do
echo -n " $f... "
if curl -sf -o "$VIGIL_DATA/$f.new" "$VIGIL_BACKEND_URL/ioc/$f"; then
mv "$VIGIL_DATA/$f.new" "$VIGIL_DATA/$f"
echo "${GREEN}updated${NC}"
else
rm -f "$VIGIL_DATA/$f.new"
echo "${YELLOW}failed (keeping current)${NC}"
fi
done
# Reinstall hosts blocklist
"$VIGIL_LIB/network_monitor.sh" install
echo "IOC update complete"
else
echo "${YELLOW}No backend URL configured${NC}"
echo "Set VIGIL_BACKEND_URL in /data/adb/vigil/vigil.conf"
echo "Or manually update files in /data/adb/vigil/"
fi
} }
cmd_forensic() { cmd_forensic() {
@@ -243,6 +221,47 @@ cmd_wipe_session() {
"$VIGIL_LIB/key_wiper.sh" wipe-session "$VIGIL_LIB/key_wiper.sh" wipe-session
} }
cmd_deep_scan() {
check_module
"$VIGIL_LIB/deep_scan.sh" deep
}
cmd_harden() {
check_module
local subcmd="${1:-harden}"
"$VIGIL_LIB/antiforensics.sh" "$subcmd"
}
cmd_duress() {
check_module
local subcmd="${1:-status}"
"$VIGIL_LIB/duress.sh" "$subcmd"
}
cmd_panic() {
check_module
"$VIGIL_LIB/duress.sh" panic
}
cmd_honeypot() {
check_module
local subcmd="${1:-status}"
shift 2>/dev/null
"$VIGIL_LIB/sms_honeypot.sh" "$subcmd" "$@"
}
cmd_app_honeypot() {
check_module
local subcmd="${1:-audit}"
shift 2>/dev/null
"$VIGIL_LIB/app_honeypot.sh" "$subcmd" "$@"
}
cmd_sanitize() {
check_module
"$VIGIL_LIB/antiforensics.sh" sanitize
}
cmd_help() { cmd_help() {
print_banner print_banner
echo "Usage: vigil <command> [options]" echo "Usage: vigil <command> [options]"
@@ -250,13 +269,17 @@ cmd_help() {
echo "${BOLD}Core Commands${NC}" echo "${BOLD}Core Commands${NC}"
echo " status Show overall protection status" echo " status Show overall protection status"
echo " scan [full|quick] Run threat scan (default: full)" echo " scan [full|quick] Run threat scan (default: full)"
echo " deep-scan Full forensic analysis (MVT-style)"
echo " alerts [N] Show last N alerts (default: 20)" echo " alerts [N] Show last N alerts (default: 20)"
echo " log [N] Show last N log lines (default: 50)" echo " log [N] Show last N log lines (default: 50)"
echo "" echo ""
echo "${BOLD}Protection${NC}" echo "${BOLD}Protection${NC}"
echo " lockdown [-f] Enter BFU lockdown mode (evict keys, disable ADB)" echo " lockdown [-f] Enter BFU lockdown mode (evict keys, disable ADB)"
echo " panic Immediate duress action (no confirmation)"
echo " unlock Clear lockdown state (after reboot)" echo " unlock Clear lockdown state (after reboot)"
echo " wipe-session Clear session data (clipboard, caches)" echo " wipe-session Clear session data (clipboard, caches)"
echo " harden [audit] Apply anti-forensics hardening (or audit)"
echo " sanitize Clean forensic artifacts from device"
echo "" echo ""
echo "${BOLD}Modules${NC}" echo "${BOLD}Modules${NC}"
echo " integrity [baseline|verify|heuristic]" echo " integrity [baseline|verify|heuristic]"
@@ -265,8 +288,14 @@ cmd_help() {
echo " Forensic Shield (anti-Cellebrite)" echo " Forensic Shield (anti-Cellebrite)"
echo " sms [monitor|analyze|status]" echo " sms [monitor|analyze|status]"
echo " SMS Shield (silent SMS detection)" echo " SMS Shield (silent SMS detection)"
echo " honeypot [monitor|spoof|spoof-at|stop|status]"
echo " SMS Honeypot (fake GPS on silent SMS)"
echo " app [audit|revoke|sandbox|feed|auto|status]"
echo " App Permissions Honeypot (data redirect)"
echo " network [install|remove|status]" echo " network [install|remove|status]"
echo " Network monitor (C2/tracker blocking)" echo " Network monitor (C2/tracker blocking)"
echo " duress [setup|status]"
echo " Duress/panic trigger configuration"
echo "" echo ""
echo "${BOLD}Maintenance${NC}" echo "${BOLD}Maintenance${NC}"
echo " update-ioc Update threat indicator database" echo " update-ioc Update threat indicator database"
@@ -282,15 +311,22 @@ check_root
case "$1" in case "$1" in
status) cmd_status ;; status) cmd_status ;;
scan) shift; cmd_scan "$@" ;; scan) shift; cmd_scan "$@" ;;
deep-scan) cmd_deep_scan ;;
integrity) shift; cmd_integrity "$@" ;; integrity) shift; cmd_integrity "$@" ;;
lockdown) shift; cmd_lockdown "$@" ;; lockdown) shift; cmd_lockdown "$@" ;;
panic) cmd_panic ;;
unlock) cmd_unlock ;; unlock) cmd_unlock ;;
wipe-session) cmd_wipe_session ;; wipe-session) cmd_wipe_session ;;
harden) shift; cmd_harden "$@" ;;
sanitize) cmd_sanitize ;;
alerts) shift; cmd_alerts "$@" ;; alerts) shift; cmd_alerts "$@" ;;
update-ioc) cmd_update_ioc ;; update-ioc) cmd_update_ioc ;;
forensic) shift; cmd_forensic "$@" ;; forensic) shift; cmd_forensic "$@" ;;
sms) shift; cmd_sms "$@" ;; sms) shift; cmd_sms "$@" ;;
honeypot) shift; cmd_honeypot "$@" ;;
app) shift; cmd_app_honeypot "$@" ;;
network) shift; cmd_network "$@" ;; network) shift; cmd_network "$@" ;;
duress) shift; cmd_duress "$@" ;;
log) shift; cmd_log "$@" ;; log) shift; cmd_log "$@" ;;
version) echo "Vigil v${VERSION}" ;; version) echo "Vigil v${VERSION}" ;;
help|--help|-h|"") cmd_help ;; help|--help|-h|"") cmd_help ;;

View File

@@ -133,17 +133,52 @@ main() {
"$VIGIL_LIB/network_monitor.sh" install >> "$VIGIL_LOG" 2>&1 "$VIGIL_LIB/network_monitor.sh" install >> "$VIGIL_LOG" 2>&1
fi fi
# 5. Run initial scan # 5. Deep scan background monitor (low-priority forensic analysis)
if [ "${DEEP_SCAN_BACKGROUND:-1}" = "1" ]; then
log INFO "Starting deep scan background monitor..."
"$VIGIL_LIB/deep_scan.sh" background >> "$VIGIL_LOG" 2>&1 &
log INFO "Deep Scan Background PID: $!"
fi
# 6. SMS Honeypot (fake location on silent SMS)
if [ "${SMS_FAKE_RESPONSE:-0}" = "1" ]; then
log INFO "Starting SMS Honeypot monitor..."
"$VIGIL_LIB/sms_honeypot.sh" monitor >> "$VIGIL_LOG" 2>&1 &
log INFO "SMS Honeypot PID: $!"
fi
# 7. Duress trigger monitors (power button + PIN)
if [ "${DURESS_ENABLED:-0}" = "1" ]; then
log INFO "Starting Duress monitors..."
"$VIGIL_LIB/duress.sh" monitor >> "$VIGIL_LOG" 2>&1 &
log INFO "Duress Monitor PID: $!"
fi
# 8. Apply anti-forensics hardening on boot
if [ "${ANTIFORENSICS_ENABLED:-1}" = "1" ]; then
log INFO "Applying anti-forensics hardening..."
"$VIGIL_LIB/antiforensics.sh" harden >> "$VIGIL_LOG" 2>&1
fi
# 9. Install network blocklists
if [ "${NETWORK_BLOCK_C2:-1}" = "1" ] || [ "${NETWORK_BLOCK_TRACKERS:-1}" = "1" ]; then
log INFO "Installing network blocklists..."
"$VIGIL_LIB/network_monitor.sh" install >> "$VIGIL_LOG" 2>&1
fi
# 10. Run initial quick scan
log INFO "Running initial quick scan..." log INFO "Running initial quick scan..."
"$VIGIL_LIB/scanner.sh" quick >> "$VIGIL_LOG" 2>&1 "$VIGIL_LIB/scanner.sh" quick >> "$VIGIL_LOG" 2>&1
# ── Main loop ── # ── Main loop ──
local last_scan=$(date +%s) local last_scan=$(date +%s)
local last_integrity=$(date +%s) local last_integrity=$(date +%s)
local last_ioc_update=$(date +%s)
local scan_interval="${SCANNER_INTERVAL:-3600}" local scan_interval="${SCANNER_INTERVAL:-3600}"
local integrity_interval="${FROSTGUARD_INTERVAL:-1800}" local integrity_interval="${FROSTGUARD_INTERVAL:-1800}"
local ioc_update_interval="${IOC_UPDATE_INTERVAL:-86400}"
log INFO "Entering main loop (scan: ${scan_interval}s, integrity: ${integrity_interval}s)" log INFO "Entering main loop (scan: ${scan_interval}s, integrity: ${integrity_interval}s, ioc: ${ioc_update_interval}s)"
while true; do while true; do
local now=$(date +%s) local now=$(date +%s)
@@ -162,6 +197,13 @@ main() {
last_integrity=$now last_integrity=$now
fi fi
# Periodic IOC auto-update
if [ $((now - last_ioc_update)) -ge "$ioc_update_interval" ]; then
log INFO "Checking for IOC updates..."
"$VIGIL_LIB/ioc_updater.sh" auto >> "$VIGIL_LOG" 2>&1
last_ioc_update=$now
fi
# Process any pending alerts # Process any pending alerts
process_alerts process_alerts

View File

@@ -60,4 +60,26 @@ NETWORK_IPTABLES_ENABLED=1 # Use iptables for IP-level blocking
# ── Duress / Panic ────────────────────────────────── # ── Duress / Panic ──────────────────────────────────
DURESS_ENABLED=0 # DISABLED by default — user must opt in DURESS_ENABLED=0 # DISABLED by default — user must opt in
DURESS_PIN="" # Duress PIN triggers emergency lockdown DURESS_PIN="" # Duress PIN triggers emergency lockdown
DURESS_ACTION="lockdown" # lockdown | wipe | wipe-full DURESS_ACTION="lockdown" # lockdown | wipe-session | wipe
# ── Deep Forensic Scanner ───────────────────────────
DEEP_SCAN_BACKGROUND=1 # Background forensic monitoring (low CPU)
DEEP_SCAN_INTERVAL=600 # Seconds between background analysis cycles
# ── Anti-Forensics Hardening ────────────────────────
ANTIFORENSICS_ENABLED=1 # Apply hardening measures on boot
ANTIFORENSICS_SANITIZE_ON_LOCK=0 # Auto-sanitize when screen locks
# ── SMS Honeypot ────────────────────────────────────
SMS_FAKE_RESPONSE=0 # DISABLED by default — user must opt in
# Set custom fake location in /data/adb/vigil/honeypot.conf:
# FAKE_LAT=48.8566
# FAKE_LON=2.3522
# ── App Honeypot ────────────────────────────────────
APP_HONEYPOT_AUTO=0 # Auto-honeypot detected threats (0=manual)
# ── IOC Auto-Updater ───────────────────────────────
IOC_UPDATE_INTERVAL=86400 # Seconds between auto-updates (86400=24hr)
VIGIL_API_KEY="" # Autarch API key for backend updates
VIGIL_BACKEND_URL="" # Autarch backend URL

273
vigil/lib/antiforensics.sh Executable file
View File

@@ -0,0 +1,273 @@
#!/system/bin/sh
# Vigil — Anti-Forensics Hardening (2025/2026)
# General device hardening beyond Cellebrite-specific detection
# (c) Setec Labs
#
# This module implements modern anti-forensics techniques that make
# the device resistant to ALL forensic extraction tools, not just Cellebrite.
# Based on research from Android-AntiForensic-Tools, lockup, and 2025/2026
# Android security patches.
#
# Techniques:
# 1. AFU→BFU hardening (encryption key lifecycle management)
# 2. Memory protection (reduce data in RAM)
# 3. Log sanitization (minimize forensic artifacts)
# 4. USB attack surface reduction
# 5. Screen capture / overlay protection
# 6. Backup extraction prevention
# 7. ADB attack surface minimization
# 8. Secure deletion with TRIM
# 9. Bootloader/recovery protection
# 10. Developer option lockdown
VIGIL_DATA="/data/adb/vigil"
VIGIL_LOG="$VIGIL_DATA/vigil.log"
ALERT_DIR="$VIGIL_DATA/alerts"
[ -f "$VIGIL_DATA/vigil.conf" ] && . "$VIGIL_DATA/vigil.conf"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [antiforensics] $1" >> "$VIGIL_LOG"
}
alert() {
local severity="$1"
local message="$2"
local timestamp=$(date +%s)
echo "${severity}|${timestamp}|antiforensics|${message}" >> "$ALERT_DIR/pending"
log "ALERT [$severity]: $message"
}
# ── HARDEN: Apply all anti-forensics hardening ──
cmd_harden() {
log "Applying anti-forensics hardening..."
echo "Vigil Anti-Forensics Hardening"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
local applied=0
# 1. Disable ADB over network (WiFi debugging)
echo -n " [1] Disable ADB over WiFi... "
settings put global adb_wifi_enabled 0 2>/dev/null
setprop service.adb.tcp.port -1 2>/dev/null
echo "done"
applied=$((applied + 1))
# 2. Disable USB debugging when locked
echo -n " [2] USB debug only when unlocked... "
settings put global adb_allowed_connection_time 0 2>/dev/null
echo "done"
applied=$((applied + 1))
# 3. Restrict USB modes — charge only by default
echo -n " [3] USB default to charge-only... "
settings put global usb_mass_storage_enabled 0 2>/dev/null
echo "done"
applied=$((applied + 1))
# 4. Disable backup transport (prevents adb backup extraction)
echo -n " [4] Disable ADB backup... "
settings put secure backup_enabled 0 2>/dev/null
settings put secure backup_transport "" 2>/dev/null
echo "done"
applied=$((applied + 1))
# 5. Minimize clipboard retention
echo -n " [5] Clear clipboard on lock... "
# This is enforced by vigild on screen-off events
settings put secure clipboard_timeout 60000 2>/dev/null # 1 min timeout
echo "done"
applied=$((applied + 1))
# 6. Reduce logcat buffer sizes (less forensic data in memory)
echo -n " [6] Minimize log buffers... "
setprop persist.logd.size 65536 2>/dev/null # 64KB (default is 256KB)
setprop persist.logd.size.main 65536 2>/dev/null
setprop persist.logd.size.system 65536 2>/dev/null
setprop persist.logd.size.crash 32768 2>/dev/null
echo "done"
applied=$((applied + 1))
# 7. Disable persistent logging
echo -n " [7] Disable persistent logs... "
setprop persist.logd.logpersistd "" 2>/dev/null
setprop persist.logd.logpersistd.buffer "" 2>/dev/null
echo "done"
applied=$((applied + 1))
# 8. Block safe mode boot (prevents disabling root/modules)
echo -n " [8] Block safe mode boot... "
settings put global safe_boot_disallowed 1 2>/dev/null
echo "done"
applied=$((applied + 1))
# 9. Disable developer options visibility
echo -n " [9] Hide developer options... "
settings put global development_settings_enabled 0 2>/dev/null
echo "done"
applied=$((applied + 1))
# 10. Reduce crash dump data
echo -n " [10] Minimize crash dumps... "
setprop persist.sys.dalvik.vm.heapdumppath "" 2>/dev/null
setprop dalvik.vm.minidump false 2>/dev/null
echo "done"
applied=$((applied + 1))
# 11. Disable screenshot/screen recording via flag
echo -n " [11] Set secure screen flag... "
# Note: This requires per-app FLAG_SECURE, we set the system default
settings put secure screencapture_disabled 1 2>/dev/null
echo "done"
applied=$((applied + 1))
# 12. Aggressive memory management (drop decrypted data faster)
echo -n " [12] Aggressive memory reclaim... "
echo 1 > /proc/sys/vm/compact_memory 2>/dev/null
echo 100 > /proc/sys/vm/swappiness 2>/dev/null # Prefer swap over keeping in RAM
echo "done"
applied=$((applied + 1))
# 13. Disable OEM unlocking (prevent bootloader re-unlock)
echo -n " [13] Disable OEM unlocking... "
settings put global oem_unlock_allowed 0 2>/dev/null
echo "done"
applied=$((applied + 1))
# 14. Restrict content provider access
echo -n " [14] Restrict content providers... "
# Disable external content provider access for sensitive providers
settings put secure content_capture_enabled 0 2>/dev/null
echo "done"
applied=$((applied + 1))
# 15. TRIM all filesystems
echo -n " [15] TRIM filesystems... "
fstrim /data 2>/dev/null &
fstrim /cache 2>/dev/null &
sm fstrim 2>/dev/null &
echo "done (background)"
applied=$((applied + 1))
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Applied $applied hardening measures"
echo ""
log "Anti-forensics hardening applied: $applied measures"
}
# ── AUDIT: Check current hardening state ──
cmd_audit() {
echo "Anti-Forensics Hardening Audit"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
local issues=0
# Check each setting
local adb_wifi=$(settings get global adb_wifi_enabled 2>/dev/null)
echo -n " ADB over WiFi: "
if [ "$adb_wifi" = "1" ]; then echo "ENABLED ⚠"; issues=$((issues+1)); else echo "disabled ✓"; fi
local adb_enabled=$(settings get global adb_enabled 2>/dev/null)
echo -n " ADB debugging: "
if [ "$adb_enabled" = "1" ]; then echo "ENABLED ⚠"; issues=$((issues+1)); else echo "disabled ✓"; fi
local backup=$(settings get secure backup_enabled 2>/dev/null)
echo -n " ADB backup: "
if [ "$backup" = "1" ]; then echo "ENABLED ⚠"; issues=$((issues+1)); else echo "disabled ✓"; fi
local dev_opts=$(settings get global development_settings_enabled 2>/dev/null)
echo -n " Developer options: "
if [ "$dev_opts" = "1" ]; then echo "VISIBLE ⚠"; issues=$((issues+1)); else echo "hidden ✓"; fi
local safe_boot=$(settings get global safe_boot_disallowed 2>/dev/null)
echo -n " Safe mode blocked: "
if [ "$safe_boot" = "1" ]; then echo "yes ✓"; else echo "NO ⚠"; issues=$((issues+1)); fi
local oem_unlock=$(settings get global oem_unlock_allowed 2>/dev/null)
echo -n " OEM unlock: "
if [ "$oem_unlock" = "1" ]; then echo "ALLOWED ⚠"; issues=$((issues+1)); else echo "blocked ✓"; fi
local selinux=$(getenforce 2>/dev/null)
echo -n " SELinux: "
if [ "$selinux" = "Enforcing" ]; then echo "enforcing ✓"; else echo "$selinux"; issues=$((issues+1)); fi
local logd_size=$(getprop persist.logd.size 2>/dev/null)
echo -n " Log buffer size: "
if [ "${logd_size:-262144}" -le 65536 ]; then echo "minimal ✓"; else echo "${logd_size} bytes ⚠"; issues=$((issues+1)); fi
local log_persist=$(getprop persist.logd.logpersistd 2>/dev/null)
echo -n " Persistent logging: "
if [ -z "$log_persist" ]; then echo "disabled ✓"; else echo "ENABLED ⚠"; issues=$((issues+1)); fi
local screen_cap=$(settings get secure screencapture_disabled 2>/dev/null)
echo -n " Screenshot protect: "
if [ "$screen_cap" = "1" ]; then echo "yes ✓"; else echo "NO ⚠"; issues=$((issues+1)); fi
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
if [ $issues -gt 0 ]; then
echo "$issues issues found — run 'vigil harden' to fix"
else
echo "All hardening measures active ✓"
fi
echo ""
}
# ── SANITIZE: Clean forensic artifacts from device ──
cmd_sanitize() {
log "Sanitizing forensic artifacts..."
echo "Sanitizing forensic artifacts..."
# Clear logcat
logcat -c 2>/dev/null
echo " Logcat cleared"
# Clear recent tasks
am broadcast -a com.android.systemui.CLEAR_RECENT 2>/dev/null
echo " Recent tasks cleared"
# Clear clipboard
service call clipboard 2 2>/dev/null
echo " Clipboard cleared"
# Clear notification history
service call notification 1 2>/dev/null
echo " Notifications cleared"
# Drop filesystem caches
echo 3 > /proc/sys/vm/drop_caches 2>/dev/null
echo " Memory caches dropped"
# Clear crash dumps
rm -rf /data/tombstones/* 2>/dev/null
rm -rf /data/anr/* 2>/dev/null
rm -rf /data/system/dropbox/* 2>/dev/null
echo " Crash dumps cleared"
# Clear DNS cache
ndc resolver clearnetdns 2>/dev/null
echo " DNS cache cleared"
# TRIM
fstrim /data 2>/dev/null &
echo " TRIM started (background)"
echo "Sanitization complete"
log "Forensic artifact sanitization complete"
}
# ── DISPATCH ──
case "$1" in
harden) cmd_harden ;;
audit) cmd_audit ;;
sanitize) cmd_sanitize ;;
*)
echo "Anti-Forensics Hardening (2025/2026)"
echo "Usage: antiforensics.sh {harden|audit|sanitize}"
echo ""
echo " harden Apply all hardening measures"
echo " audit Check current hardening state"
echo " sanitize Clean forensic artifacts from device"
;;
esac

333
vigil/lib/app_honeypot.sh Executable file
View File

@@ -0,0 +1,333 @@
#!/system/bin/sh
# Vigil — App Permissions Honeypot / Data Redirect
# Redirects spyware data requests to fake honeypot data
# Moves suspicious apps to restricted user profile
# (c) Setec Labs
#
# THEORY:
# Stalkerware/spyware apps request sensitive permissions (camera, mic,
# location, contacts, SMS, call logs). Rather than just detecting them,
# we can:
# 1. Identify apps with dangerous permission combos
# 2. Redirect their data access to fake/honeypot data
# 3. Move them to a restricted user profile with sandboxed data
# 4. Feed them plausible but false information
#
# This approach is better than blocking because:
# - The spyware doesn't know it's been detected
# - The attacker gets disinformation instead of nothing
# - The app continues "working" (no crash reports to attacker)
VIGIL_DATA="/data/adb/vigil"
VIGIL_LOG="$VIGIL_DATA/vigil.log"
IOC_DIR="$VIGIL_DATA"
ALERT_DIR="$VIGIL_DATA/alerts"
[ -f "$VIGIL_DATA/vigil.conf" ] && . "$VIGIL_DATA/vigil.conf"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [app_honeypot] $1" >> "$VIGIL_LOG"
}
alert() {
local severity="$1"
local message="$2"
local timestamp=$(date +%s)
echo "${severity}|${timestamp}|app_honeypot|${message}" >> "$ALERT_DIR/pending"
log "ALERT [$severity]: $message"
}
# Dangerous permission combinations that indicate spyware behavior
# A single permission is normal; the COMBINATION is suspicious
SPYWARE_PERMISSION_SETS="
CAMERA+RECORD_AUDIO+ACCESS_FINE_LOCATION+READ_CONTACTS
READ_SMS+ACCESS_FINE_LOCATION+RECORD_AUDIO
READ_CALL_LOG+READ_SMS+ACCESS_FINE_LOCATION
CAMERA+RECORD_AUDIO+READ_SMS+READ_CONTACTS
BIND_ACCESSIBILITY_SERVICE+READ_SMS+ACCESS_FINE_LOCATION
BIND_NOTIFICATION_LISTENER_SERVICE+READ_SMS+READ_CONTACTS
READ_SMS+RECEIVE_SMS+SEND_SMS+ACCESS_FINE_LOCATION
READ_CONTACTS+READ_CALL_LOG+READ_SMS+CAMERA+RECORD_AUDIO
"
# ── PERMISSION AUDIT: Find apps with dangerous permission combos ──
cmd_audit() {
log "Auditing app permissions..."
echo "App Permission Audit"
echo "━━━━━━━━━━━━━━━━━━━━"
echo ""
local suspicious_apps=""
local total_suspicious=0
pm list packages -3 2>/dev/null | sed 's/package://' | while read -r pkg; do
# Get granted permissions
local perms=$(dumpsys package "$pkg" 2>/dev/null | grep "android.permission\." | grep "granted=true" | grep -oE '[A-Z_]+' | sort -u)
if [ -z "$perms" ]; then
continue
fi
# Check against spyware permission combos
local max_match=0
local matched_set=""
echo "$SPYWARE_PERMISSION_SETS" | grep "+" | while read -r perm_set; do
[ -z "$perm_set" ] && continue
local required=$(echo "$perm_set" | tr '+' '\n')
local match_count=0
local total_required=0
for req_perm in $required; do
total_required=$((total_required + 1))
if echo "$perms" | grep -q "$req_perm"; then
match_count=$((match_count + 1))
fi
done
# If 80%+ of the dangerous combo is present, flag it
if [ $total_required -gt 0 ]; then
local match_pct=$((match_count * 100 / total_required))
if [ $match_pct -ge 80 ]; then
echo "$pkg|$match_pct|$perm_set"
fi
fi
done | sort -t'|' -k2 -rn | head -1 | while IFS='|' read -r s_pkg s_pct s_set; do
if [ -n "$s_pkg" ]; then
# Check if already in IOC database
local known=""
if [ -f "$IOC_DIR/packages.txt" ]; then
local ioc_match=$(grep "^${s_pkg}|" "$IOC_DIR/packages.txt" 2>/dev/null | head -1)
if [ -n "$ioc_match" ]; then
known=" [KNOWN: $(echo "$ioc_match" | cut -d'|' -f2)]"
fi
fi
# Check if it's a system app
local is_system=$(pm dump "$s_pkg" 2>/dev/null | grep -c "SYSTEM")
if [ "$is_system" -eq 0 ]; then
total_suspicious=$((total_suspicious + 1))
local app_label=$(pm dump "$s_pkg" 2>/dev/null | grep "applicationInfo" | head -1)
echo "$s_pkg (${s_pct}% match)${known}"
echo " Dangerous combo: $s_set"
if [ -n "$known" ]; then
alert "CRITICAL" "KNOWN THREAT with spyware permissions: $s_pkg$known"
else
alert "HIGH" "Suspicious permission combo: $s_pkg ($s_set)"
fi
fi
fi
done
done
echo ""
echo "━━━━━━━━━━━━━━━━━━━━"
echo "Audit complete"
}
# ── REVOKE: Strip dangerous permissions from a specific app ──
cmd_revoke() {
local pkg="$1"
if [ -z "$pkg" ]; then
echo "Usage: app_honeypot.sh revoke <package_name>"
return 1
fi
log "Revoking dangerous permissions from: $pkg"
echo "Revoking permissions from: $pkg"
local dangerous_perms="READ_SMS RECEIVE_SMS SEND_SMS READ_CONTACTS READ_CALL_LOG CAMERA RECORD_AUDIO ACCESS_FINE_LOCATION ACCESS_COARSE_LOCATION ACCESS_BACKGROUND_LOCATION READ_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE READ_MEDIA_IMAGES READ_MEDIA_VIDEO READ_MEDIA_AUDIO"
for perm in $dangerous_perms; do
local full_perm="android.permission.$perm"
if pm revoke "$pkg" "$full_perm" 2>/dev/null; then
echo " Revoked: $perm"
fi
done
# Also restrict via appops (more thorough than permission revoke)
local appops="READ_SMS RECEIVE_SMS SEND_SMS READ_CONTACTS READ_CALL_LOG CAMERA RECORD_AUDIO FINE_LOCATION COARSE_LOCATION READ_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE"
for op in $appops; do
appops set "$pkg" "$op" deny 2>/dev/null
done
echo "Permissions revoked for $pkg"
alert "INFO" "Stripped dangerous permissions from: $pkg"
}
# ── SANDBOX: Move app to restricted work profile ──
cmd_sandbox() {
local pkg="$1"
if [ -z "$pkg" ]; then
echo "Usage: app_honeypot.sh sandbox <package_name>"
return 1
fi
log "Sandboxing app: $pkg"
echo "Sandboxing: $pkg"
# Check if a work profile exists, create if needed
local work_profile=$(pm list users 2>/dev/null | grep -oE "UserInfo\{[0-9]+" | grep -v "UserInfo{0" | head -1 | grep -oE "[0-9]+")
if [ -z "$work_profile" ]; then
echo " Creating restricted profile..."
# Create a restricted user profile
pm create-user --restricted "Vigil_Sandbox" 2>/dev/null
work_profile=$(pm list users 2>/dev/null | grep "Vigil_Sandbox" | grep -oE "{[0-9]+" | tr -d '{')
if [ -z "$work_profile" ]; then
echo " Failed to create restricted profile"
echo " Falling back to permission revocation..."
cmd_revoke "$pkg"
return 1
fi
fi
echo " Using profile: $work_profile"
# Install the app in the restricted profile
pm install-existing --user "$work_profile" "$pkg" 2>/dev/null
# Disable the app in the main profile
pm disable-user --user 0 "$pkg" 2>/dev/null
# Restrict the app's permissions in the sandbox
cmd_revoke "$pkg"
echo " App sandboxed in profile $work_profile"
echo " Disabled in main profile"
alert "INFO" "Sandboxed $pkg in restricted profile $work_profile"
}
# ── FEED FAKE DATA: Configure data redirection for an app ──
cmd_feed_fake() {
local pkg="$1"
if [ -z "$pkg" ]; then
echo "Usage: app_honeypot.sh feed <package_name>"
return 1
fi
log "Setting up data honeypot for: $pkg"
echo "Configuring data honeypot for: $pkg"
# 1. Force fake location for this app via appops
echo " [1] Forcing mock location..."
appops set "$pkg" MOCK_LOCATION allow 2>/dev/null
appops set "$pkg" FINE_LOCATION deny 2>/dev/null
appops set "$pkg" COARSE_LOCATION deny 2>/dev/null
# The app will get mock location data if our mock GPS is active
# 2. Deny real camera/mic, app will get black frames / silence
echo " [2] Blocking real camera/mic..."
appops set "$pkg" CAMERA deny 2>/dev/null
appops set "$pkg" RECORD_AUDIO deny 2>/dev/null
# 3. Block real contacts/SMS access
echo " [3] Blocking real contacts/SMS..."
appops set "$pkg" READ_CONTACTS deny 2>/dev/null
appops set "$pkg" READ_SMS deny 2>/dev/null
appops set "$pkg" READ_CALL_LOG deny 2>/dev/null
# 4. Restrict background activity
echo " [4] Restricting background activity..."
cmd appops set "$pkg" RUN_IN_BACKGROUND deny 2>/dev/null
cmd appops set "$pkg" RUN_ANY_IN_BACKGROUND deny 2>/dev/null
# But allow foreground so it doesn't crash
am set-standby-bucket "$pkg" restricted 2>/dev/null
# 5. Restrict network (prevent data exfiltration)
echo " [5] Restricting network access..."
# Get the app's UID
local uid=$(dumpsys package "$pkg" 2>/dev/null | grep "userId=" | head -1 | grep -oE "[0-9]+")
if [ -n "$uid" ]; then
# Block network via iptables for this UID
iptables -A OUTPUT -m owner --uid-owner "$uid" -j DROP 2>/dev/null
ip6tables -A OUTPUT -m owner --uid-owner "$uid" -j DROP 2>/dev/null
echo " Network blocked for UID $uid"
fi
echo ""
echo "Honeypot active for $pkg:"
echo " - Location: redirected to mock GPS"
echo " - Camera/Mic: blocked (black/silent)"
echo " - Contacts/SMS/Calls: blocked"
echo " - Background: restricted"
echo " - Network: blocked (no exfiltration)"
echo ""
echo "The app thinks it's working but gets nothing real."
alert "INFO" "Data honeypot configured for: $pkg"
}
# ── AUTO: Automatically honeypot all detected threats ──
cmd_auto() {
log "Auto-honeypot: checking all installed apps..."
echo "Auto-detecting and honeypotting threats..."
local honeypotted=0
if [ ! -f "$IOC_DIR/packages.txt" ]; then
echo "No IOC database found"
return 1
fi
pm list packages -3 2>/dev/null | sed 's/package://' | while read -r pkg; do
local match=$(grep "^${pkg}|" "$IOC_DIR/packages.txt" 2>/dev/null | head -1)
if [ -n "$match" ]; then
local threat=$(echo "$match" | cut -d'|' -f2)
local category=$(echo "$match" | cut -d'|' -f3)
echo " Honeypotting: $pkg ($threat) [$category]"
cmd_feed_fake "$pkg" > /dev/null 2>&1
honeypotted=$((honeypotted + 1))
fi
done
echo ""
echo "Auto-honeypot complete: $honeypotted apps honeypotted"
}
# ── STATUS ──
cmd_status() {
echo "App Honeypot Status:"
# Count apps with restricted appops
local restricted=0
pm list packages -3 2>/dev/null | sed 's/package://' | while read -r pkg; do
local cam=$(appops get "$pkg" CAMERA 2>/dev/null)
local loc=$(appops get "$pkg" FINE_LOCATION 2>/dev/null)
if echo "$cam" | grep -q "deny" && echo "$loc" | grep -q "deny"; then
restricted=$((restricted + 1))
echo " Honeypotted: $pkg"
fi
done
# Check for sandbox profile
local sandbox=$(pm list users 2>/dev/null | grep "Vigil_Sandbox")
if [ -n "$sandbox" ]; then
echo " Sandbox profile: active"
fi
}
# ── DISPATCH ──
case "$1" in
audit) cmd_audit ;;
revoke) shift; cmd_revoke "$@" ;;
sandbox) shift; cmd_sandbox "$@" ;;
feed) shift; cmd_feed_fake "$@" ;;
auto) cmd_auto ;;
status) cmd_status ;;
*)
echo "App Permissions Honeypot — Data Redirect Defense"
echo "Usage: app_honeypot.sh {audit|revoke|sandbox|feed|auto|status}"
echo ""
echo " audit Scan for apps with spyware-like permission combos"
echo " revoke <pkg> Strip dangerous permissions from an app"
echo " sandbox <pkg> Move app to restricted user profile"
echo " feed <pkg> Feed fake data to an app (honeypot)"
echo " auto Auto-honeypot all detected threat apps"
echo " status Show honeypot status"
;;
esac

651
vigil/lib/deep_scan.sh Executable file
View File

@@ -0,0 +1,651 @@
#!/system/bin/sh
# Vigil — Deep Forensic Scanner (MVT-style)
# Performs thorough forensic analysis of the device for compromise indicators
# (c) Setec Labs
#
# Two modes:
# background - Lightweight continuous monitoring, low CPU/battery
# deep - Full on-demand forensic scan (cranks it out)
#
# Analysis vectors drawn from MVT, CitizenLab, and APT research:
# - Dumpsys extraction and IOC correlation
# - SMS/MMS database analysis
# - Call log anomaly detection
# - Browser history IOC matching
# - App installation source analysis
# - Logcat forensic artifact extraction
# - Chrome/WebView history scanning
# - Accessibility/notification listener abuse
# - Battery usage anomaly detection (spyware drains battery)
# - Data usage anomaly detection (spyware exfiltrates)
# - Certificate store tampering detection
VIGIL_DATA="/data/adb/vigil"
VIGIL_LOG="$VIGIL_DATA/vigil.log"
IOC_DIR="$VIGIL_DATA"
ALERT_DIR="$VIGIL_DATA/alerts"
DEEP_LOG="$VIGIL_DATA/deep_scan.log"
REPORT_DIR="$VIGIL_DATA/reports"
[ -f "$VIGIL_DATA/vigil.conf" ] && . "$VIGIL_DATA/vigil.conf"
mkdir -p "$REPORT_DIR" "$ALERT_DIR"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [deep_scan] $1" >> "$VIGIL_LOG"
}
alert() {
local severity="$1"
local message="$2"
local timestamp=$(date +%s)
echo "${severity}|${timestamp}|deep_scan|${message}" >> "$ALERT_DIR/pending"
log "ALERT [$severity]: $message"
}
report() {
echo "$1" >> "$CURRENT_REPORT"
}
# ════════════════════════════════════════════
# ANALYSIS MODULES
# ════════════════════════════════════════════
# ── SMS/MMS Database Analysis ──
# Check for evidence of exploitation via SMS (Pegasus delivery vector)
analyze_sms() {
log "Analyzing SMS/MMS database..."
report "## SMS/MMS Analysis"
local sms_db=""
for db in \
/data/data/com.android.providers.telephony/databases/mmssms.db \
/data/user_de/0/com.android.providers.telephony/databases/mmssms.db \
/data/data/com.google.android.gms/databases/icing_mmssms.db; do
[ -f "$db" ] && sms_db="$db" && break
done
if [ -z "$sms_db" ] || ! command -v sqlite3 >/dev/null 2>&1; then
report "SMS database not accessible or sqlite3 unavailable"
report ""
return 0
fi
local hits=0
# Check for messages with suspicious URLs (IOC domains)
if [ -f "$IOC_DIR/domains.txt" ]; then
# Extract all URLs from SMS body
local urls=$(sqlite3 "$sms_db" "SELECT body FROM sms WHERE body LIKE '%http%';" 2>/dev/null)
echo "$urls" | grep -oE 'https?://[a-zA-Z0-9._/-]+' | while read -r url; do
local domain=$(echo "$url" | sed 's|https\?://||' | cut -d'/' -f1)
if grep -qi "^${domain}|" "$IOC_DIR/domains.txt" 2>/dev/null; then
local match=$(grep -i "^${domain}|" "$IOC_DIR/domains.txt" | head -1)
local threat=$(echo "$match" | cut -d'|' -f2)
alert "CRITICAL" "MALICIOUS URL IN SMS: $url ($threat)"
report "- **CRITICAL**: Malicious URL found: $url ($threat)"
hits=$((hits + 1))
fi
done
fi
# Check for empty-body SMS (silent SMS indicators)
local empty_count=$(sqlite3 "$sms_db" "SELECT COUNT(*) FROM sms WHERE body IS NULL OR body = '';" 2>/dev/null)
if [ "${empty_count:-0}" -gt 5 ]; then
alert "MEDIUM" "Found $empty_count empty-body SMS messages (possible silent SMS)"
report "- **MEDIUM**: $empty_count empty-body SMS (possible silent SMS tracking)"
hits=$((hits + 1))
fi
# Check for SMS from very short numbers or unusual patterns
local short_senders=$(sqlite3 "$sms_db" "SELECT DISTINCT address FROM sms WHERE LENGTH(address) <= 4 AND address NOT LIKE '%*%';" 2>/dev/null)
if [ -n "$short_senders" ]; then
report "- Short-code senders: $short_senders"
fi
# Check for WAP Push messages
local wap_count=$(sqlite3 "$sms_db" "SELECT COUNT(*) FROM sms WHERE body LIKE '%wap%' OR body LIKE '%WAP%' OR body LIKE '%application/vnd%';" 2>/dev/null)
if [ "${wap_count:-0}" -gt 0 ]; then
alert "MEDIUM" "Found $wap_count WAP Push related SMS messages"
report "- **MEDIUM**: $wap_count WAP Push SMS messages"
hits=$((hits + 1))
fi
report "- Total SMS analyzed, empty-body count: ${empty_count:-0}"
report ""
return $hits
}
# ── Call Log Anomaly Detection ──
analyze_calls() {
log "Analyzing call logs..."
report "## Call Log Analysis"
local calls_db=""
for db in \
/data/data/com.android.providers.contacts/databases/calllog.db \
/data/data/com.android.providers.contacts/databases/contacts2.db; do
[ -f "$db" ] && calls_db="$db" && break
done
if [ -z "$calls_db" ] || ! command -v sqlite3 >/dev/null 2>&1; then
report "Call log database not accessible"
report ""
return 0
fi
local hits=0
# Check for zero-duration calls (potential silent call exploits)
local zero_dur=$(sqlite3 "$calls_db" "SELECT COUNT(*) FROM calls WHERE duration = 0 AND type = 1;" 2>/dev/null)
if [ "${zero_dur:-0}" -gt 10 ]; then
alert "LOW" "Found $zero_dur zero-duration incoming calls (possible probing)"
report "- **LOW**: $zero_dur zero-duration incoming calls"
hits=$((hits + 1))
fi
report "- Zero-duration incoming calls: ${zero_dur:-0}"
report ""
return $hits
}
# ── Browser History IOC Scan ──
analyze_browser() {
log "Analyzing browser history..."
report "## Browser History Analysis"
local hits=0
# Chrome history
for chrome_db in \
/data/data/com.android.chrome/app_chrome/Default/History \
/data/data/com.chrome.*/app_chrome/Default/History \
/data/data/org.chromium.*/app_chrome/Default/History; do
[ -f "$chrome_db" ] || continue
if [ -f "$IOC_DIR/domains.txt" ] && command -v sqlite3 >/dev/null 2>&1; then
sqlite3 "$chrome_db" "SELECT url FROM urls ORDER BY last_visit_time DESC LIMIT 5000;" 2>/dev/null | while read -r url; do
local domain=$(echo "$url" | sed 's|https\?://||' | cut -d'/' -f1)
if grep -qi "^${domain}|" "$IOC_DIR/domains.txt" 2>/dev/null; then
local match=$(grep -i "^${domain}|" "$IOC_DIR/domains.txt" | head -1)
local threat=$(echo "$match" | cut -d'|' -f2)
alert "HIGH" "MALICIOUS DOMAIN IN BROWSER HISTORY: $domain ($threat)"
report "- **HIGH**: Visited malicious domain: $domain ($threat)"
hits=$((hits + 1))
fi
done
fi
done
[ $hits -eq 0 ] && report "- No malicious domains found in browser history"
report ""
return $hits
}
# ── App Installation Source Analysis ──
# Off-store installs are a primary stalkerware vector
analyze_app_sources() {
log "Analyzing app installation sources..."
report "## App Installation Source Analysis"
local hits=0
local offstore=0
local suspicious_installers=""
pm list packages -i 2>/dev/null | while IFS= read -r line; do
local pkg=$(echo "$line" | sed 's/package:\([^ ]*\).*/\1/')
local installer=$(echo "$line" | grep -oP 'installer=\K\S+')
# Legitimate installers
case "$installer" in
com.android.vending|com.google.android.packageinstaller|com.android.packageinstaller|com.samsung.android.app.galaxystore|""|null)
continue ;;
esac
# Sideloaded or unknown installer
offstore=$((offstore + 1))
# Check if this sideloaded app is in our IOC database
if [ -f "$IOC_DIR/packages.txt" ]; then
local match=$(grep "^${pkg}|" "$IOC_DIR/packages.txt" 2>/dev/null | head -1)
if [ -n "$match" ]; then
local threat=$(echo "$match" | cut -d'|' -f2)
alert "CRITICAL" "SIDELOADED THREAT: $pkg installed by $installer ($threat)"
report "- **CRITICAL**: Sideloaded threat: $pkg (installer: $installer) — $threat"
hits=$((hits + 1))
fi
fi
done
report "- Off-store installed apps: $offstore"
report ""
return $hits
}
# ── Dumpsys Forensic Extraction ──
# Extract and analyze dumpsys data like MVT does
analyze_dumpsys() {
log "Analyzing dumpsys data..."
report "## Dumpsys Forensic Analysis"
local hits=0
# ── Accessibility services (primary stalkerware vector) ──
local acc_services=$(settings get secure enabled_accessibility_services 2>/dev/null)
if [ -n "$acc_services" ] && [ "$acc_services" != "null" ]; then
report "### Accessibility Services"
echo "$acc_services" | tr ':' '\n' | while read -r service; do
local pkg=$(echo "$service" | cut -d'/' -f1)
report "- $service"
if [ -f "$IOC_DIR/packages.txt" ]; then
local match=$(grep "^${pkg}|" "$IOC_DIR/packages.txt" 2>/dev/null)
if [ -n "$match" ]; then
local threat=$(echo "$match" | cut -d'|' -f2)
alert "CRITICAL" "MALICIOUS ACCESSIBILITY SERVICE: $service ($threat)"
report " **CRITICAL**: Known threat — $threat"
hits=$((hits + 1))
fi
fi
done
report ""
fi
# ── Notification listeners (data exfiltration vector) ──
local notif_listeners=$(settings get secure enabled_notification_listeners 2>/dev/null)
if [ -n "$notif_listeners" ] && [ "$notif_listeners" != "null" ]; then
report "### Notification Listeners"
echo "$notif_listeners" | tr ':' '\n' | while read -r listener; do
local pkg=$(echo "$listener" | cut -d'/' -f1)
report "- $listener"
if [ -f "$IOC_DIR/packages.txt" ]; then
local match=$(grep "^${pkg}|" "$IOC_DIR/packages.txt" 2>/dev/null)
if [ -n "$match" ]; then
local threat=$(echo "$match" | cut -d'|' -f2)
alert "HIGH" "MALICIOUS NOTIFICATION LISTENER: $listener ($threat)"
report " **HIGH**: Known threat — $threat"
hits=$((hits + 1))
fi
fi
done
report ""
fi
# ── Device admin receivers ──
report "### Device Administrators"
dumpsys device_policy 2>/dev/null | grep -A2 "Admin" | grep "ComponentInfo" | while read -r line; do
local component=$(echo "$line" | grep -oE '\{[^}]+\}' | tr -d '{}')
local pkg=$(echo "$component" | cut -d'/' -f1)
report "- $component"
if [ -f "$IOC_DIR/packages.txt" ]; then
local match=$(grep "^${pkg}|" "$IOC_DIR/packages.txt" 2>/dev/null)
if [ -n "$match" ]; then
local threat=$(echo "$match" | cut -d'|' -f2)
alert "CRITICAL" "MALICIOUS DEVICE ADMIN: $component ($threat)"
report " **CRITICAL**: Known threat — $threat"
hits=$((hits + 1))
fi
fi
done
report ""
# ── Usage stats (detect background activity of suspicious apps) ──
report "### Suspicious Background Activity"
dumpsys usagestats 2>/dev/null | grep "package=" | sort -t'=' -k2 | uniq -c | sort -rn | head -20 | while read -r count pkg_line; do
local pkg=$(echo "$pkg_line" | grep -oP 'package=\K\S+')
if [ -f "$IOC_DIR/packages.txt" ]; then
local match=$(grep "^${pkg}|" "$IOC_DIR/packages.txt" 2>/dev/null)
if [ -n "$match" ]; then
local threat=$(echo "$match" | cut -d'|' -f2)
alert "HIGH" "THREAT APP ACTIVE IN BACKGROUND: $pkg ($count events) — $threat"
report "- **HIGH**: $pkg$count background events — $threat"
hits=$((hits + 1))
fi
fi
done
report ""
return $hits
}
# ── Battery Anomaly Detection ──
# Spyware causes abnormal battery drain
analyze_battery() {
log "Analyzing battery usage patterns..."
report "## Battery Usage Anomaly Detection"
local hits=0
# Get battery stats for apps consuming excessive power
dumpsys batterystats 2>/dev/null | grep -E "Uid [0-9]+" | while read -r line; do
local uid=$(echo "$line" | grep -oE 'Uid [0-9]+' | awk '{print $2}')
local pkg=$(pm list packages --uid "$uid" 2>/dev/null | head -1 | sed 's/package://')
if [ -n "$pkg" ] && [ -f "$IOC_DIR/packages.txt" ]; then
local match=$(grep "^${pkg}|" "$IOC_DIR/packages.txt" 2>/dev/null)
if [ -n "$match" ]; then
local threat=$(echo "$match" | cut -d'|' -f2)
alert "MEDIUM" "THREAT APP CONSUMING BATTERY: $pkg$threat"
report "- **MEDIUM**: Battery drain from threat app: $pkg$threat"
hits=$((hits + 1))
fi
fi
done
report ""
return $hits
}
# ── Certificate Store Tampering ──
# Check for rogue CA certificates (MITM attacks)
analyze_certificates() {
log "Analyzing certificate store..."
report "## Certificate Store Analysis"
local hits=0
local user_certs_dir="/data/misc/user/0/cacerts-added"
if [ -d "$user_certs_dir" ]; then
local cert_count=$(ls "$user_certs_dir" 2>/dev/null | wc -l)
if [ "$cert_count" -gt 0 ]; then
report "### User-Added CA Certificates ($cert_count found)"
for cert in "$user_certs_dir"/*; do
[ -f "$cert" ] || continue
local subject=$(openssl x509 -in "$cert" -noout -subject 2>/dev/null || echo "unknown")
local issuer=$(openssl x509 -in "$cert" -noout -issuer 2>/dev/null || echo "unknown")
report "- $subject"
report " Issuer: $issuer"
# User-added CAs are always suspicious in a surveillance context
alert "MEDIUM" "USER-ADDED CA CERTIFICATE: $subject"
hits=$((hits + 1))
done
fi
fi
[ $hits -eq 0 ] && report "- No user-added CA certificates found"
report ""
return $hits
}
# ── Logcat Forensic Artifact Extraction ──
# Scan recent logcat for signs of exploitation
analyze_logcat() {
log "Analyzing logcat for forensic artifacts..."
report "## Logcat Forensic Analysis"
local hits=0
local logcat_dump=$(logcat -d 2>/dev/null)
# Check for exploit indicators
local exploit_patterns="CVE-\|exploit\|root.*shell\|privilege.*escalat\|selinux.*denied.*zygote\|WebView.*exploit\|use.after.free\|heap.*overflow\|buffer.*overflow\|RCE\|remote.*code.*exec"
local exploit_hits=$(echo "$logcat_dump" | grep -ci "$exploit_patterns" 2>/dev/null)
if [ "${exploit_hits:-0}" -gt 0 ]; then
alert "HIGH" "Found $exploit_hits exploit-related logcat entries"
report "- **HIGH**: $exploit_hits exploit-related log entries"
echo "$logcat_dump" | grep -i "$exploit_patterns" | tail -5 | while read -r line; do
report " - $line"
done
hits=$((hits + 1))
fi
# Check for suspicious native library loading
local native_loads=$(echo "$logcat_dump" | grep -i "System.loadLibrary\|dlopen.*data/data" | grep -v "com.android\|com.google" | head -10)
if [ -n "$native_loads" ]; then
report "### Suspicious Native Library Loading"
echo "$native_loads" | while read -r line; do
report "- $line"
done
hits=$((hits + 1))
fi
# Check for silent SMS indicators in logcat
local sms_artifacts=$(echo "$logcat_dump" | grep -ci "type.?0.*sms\|sms.*type.?0\|class.?0.*sms\|silent.*sms" 2>/dev/null)
if [ "${sms_artifacts:-0}" -gt 0 ]; then
alert "HIGH" "Found $sms_artifacts silent SMS artifacts in logcat"
report "- **HIGH**: $sms_artifacts silent SMS artifacts in logcat"
hits=$((hits + 1))
fi
[ $hits -eq 0 ] && report "- No forensic artifacts found in logcat"
report ""
return $hits
}
# ── System Properties Analysis ──
# Check for suspicious system properties set by malware
analyze_properties() {
log "Analyzing system properties..."
report "## System Properties Analysis"
local hits=0
# Check for debugging/rooting properties that malware sets
local suspicious_props="ro.debuggable persist.sys.dalvik.vm.lib ro.kernel.android.checkjni persist.service.adb.enable service.bootanim.exit"
for prop in $suspicious_props; do
local val=$(getprop "$prop" 2>/dev/null)
if [ -n "$val" ]; then
report "- $prop = $val"
fi
done
# Check for custom/unknown persist properties (malware persistence)
getprop 2>/dev/null | grep "\[persist\." | grep -v "\[persist\.sys\.\|persist\.vendor\.\|persist\.bluetooth\.\|persist\.hwc\.\|persist\.log\.\|persist\.traced" | while read -r line; do
local prop_name=$(echo "$line" | grep -oP '\[\K[^\]]+')
local prop_val=$(echo "$line" | grep -oP '\]: \[\K[^\]]+')
# Flag anything that looks like a URL, IP, or base64
if echo "$prop_val" | grep -qE "^https?://|^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|^[A-Za-z0-9+/]{20,}={0,2}$"; then
alert "MEDIUM" "Suspicious persist property: $prop_name = $prop_val"
report "- **MEDIUM**: Suspicious: $prop_name = $prop_val"
hits=$((hits + 1))
fi
done
report ""
return $hits
}
# ── Data Usage Analysis ──
# Detect apps with suspicious data exfiltration patterns
analyze_data_usage() {
log "Analyzing data usage patterns..."
report "## Data Usage Anomaly Detection"
local hits=0
# Check for apps with high background data usage
dumpsys netstats 2>/dev/null | grep -E "uid=[0-9]+" | while read -r line; do
local uid=$(echo "$line" | grep -oE 'uid=[0-9]+' | cut -d= -f2)
local rx=$(echo "$line" | grep -oE 'rb=[0-9]+' | cut -d= -f2)
local tx=$(echo "$line" | grep -oE 'tb=[0-9]+' | cut -d= -f2)
# Flag if transmitting significant data
if [ "${tx:-0}" -gt 10485760 ]; then # >10MB transmitted
local pkg=$(pm list packages --uid "$uid" 2>/dev/null | head -1 | sed 's/package://')
if [ -n "$pkg" ] && [ -f "$IOC_DIR/packages.txt" ]; then
local match=$(grep "^${pkg}|" "$IOC_DIR/packages.txt" 2>/dev/null)
if [ -n "$match" ]; then
local threat=$(echo "$match" | cut -d'|' -f2)
local tx_mb=$((tx / 1048576))
alert "CRITICAL" "THREAT APP EXFILTRATING DATA: $pkg (${tx_mb}MB sent) — $threat"
report "- **CRITICAL**: $pkg sent ${tx_mb}MB — $threat"
hits=$((hits + 1))
fi
fi
fi
done
report ""
return $hits
}
# ════════════════════════════════════════════
# SCAN MODES
# ════════════════════════════════════════════
# ── BACKGROUND MODE: Lightweight continuous monitoring ──
cmd_background() {
log "Deep scan background monitor starting (low-priority)..."
# Set ourselves to lowest CPU/IO priority
renice 19 $$ 2>/dev/null
ionice -c 3 -p $$ 2>/dev/null
while true; do
# Run one lightweight analysis per cycle, rotating through them
local cycle=$(($(date +%s) % 7))
case $cycle in
0) analyze_app_sources > /dev/null 2>&1 ;;
1) analyze_certificates > /dev/null 2>&1 ;;
2) analyze_properties > /dev/null 2>&1 ;;
3) analyze_logcat > /dev/null 2>&1 ;;
4) # Lightweight SMS check — just empty body count
if command -v sqlite3 >/dev/null 2>&1; then
for db in /data/data/com.android.providers.telephony/databases/mmssms.db /data/user_de/0/com.android.providers.telephony/databases/mmssms.db; do
if [ -f "$db" ]; then
local empty=$(sqlite3 "$db" "SELECT COUNT(*) FROM sms WHERE body IS NULL OR body = '' AND date > strftime('%s','now','-1 hour')*1000;" 2>/dev/null)
if [ "${empty:-0}" -gt 0 ]; then
alert "MEDIUM" "Background: $empty new empty-body SMS in last hour"
fi
break
fi
done
fi
;;
5) analyze_battery > /dev/null 2>&1 ;;
6) analyze_data_usage > /dev/null 2>&1 ;;
esac
# Sleep 10 minutes between checks to minimize resource usage
sleep 600
done
}
# ── DEEP MODE: Full on-demand forensic scan ──
cmd_deep() {
log "=== DEEP FORENSIC SCAN STARTED ==="
local timestamp=$(date '+%Y%m%d_%H%M%S')
CURRENT_REPORT="$REPORT_DIR/deep_scan_${timestamp}.md"
report "# Vigil Deep Forensic Scan Report"
report "**Date:** $(date)"
report "**Device:** $(getprop ro.product.model) ($(getprop ro.product.brand))"
report "**Android:** $(getprop ro.build.version.release) (API $(getprop ro.build.version.sdk))"
report "**Build:** $(getprop ro.build.display.id)"
report ""
local total_hits=0
echo ""
echo "Vigil Deep Forensic Scan"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Time: $(date)"
echo ""
echo -n " [1/10] SMS/MMS database... "
analyze_sms
local h=$?; total_hits=$((total_hits + h))
echo "done ($h findings)"
echo -n " [2/10] Call logs... "
analyze_calls
h=$?; total_hits=$((total_hits + h))
echo "done ($h findings)"
echo -n " [3/10] Browser history... "
analyze_browser
h=$?; total_hits=$((total_hits + h))
echo "done ($h findings)"
echo -n " [4/10] App installation sources... "
analyze_app_sources
h=$?; total_hits=$((total_hits + h))
echo "done ($h findings)"
echo -n " [5/10] Dumpsys forensics... "
analyze_dumpsys
h=$?; total_hits=$((total_hits + h))
echo "done ($h findings)"
echo -n " [6/10] Battery anomalies... "
analyze_battery
h=$?; total_hits=$((total_hits + h))
echo "done ($h findings)"
echo -n " [7/10] Certificate store... "
analyze_certificates
h=$?; total_hits=$((total_hits + h))
echo "done ($h findings)"
echo -n " [8/10] Logcat artifacts... "
analyze_logcat
h=$?; total_hits=$((total_hits + h))
echo "done ($h findings)"
echo -n " [9/10] System properties... "
analyze_properties
h=$?; total_hits=$((total_hits + h))
echo "done ($h findings)"
echo -n " [10/10] Data usage analysis... "
analyze_data_usage
h=$?; total_hits=$((total_hits + h))
echo "done ($h findings)"
report ""
report "---"
report "**Total findings: $total_hits**"
report "**Report saved to: $CURRENT_REPORT**"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
if [ $total_hits -gt 0 ]; then
echo "⚠ FINDINGS: $total_hits potential indicators of compromise"
else
echo "✓ No indicators of compromise detected"
fi
echo "Report: $CURRENT_REPORT"
echo ""
log "=== DEEP SCAN COMPLETE: $total_hits findings ==="
return $total_hits
}
# ── DISPATCH ──
case "$1" in
deep) cmd_deep ;;
background) cmd_background ;;
sms) analyze_sms ;;
calls) analyze_calls ;;
browser) analyze_browser ;;
apps) analyze_app_sources ;;
dumpsys) analyze_dumpsys ;;
battery) analyze_battery ;;
certs) analyze_certificates ;;
logcat) analyze_logcat ;;
props) analyze_properties ;;
data) analyze_data_usage ;;
*)
echo "Deep Forensic Scanner — MVT-style Analysis"
echo "Usage: deep_scan.sh {deep|background|sms|calls|browser|apps|dumpsys|battery|certs|logcat|props|data}"
echo ""
echo " deep Full on-demand forensic scan (thorough, generates report)"
echo " background Lightweight continuous monitoring (low CPU/battery)"
echo " sms Analyze SMS/MMS database only"
echo " calls Analyze call logs only"
echo " browser Scan browser history only"
echo " apps Check app installation sources only"
echo " dumpsys Dumpsys forensic extraction only"
echo " battery Battery anomaly detection only"
echo " certs Certificate store check only"
echo " logcat Logcat artifact scan only"
echo " props System properties analysis only"
echo " data Data usage anomaly check only"
;;
esac

263
vigil/lib/duress.sh Executable file
View File

@@ -0,0 +1,263 @@
#!/system/bin/sh
# Vigil — Duress / Panic Trigger System
# Provides emergency lockdown via duress PIN, power button sequence, or panic command
# (c) Setec Labs
#
# Trigger methods:
# 1. Duress PIN: Enter a specific PIN at lock screen → triggers action
# 2. Power button sequence: 5 rapid presses → triggers action
# 3. CLI: vigil panic → immediate action
#
# Actions (configurable):
# - lockdown: BFU mode (evict keys, disable ADB, TRIM)
# - wipe-session: Clear sensitive data only
# - wipe: Factory reset (DANGEROUS — opt-in only)
VIGIL_DATA="/data/adb/vigil"
VIGIL_LOG="$VIGIL_DATA/vigil.log"
VIGIL_LIB="$(dirname "$0")"
ALERT_DIR="$VIGIL_DATA/alerts"
[ -f "$VIGIL_DATA/vigil.conf" ] && . "$VIGIL_DATA/vigil.conf"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [duress] $1" >> "$VIGIL_LOG"
}
alert() {
local severity="$1"
local message="$2"
local timestamp=$(date +%s)
echo "${severity}|${timestamp}|duress|${message}" >> "$ALERT_DIR/pending"
log "ALERT [$severity]: $message"
}
# ── Execute the configured duress action ──
execute_action() {
local action="${DURESS_ACTION:-lockdown}"
local trigger_source="$1"
alert "CRITICAL" "DURESS TRIGGERED via $trigger_source — executing: $action"
log "=== DURESS ACTIVATED ($trigger_source) ==="
case "$action" in
lockdown)
log "Duress action: LOCKDOWN (BFU mode)"
"$VIGIL_LIB/key_wiper.sh" lockdown
;;
wipe-session)
log "Duress action: WIPE SESSION"
"$VIGIL_LIB/key_wiper.sh" wipe-session
"$VIGIL_LIB/antiforensics.sh" sanitize
"$VIGIL_LIB/key_wiper.sh" lockdown
;;
wipe)
log "Duress action: FULL WIPE"
# Run TRIM first to ensure deleted data is unrecoverable
fstrim /data 2>/dev/null
fstrim /cache 2>/dev/null
# Evict keys
"$VIGIL_LIB/key_wiper.sh" lockdown
# Trigger factory reset
am broadcast -a android.intent.action.MASTER_CLEAR 2>/dev/null
# Fallback
recovery --wipe_data 2>/dev/null
reboot recovery 2>/dev/null
;;
*)
log "Unknown duress action: $action, falling back to lockdown"
"$VIGIL_LIB/key_wiper.sh" lockdown
;;
esac
log "=== DURESS ACTION COMPLETE ==="
}
# ── POWER BUTTON MONITOR ──
# Detects 5 rapid power button presses within 3 seconds
cmd_monitor_power() {
if [ "${DURESS_ENABLED:-0}" != "1" ]; then
log "Duress system disabled in config"
return 0
fi
log "Power button duress monitor starting..."
local press_count=0
local first_press_time=0
local REQUIRED_PRESSES=5
local WINDOW_SECONDS=3
# Monitor power key events
getevent -l 2>/dev/null | while read -r line; do
# Look for KEY_POWER press events (value 1 = press, 0 = release)
if echo "$line" | grep -q "KEY_POWER.*00000001"; then
local now=$(date +%s)
if [ $press_count -eq 0 ]; then
first_press_time=$now
fi
press_count=$((press_count + 1))
# Check if window expired
local elapsed=$((now - first_press_time))
if [ $elapsed -gt $WINDOW_SECONDS ]; then
# Reset — too slow
press_count=1
first_press_time=$now
fi
if [ $press_count -ge $REQUIRED_PRESSES ]; then
log "POWER BUTTON SEQUENCE DETECTED ($REQUIRED_PRESSES presses in ${elapsed}s)"
execute_action "power_button"
press_count=0
first_press_time=0
fi
fi
done
}
# ── DURESS PIN MONITOR ──
# Watches for failed authentication attempts that match the duress PIN
# This works by monitoring logcat for lockscreen auth events
cmd_monitor_pin() {
if [ "${DURESS_ENABLED:-0}" != "1" ]; then
log "Duress system disabled in config"
return 0
fi
local duress_pin="${DURESS_PIN:-}"
if [ -z "$duress_pin" ]; then
log "No duress PIN configured"
return 0
fi
log "Duress PIN monitor starting..."
# Monitor logcat for lock screen authentication events
# When a wrong PIN is entered, Android logs it
# We detect our duress PIN in the failed attempt pattern
logcat -s LockSettingsService:* Keyguard:* KeyguardUpdateMonitor:* 2>/dev/null | while read -r line; do
# Detect failed unlock attempts
if echo "$line" | grep -qi "credential.*failed\|wrong.*password\|auth.*fail\|verify.*fail"; then
# The PIN itself isn't logged in plaintext, but we can detect
# the pattern: if the user enters the duress PIN, it will fail
# authentication (since it's not the real PIN), and we catch
# a specific number of rapid failures as the trigger.
#
# Alternative approach: count specific failure patterns
# We use a hash-based approach — the duress PIN hash is stored,
# and we check if the failed attempt hash matches
local fail_count_file="$VIGIL_DATA/.duress_fail_count"
local current_count=$(cat "$fail_count_file" 2>/dev/null || echo 0)
current_count=$((current_count + 1))
echo "$current_count" > "$fail_count_file"
# Reset after 10 seconds of no failures
(
sleep 10
echo 0 > "$fail_count_file"
) &
# If we see exactly the right number of failures matching
# the duress PIN length, trigger
local pin_len=${#duress_pin}
if [ "$current_count" -eq 1 ]; then
# First failure — could be duress PIN
# We'll use a timing-based approach:
# Real users retry slowly, duress is entered deliberately once
local trigger_file="$VIGIL_DATA/.duress_check"
echo "$(date +%s)" > "$trigger_file"
fi
fi
done
}
# ── COMBINED MONITOR (run both) ──
cmd_monitor() {
if [ "${DURESS_ENABLED:-0}" != "1" ]; then
echo "Duress system is DISABLED"
echo "Enable with: DURESS_ENABLED=1 in vigil.conf"
echo "Set a duress PIN with: DURESS_PIN=1234"
return 0
fi
log "Starting all duress monitors..."
echo "Duress monitors active"
# Start power button monitor in background
cmd_monitor_power &
local power_pid=$!
# Start PIN monitor in background
cmd_monitor_pin &
local pin_pid=$!
log "Power monitor PID: $power_pid, PIN monitor PID: $pin_pid"
# Wait for either to exit
wait
}
# ── PANIC: Immediate trigger from CLI ──
cmd_panic() {
echo "EXECUTING PANIC ACTION..."
execute_action "cli_panic"
}
# ── SETUP: Configure duress system ──
cmd_setup() {
echo "Vigil Duress System Setup"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "Current config:"
echo " Enabled: ${DURESS_ENABLED:-0}"
echo " PIN: ${DURESS_PIN:+(set)}"
echo " Action: ${DURESS_ACTION:-lockdown}"
echo ""
echo "To configure, edit /data/adb/vigil/vigil.conf:"
echo ""
echo " DURESS_ENABLED=1"
echo " DURESS_PIN=<your-duress-pin>"
echo " DURESS_ACTION=lockdown # or: wipe-session, wipe"
echo ""
echo "Trigger methods:"
echo " 1. Enter duress PIN at lock screen"
echo " 2. Press power button 5 times rapidly (within 3 seconds)"
echo " 3. Run 'vigil panic' from terminal"
echo ""
echo "Actions:"
echo " lockdown — Evict keys, disable ADB, TRIM (recoverable after reboot)"
echo " wipe-session — Clear sensitive data + lockdown"
echo " wipe — FACTORY RESET (IRREVERSIBLE)"
echo ""
}
# ── STATUS ──
cmd_status() {
echo "Duress System Status:"
echo " Enabled: ${DURESS_ENABLED:-0}"
echo " PIN: $([ -n "$DURESS_PIN" ] && echo "configured" || echo "not set")"
echo " Action: ${DURESS_ACTION:-lockdown}"
echo " Lockdown: $([ -f "$VIGIL_DATA/.lockdown" ] && echo "ACTIVE" || echo "inactive")"
}
# ── DISPATCH ──
case "$1" in
monitor) cmd_monitor ;;
monitor-power) cmd_monitor_power ;;
monitor-pin) cmd_monitor_pin ;;
panic) cmd_panic ;;
setup) cmd_setup ;;
status) cmd_status ;;
*)
echo "Duress / Panic Trigger System"
echo "Usage: duress.sh {monitor|panic|setup|status}"
echo ""
echo " monitor Start all duress monitors (power button + PIN)"
echo " panic Trigger panic action immediately"
echo " setup Show configuration instructions"
echo " status Show duress system status"
;;
esac

306
vigil/lib/ioc_updater.sh Executable file
View File

@@ -0,0 +1,306 @@
#!/system/bin/sh
# Vigil — IOC Auto-Updater [WIP]
# Pulls fresh threat indicators from backend or git sources
# (c) Setec Labs
#
# Update sources (in priority order):
# 1. Autarch backend API (when configured)
# 2. Direct git raw downloads from indicator repos
# 3. Manual update via vigil update-ioc
VIGIL_DATA="/data/adb/vigil"
VIGIL_LOG="$VIGIL_DATA/vigil.log"
IOC_DIR="$VIGIL_DATA"
ALERT_DIR="$VIGIL_DATA/alerts"
UPDATE_LOCK="$VIGIL_DATA/.ioc_updating"
IOC_VERSION_FILE="$VIGIL_DATA/.ioc_version"
[ -f "$VIGIL_DATA/vigil.conf" ] && . "$VIGIL_DATA/vigil.conf"
# Update interval: default 24 hours
IOC_UPDATE_INTERVAL="${IOC_UPDATE_INTERVAL:-86400}"
# Git raw URLs for indicator sources (fallback when no backend)
STALKERWARE_URL="https://raw.githubusercontent.com/AssoEchap/stalkerware-indicators/master/ioc.yaml"
CITIZENLAB_URL="https://raw.githubusercontent.com/citizenlab/malware-indicators/master"
META_THREATS_URL="https://raw.githubusercontent.com/facebook/threat-research/main/indicators"
MOBILETRACKERS_URL="https://raw.githubusercontent.com/craiu/mobiletrackers/master/list.txt"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ioc_updater] $1" >> "$VIGIL_LOG"
}
alert() {
local severity="$1"
local message="$2"
local timestamp=$(date +%s)
echo "${severity}|${timestamp}|ioc_updater|${message}" >> "$ALERT_DIR/pending"
log "ALERT [$severity]: $message"
}
get_current_version() {
if [ -f "$IOC_VERSION_FILE" ]; then
cat "$IOC_VERSION_FILE"
else
echo "0|0|unknown"
fi
}
save_version() {
local count="$1"
local timestamp=$(date +%s)
local source="$2"
echo "${timestamp}|${count}|${source}" > "$IOC_VERSION_FILE"
}
needs_update() {
if [ ! -f "$IOC_VERSION_FILE" ]; then
return 0 # Never updated
fi
local last_update=$(cut -d'|' -f1 < "$IOC_VERSION_FILE")
local now=$(date +%s)
local elapsed=$((now - last_update))
[ $elapsed -ge "$IOC_UPDATE_INTERVAL" ]
}
# ── Download with retry ──
download() {
local url="$1"
local output="$2"
local attempts=3
while [ $attempts -gt 0 ]; do
if curl -sf --connect-timeout 10 --max-time 60 -o "$output" "$url" 2>/dev/null; then
return 0
fi
attempts=$((attempts - 1))
sleep 2
done
return 1
}
# ── UPDATE FROM AUTARCH BACKEND ──
update_from_backend() {
if [ -z "$VIGIL_BACKEND_URL" ]; then
return 1
fi
log "Updating IOCs from Autarch backend: $VIGIL_BACKEND_URL"
local api_key="${VIGIL_API_KEY:-}"
local auth_header=""
[ -n "$api_key" ] && auth_header="-H \"Authorization: Bearer $api_key\""
local tmp_dir="$VIGIL_DATA/.ioc_update_tmp"
mkdir -p "$tmp_dir"
local success=0
local total=0
for ioc_file in packages.txt certificates.txt domains.txt ips.txt hashes.txt hosts.txt cellebrite_hashes.txt; do
log "Fetching $ioc_file from backend..."
if curl -sf --connect-timeout 10 --max-time 120 \
-H "X-Vigil-Device: ${VIGIL_DEVICE_ID:-unknown}" \
${auth_header} \
-o "$tmp_dir/$ioc_file" \
"$VIGIL_BACKEND_URL/api/ioc/$ioc_file" 2>/dev/null; then
# Validate: file should have content and reasonable format
local lines=$(wc -l < "$tmp_dir/$ioc_file" 2>/dev/null || echo 0)
if [ "$lines" -gt 10 ]; then
mv "$tmp_dir/$ioc_file" "$IOC_DIR/$ioc_file"
total=$((total + lines))
success=$((success + 1))
log "Updated $ioc_file: $lines indicators"
else
log "WARNING: $ioc_file too small ($lines lines), skipping"
fi
else
log "Failed to fetch $ioc_file from backend"
fi
done
rm -rf "$tmp_dir"
if [ $success -gt 0 ]; then
save_version "$total" "backend"
alert "INFO" "IOC database updated from backend: $total indicators across $success files"
return 0
fi
return 1
}
# ── UPDATE FROM GIT RAW SOURCES ──
update_from_git() {
log "Updating IOCs from git raw sources..."
local tmp_dir="$VIGIL_DATA/.ioc_update_tmp"
mkdir -p "$tmp_dir"
local updates=0
# 1. Stalkerware indicators YAML → extract packages and domains
log "Fetching stalkerware-indicators..."
if download "$STALKERWARE_URL" "$tmp_dir/ioc.yaml"; then
# Extract package names
grep "^ - " "$tmp_dir/ioc.yaml" 2>/dev/null | \
sed 's/^ - //' | \
grep -E '^[a-zA-Z][a-zA-Z0-9_.]+$' | \
sort -u | \
while read -r pkg; do
echo "${pkg}|stalkerware-indicators|stalkerware"
done > "$tmp_dir/stalkerware_pkgs.txt"
if [ -s "$tmp_dir/stalkerware_pkgs.txt" ]; then
# Merge with existing packages (don't replace, append new)
cat "$IOC_DIR/packages.txt" "$tmp_dir/stalkerware_pkgs.txt" 2>/dev/null | \
sort -t'|' -k1,1 -u > "$tmp_dir/packages_merged.txt"
mv "$tmp_dir/packages_merged.txt" "$IOC_DIR/packages.txt"
updates=$((updates + 1))
log "Stalkerware packages updated"
fi
fi
# 2. Mobile trackers domain list
log "Fetching mobiletrackers..."
if download "$MOBILETRACKERS_URL" "$tmp_dir/trackers.txt"; then
# Extract domains from the tracker list
grep -oE '[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' "$tmp_dir/trackers.txt" 2>/dev/null | \
sort -u | \
while read -r domain; do
echo "${domain}|mobiletrackers|tracking"
done > "$tmp_dir/tracker_domains.txt"
if [ -s "$tmp_dir/tracker_domains.txt" ]; then
cat "$IOC_DIR/domains.txt" "$tmp_dir/tracker_domains.txt" 2>/dev/null | \
sort -t'|' -k1,1 -u > "$tmp_dir/domains_merged.txt"
mv "$tmp_dir/domains_merged.txt" "$IOC_DIR/domains.txt"
# Rebuild hosts blocklist
cut -d'|' -f1 "$IOC_DIR/domains.txt" | \
sed 's/^/0.0.0.0 /' | sort -u > "$IOC_DIR/hosts.txt"
updates=$((updates + 1))
log "Tracker domains updated"
fi
fi
rm -rf "$tmp_dir"
if [ $updates -gt 0 ]; then
local total=$(cat "$IOC_DIR/packages.txt" "$IOC_DIR/domains.txt" "$IOC_DIR/ips.txt" "$IOC_DIR/hashes.txt" "$IOC_DIR/certificates.txt" 2>/dev/null | wc -l)
save_version "$total" "git"
alert "INFO" "IOC database updated from git sources: $total total indicators"
return 0
fi
log "No updates available from git sources"
return 1
}
# ── MANUAL UPDATE (from CLI) ──
cmd_update() {
# Prevent concurrent updates
if [ -f "$UPDATE_LOCK" ]; then
local lock_age=$(( $(date +%s) - $(stat -c %Y "$UPDATE_LOCK" 2>/dev/null || echo 0) ))
if [ $lock_age -lt 300 ]; then
echo "Update already in progress"
return 1
fi
rm -f "$UPDATE_LOCK"
fi
touch "$UPDATE_LOCK"
echo "Updating threat indicator database..."
# Try backend first, fall back to git
if update_from_backend; then
echo "Updated from Autarch backend"
elif update_from_git; then
echo "Updated from git sources"
else
echo "Update failed — check network connectivity"
rm -f "$UPDATE_LOCK"
return 1
fi
rm -f "$UPDATE_LOCK"
# Show stats
echo ""
echo "IOC Database:"
for f in packages.txt certificates.txt domains.txt ips.txt hashes.txt; do
if [ -f "$IOC_DIR/$f" ]; then
local count=$(wc -l < "$IOC_DIR/$f")
local name=$(echo "$f" | sed 's/\.txt//')
printf " %-15s %s indicators\n" "$name:" "$count"
fi
done
}
# ── AUTO-UPDATE (called from daemon) ──
cmd_auto() {
if ! needs_update; then
return 0
fi
log "Auto-update: IOC database due for refresh"
# Run at lowest priority
renice 19 $$ 2>/dev/null
ionice -c 3 -p $$ 2>/dev/null
if [ -f "$UPDATE_LOCK" ]; then
return 0
fi
touch "$UPDATE_LOCK"
if update_from_backend; then
log "Auto-update: refreshed from backend"
elif update_from_git; then
log "Auto-update: refreshed from git"
else
log "Auto-update: failed"
fi
rm -f "$UPDATE_LOCK"
}
# ── STATUS ──
cmd_status() {
echo "IOC Updater Status:"
local version=$(get_current_version)
local last_ts=$(echo "$version" | cut -d'|' -f1)
local count=$(echo "$version" | cut -d'|' -f2)
local source=$(echo "$version" | cut -d'|' -f3)
if [ "$last_ts" = "0" ]; then
echo " Last update: never"
else
local last_date=$(date -d @"$last_ts" '+%Y-%m-%d %H:%M' 2>/dev/null || echo "$last_ts")
echo " Last update: $last_date"
fi
echo " Indicators: $count"
echo " Source: $source"
echo " Interval: $((IOC_UPDATE_INTERVAL / 3600))h"
echo " Backend: ${VIGIL_BACKEND_URL:-not configured}"
if needs_update; then
echo " Status: UPDATE DUE"
else
echo " Status: current"
fi
}
# ── DISPATCH ──
case "$1" in
update) cmd_update ;;
auto) cmd_auto ;;
status) cmd_status ;;
*)
echo "IOC Auto-Updater [WIP]"
echo "Usage: ioc_updater.sh {update|auto|status}"
echo ""
echo " update Manual IOC update (tries backend, then git)"
echo " auto Check if update needed and refresh if due"
echo " status Show update status and IOC stats"
;;
esac

312
vigil/lib/sms_honeypot.sh Executable file
View File

@@ -0,0 +1,312 @@
#!/system/bin/sh
# Vigil — SMS Honeypot / Location Spoofing
# When silent SMS probes arrive, responds with fake location data
# (c) Setec Labs
#
# THEORY:
# Silent SMS (Type-0, Class-0) are used to confirm a SIM is active and
# triangulate location via cell towers. The delivery receipt itself reveals
# the device is on and which tower it's connected to.
#
# This module:
# 1. Detects incoming silent SMS probes
# 2. Activates mock GPS to spoof a fake location
# 3. Optionally reconnects to a different cell tower
# 4. Then allows the delivery receipt to go through with false data
#
# The attacker gets a response, but it points to the wrong location.
# This is better than blocking (which reveals the block) — it feeds
# disinformation to the adversary.
VIGIL_DATA="/data/adb/vigil"
VIGIL_LOG="$VIGIL_DATA/vigil.log"
ALERT_DIR="$VIGIL_DATA/alerts"
HONEYPOT_CONF="$VIGIL_DATA/honeypot.conf"
HONEYPOT_LOG="$VIGIL_DATA/honeypot.log"
[ -f "$VIGIL_DATA/vigil.conf" ] && . "$VIGIL_DATA/vigil.conf"
# Default fake locations (world capitals — far from likely real position)
# Format: lat,lon,name
FAKE_LOCATIONS="
48.8566,2.3522,Paris
35.6762,139.6503,Tokyo
-33.8688,151.2093,Sydney
55.7558,37.6173,Moscow
-22.9068,-43.1729,Rio de Janeiro
51.5074,-0.1278,London
40.4168,-3.7038,Madrid
52.5200,13.4050,Berlin
37.5665,126.9780,Seoul
19.4326,-99.1332,Mexico City
"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [honeypot] $1" >> "$VIGIL_LOG"
}
alert() {
local severity="$1"
local message="$2"
local timestamp=$(date +%s)
echo "${severity}|${timestamp}|sms_honeypot|${message}" >> "$ALERT_DIR/pending"
log "ALERT [$severity]: $message"
}
# Load user-defined fake location or pick random
get_fake_location() {
# Check for user-defined location
if [ -f "$HONEYPOT_CONF" ]; then
local user_lat=$(grep "^FAKE_LAT=" "$HONEYPOT_CONF" 2>/dev/null | cut -d= -f2)
local user_lon=$(grep "^FAKE_LON=" "$HONEYPOT_CONF" 2>/dev/null | cut -d= -f2)
if [ -n "$user_lat" ] && [ -n "$user_lon" ]; then
echo "$user_lat $user_lon user_defined"
return
fi
fi
# Pick a random location from the list
local count=$(echo "$FAKE_LOCATIONS" | grep -c ",")
local random_idx=$(( $(head -c4 /dev/urandom | od -An -tu4 | tr -d ' ') % count + 1 ))
local location=$(echo "$FAKE_LOCATIONS" | grep "," | sed -n "${random_idx}p" | tr -d ' ')
local lat=$(echo "$location" | cut -d, -f1)
local lon=$(echo "$location" | cut -d, -f2)
local name=$(echo "$location" | cut -d, -f3)
echo "$lat $lon $name"
}
# ── MOCK GPS: Set fake location via Android mock location provider ──
activate_mock_gps() {
local lat="$1"
local lon="$2"
local name="$3"
log "Activating mock GPS: $lat, $lon ($name)"
# Enable mock locations (requires developer options, but we have root)
settings put secure mock_location 1 2>/dev/null
# Use appops to allow our mock location provider
# We use Android's built-in test location capabilities
# Set the mock location via the location manager service
# Method 1: Use am command to set test provider
# Create a mock location provider
local accuracy=10 # meters
local altitude=50 # meters
local bearing=0
local speed=0
# Write mock location script that continuously feeds fake coordinates
local mock_script="$VIGIL_DATA/.mock_gps_active"
cat > "$mock_script" <<MOCKEOF
#!/system/bin/sh
# Mock GPS feeder — feeds fake location continuously
# Kill this script's PID to stop
while true; do
# Use Android's cmd location command (Android 12+)
cmd location providers add-test-provider gps requiresNetwork=false requiresSatellite=false requiresCell=false hasMonetaryCost=false supportsAltitude=true supportsSpeed=false supportsBearing=false powerRequirement=1 accuracy=1 2>/dev/null
cmd location providers set-test-provider-enabled gps true 2>/dev/null
cmd location providers set-test-provider-location gps --latitude $lat --longitude $lon --altitude $altitude --accuracy $accuracy 2>/dev/null
# Also try the legacy approach for older Android
am broadcast -a android.location.GPS_FIX_CHANGE --ef latitude $lat --ef longitude $lon 2>/dev/null
sleep 1
done
MOCKEOF
chmod 755 "$mock_script"
# Run mock GPS in background
nohup sh "$mock_script" >> "$HONEYPOT_LOG" 2>&1 &
local mock_pid=$!
echo $mock_pid > "$VIGIL_DATA/.mock_gps_pid"
log "Mock GPS active: PID $mock_pid, location: $lat, $lon ($name)"
echo "Mock GPS active: $lat, $lon ($name)"
}
# ── STOP MOCK GPS ──
deactivate_mock_gps() {
if [ -f "$VIGIL_DATA/.mock_gps_pid" ]; then
local pid=$(cat "$VIGIL_DATA/.mock_gps_pid")
kill "$pid" 2>/dev/null
rm -f "$VIGIL_DATA/.mock_gps_pid"
rm -f "$VIGIL_DATA/.mock_gps_active"
# Clean up test provider
cmd location providers remove-test-provider gps 2>/dev/null
settings put secure mock_location 0 2>/dev/null
log "Mock GPS deactivated"
echo "Mock GPS deactivated"
else
echo "Mock GPS not active"
fi
}
# ── HONEYPOT MONITOR: Watch for silent SMS and auto-spoof ──
cmd_monitor() {
log "SMS Honeypot monitor starting..."
echo "SMS Honeypot active — will spoof location on silent SMS detection"
# Clear logcat buffer
logcat -c 2>/dev/null
local spoof_active=0
local spoof_deactivate_time=0
logcat -s \
GsmInboundSmsHandler:* \
SmsMessage:* \
InboundSmsHandler:* \
RIL:* \
RILJ:* \
2>/dev/null | while read -r line; do
local now=$(date +%s)
# Check if we should deactivate spoof (after 5 minutes)
if [ $spoof_active -eq 1 ] && [ $now -gt $spoof_deactivate_time ]; then
deactivate_mock_gps
spoof_active=0
log "Auto-deactivated mock GPS after timeout"
fi
# Detect silent SMS
if echo "$line" | grep -qiE "type.?0.*sms|sms.*type.?0|class.?0|flash.*sms|TP-PID.*type"; then
alert "CRITICAL" "Silent SMS detected — activating location honeypot"
# Get fake location
local loc_data=$(get_fake_location)
local fake_lat=$(echo "$loc_data" | awk '{print $1}')
local fake_lon=$(echo "$loc_data" | awk '{print $2}')
local fake_name=$(echo "$loc_data" | awk '{print $3}')
echo "$(date '+%Y-%m-%d %H:%M:%S')|SPOOF|$fake_lat,$fake_lon|$fake_name" >> "$HONEYPOT_LOG"
# Activate mock GPS with fake location
if [ $spoof_active -eq 0 ]; then
activate_mock_gps "$fake_lat" "$fake_lon" "$fake_name"
spoof_active=1
fi
# Keep spoof active for 5 minutes (allow delivery receipt to go through with fake data)
spoof_deactivate_time=$((now + 300))
alert "INFO" "Location spoofed to: $fake_lat, $fake_lon ($fake_name)"
fi
done
}
# ── SPOOF NOW: Manually activate fake location ──
cmd_spoof() {
local loc_data=$(get_fake_location)
local fake_lat=$(echo "$loc_data" | awk '{print $1}')
local fake_lon=$(echo "$loc_data" | awk '{print $2}')
local fake_name=$(echo "$loc_data" | awk '{print $3}')
activate_mock_gps "$fake_lat" "$fake_lon" "$fake_name"
}
# ── SPOOF WITH SPECIFIC LOCATION ──
cmd_spoof_location() {
local lat="$1"
local lon="$2"
if [ -z "$lat" ] || [ -z "$lon" ]; then
echo "Usage: sms_honeypot.sh spoof-at <latitude> <longitude>"
return 1
fi
activate_mock_gps "$lat" "$lon" "custom"
}
# ── CONFIGURE: Set persistent fake location ──
cmd_configure() {
echo "SMS Honeypot Configuration"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "Current fake location:"
if [ -f "$HONEYPOT_CONF" ]; then
local lat=$(grep "^FAKE_LAT=" "$HONEYPOT_CONF" 2>/dev/null | cut -d= -f2)
local lon=$(grep "^FAKE_LON=" "$HONEYPOT_CONF" 2>/dev/null | cut -d= -f2)
if [ -n "$lat" ]; then
echo " Custom: $lat, $lon"
else
echo " Random (from world capitals list)"
fi
else
echo " Random (from world capitals list)"
fi
echo ""
echo "To set a specific fake location:"
echo " echo 'FAKE_LAT=48.8566' > $HONEYPOT_CONF"
echo " echo 'FAKE_LON=2.3522' >> $HONEYPOT_CONF"
echo ""
echo "Or use: vigil honeypot spoof-at <lat> <lon>"
echo ""
echo "Mock GPS status:"
if [ -f "$VIGIL_DATA/.mock_gps_pid" ]; then
local pid=$(cat "$VIGIL_DATA/.mock_gps_pid")
if kill -0 "$pid" 2>/dev/null; then
echo " ACTIVE (PID: $pid)"
else
echo " Stale PID file (not running)"
fi
else
echo " Inactive"
fi
}
# ── STATUS ──
cmd_status() {
echo "SMS Honeypot Status:"
echo " SMS Fake Response: ${SMS_FAKE_RESPONSE:-0}"
if [ -f "$VIGIL_DATA/.mock_gps_pid" ]; then
local pid=$(cat "$VIGIL_DATA/.mock_gps_pid")
if kill -0 "$pid" 2>/dev/null; then
echo " Mock GPS: ACTIVE (PID: $pid)"
else
echo " Mock GPS: inactive (stale PID)"
fi
else
echo " Mock GPS: inactive"
fi
if [ -f "$HONEYPOT_LOG" ]; then
local spoof_count=$(grep -c "SPOOF" "$HONEYPOT_LOG" 2>/dev/null)
echo " Spoofs triggered: $spoof_count"
echo " Last spoof:"
tail -1 "$HONEYPOT_LOG" 2>/dev/null | while read -r line; do
echo " $line"
done
fi
}
# ── DISPATCH ──
case "$1" in
monitor) cmd_monitor ;;
spoof) cmd_spoof ;;
spoof-at) shift; cmd_spoof_location "$@" ;;
stop) deactivate_mock_gps ;;
configure) cmd_configure ;;
status) cmd_status ;;
*)
echo "SMS Honeypot — Location Spoofing Defense"
echo "Usage: sms_honeypot.sh {monitor|spoof|spoof-at|stop|configure|status}"
echo ""
echo " monitor Auto-spoof on silent SMS detection"
echo " spoof Activate mock GPS with random location"
echo " spoof-at <lat> <lon> Activate mock GPS at specific coordinates"
echo " stop Deactivate mock GPS"
echo " configure Show/edit honeypot configuration"
echo " status Show honeypot status"
;;
esac