A friend messaged me last month convinced her Android phone was compromised — battery draining fast, weird pop-ups, a mystery app she didn’t remember installing. Instead of walking her through a sketchy “cleaner” app from the Play Store, I plugged her phone into my laptop and ran a set of ADB commands that gave us a real answer in about ten minutes. That experience is why I put together this guide: a practical, transparent ADB-based malware scanning approach anyone comfortable with a terminal can use in 2025.
Why Use ADB for Malware Scanning?
Android Debug Bridge (ADB) gives you a direct, low-level view into a device’s installed packages, running processes, and permissions — without needing root access for most checks. Unlike opaque “antivirus” apps that run inside the same sandboxed environment as potential malware, ADB inspection happens from a connected computer, giving you visibility that’s harder for malicious apps to hide from or tamper with.
Prerequisites
- Android SDK Platform Tools installed (provides the
adbbinary) — download here. - USB debugging enabled on the target device (Settings → About Phone → tap “Build Number” 7 times → Developer Options → enable USB Debugging).
- A USB cable and, ideally, the device unlocked with the ADB authorization prompt accepted.
# Verify ADB is installed and device is connected
adb version
adb devices
Expected output should list your device’s serial number with status device (not unauthorized — if unauthorized, check the phone screen for the RSA key confirmation prompt).
Manual ADB Commands for Malware Triage
Before scripting everything, it’s worth understanding the individual commands doing the work.
# List all installed packages, including system apps
adb shell pm list packages -f
# List only third-party (user-installed) apps — most malware lands here
adb shell pm list packages -3
# Get detailed info about a specific suspicious package
adb shell dumpsys package com.suspicious.app
# Check permissions granted to a specific app
adb shell dumpsys package com.suspicious.app | grep -A 20 "runtime permissions"
# View currently running processes
adb shell ps -A
# Check for apps with the DEVICE_ADMIN or Accessibility Service permission (common malware persistence tactic)
adb shell dumpsys device_policy
adb shell settings get secure enabled_accessibility_services
# Pull an APK off the device for offline analysis
adb shell pm path com.suspicious.app
adb pull /data/app/~~randomstring==/com.suspicious.app-randomstring/base.apk ./suspicious.apk
Building a Reusable ADB Malware Scanner Script
Below is a practical Bash script that automates the common red flags: sideloaded apps, excessive permissions, accessibility service abuse, and apps disguised with misleading names. This isn’t a replacement for a full malware analysis lab, but it’s an excellent triage tool.
#!/usr/bin/env bash
# adb_malware_scan.sh — Basic Android malware triage via ADB
# Usage: ./adb_malware_scan.sh
set -euo pipefail
echo "=== ADB Malware Scanner (2025) ==="
if ! command -v adb &> /dev/null; then
echo "[!] adb not found. Install Android SDK Platform Tools first."
exit 1
fi
DEVICE_COUNT=$(adb devices | grep -c "device$" || true)
if [ "$DEVICE_COUNT" -lt 1 ]; then
echo "[!] No authorized device found. Check USB debugging and confirm the RSA prompt on-device."
exit 1
fi
OUTPUT_DIR="adb_scan_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$OUTPUT_DIR"
echo "[*] Listing third-party installed packages..."
adb shell pm list packages -3 | sed 's/package://' | sort > "$OUTPUT_DIR/user_apps.txt"
echo " Found $(wc -l < "$OUTPUT_DIR/user_apps.txt") user-installed apps."
echo "[*] Checking accessibility services (common persistence/abuse vector)..."
adb shell settings get secure enabled_accessibility_services > "$OUTPUT_DIR/accessibility_services.txt"
cat "$OUTPUT_DIR/accessibility_services.txt"
echo "[*] Checking device admin apps (used by some ransomware/spyware to resist uninstall)..."
adb shell dumpsys device_policy | grep -i "admin" > "$OUTPUT_DIR/device_admins.txt" || true
cat "$OUTPUT_DIR/device_admins.txt"
echo "[*] Scanning each user app for high-risk permission combinations..."
{
echo "package,sms,accessibility,overlay,admin,contacts"
while read -r pkg; do
perms=$(adb shell dumpsys package "$pkg" | grep -E "android.permission" || true)
sms=$(echo "$perms" | grep -c "RECEIVE_SMS\|SEND_SMS" || true)
acc=$(echo "$perms" | grep -c "BIND_ACCESSIBILITY_SERVICE" || true)
overlay=$(echo "$perms" | grep -c "SYSTEM_ALERT_WINDOW" || true)
admin=$(echo "$perms" | grep -c "BIND_DEVICE_ADMIN" || true)
contacts=$(echo "$perms" | grep -c "READ_CONTACTS" || true)
echo "$pkg,$sms,$acc,$overlay,$admin,$contacts"
done < "$OUTPUT_DIR/user_apps.txt"
} > "$OUTPUT_DIR/permission_matrix.csv"
echo "[*] Flagging apps with 3+ high-risk permissions..."
awk -F',' 'NR>1 && ($2+$3+$4+$5+$6) >= 3 {print $1}' "$OUTPUT_DIR/permission_matrix.csv" > "$OUTPUT_DIR/flagged_apps.txt"
if [ -s "$OUTPUT_DIR/flagged_apps.txt" ]; then
echo "[!] Flagged high-risk apps requiring manual review:"
cat "$OUTPUT_DIR/flagged_apps.txt"
else
echo "[+] No apps matched the high-risk permission threshold."
fi
echo "[*] Results saved to: $OUTPUT_DIR/"
echo "=== Scan Complete ==="
Save this as adb_malware_scan.sh, make it executable with chmod +x adb_malware_scan.sh, and run it with the device connected.
Understanding the Scan Logic
flowchart TD
A[Connect Device via ADB] --> B[Enumerate Third-Party Packages]
B --> C[Query Permissions per Package]
C --> D{High-Risk Permission Combo?}
D -->|SMS + Accessibility + Overlay| E[Flag for Manual Review]
D -->|Device Admin without clear purpose| E
D -->|Normal permission profile| F[Mark as Likely Benign]
E --> G[Pull APK for Deeper Static Analysis]
G --> H[Analyze with VirusTotal / MobSF / Manual RE]
The scanner isn’t trying to definitively declare “malware found” — permission combinations alone are heuristic indicators, not proof. A legitimate SMS backup app will also request RECEIVE_SMS. The goal is to shrink hundreds of installed apps down to a manageable shortlist worth investigating further.
Deeper Analysis: What To Do With Flagged Apps
Once you have a shortlist, pull the APK and analyze it further:
# Pull the APK
apk_path=$(adb shell pm path com.suspicious.app | sed 's/package://')
adb pull "$apk_path" ./suspicious.apk
# Quick static triage with aapt (part of Android SDK build tools)
aapt dump badging suspicious.apk | grep -E "package|uses-permission"
# Check the APK's hash against VirusTotal (requires API key, or use the web UI)
sha256sum suspicious.apk
For genuinely thorough analysis, upload the APK hash (not necessarily the file, for privacy) to VirusTotal, or run it through MobSF (Mobile Security Framework), an open-source static/dynamic Android and iOS analysis platform that decompiles the APK and flags known malicious patterns, hardcoded secrets, and insecure configurations automatically.
Common Android Malware Indicators to Watch For
| Indicator | What It Suggests |
|---|---|
| App requests Accessibility Service without a clear accessibility purpose | Common technique for overlay attacks, keylogging, and auto-clicking malicious actions |
| App requests Device Admin rights | Often used by ransomware/spyware to resist uninstallation |
| App requests SMS read/send permissions but isn’t a messaging/2FA app | Possible SMS-based fraud (OTP interception, premium SMS abuse) |
| Package name mimics a legitimate app but isn’t from the official developer | Classic trojan/clone app technique |
| App was sideloaded (not from Play Store) and requests broad permissions | Higher risk profile; Play Store apps undergo at least baseline vetting |
| Excessive battery/data usage from an unfamiliar app | Possible background exfiltration or crypto-mining activity |
Extending the Scanner: Continuous Monitoring
The script above is designed for one-off triage, but the same building blocks can be adapted into a lightweight continuous monitoring setup for a device you manage regularly — useful for parents monitoring a child’s device, IT teams managing a small fleet of company Android devices, or anyone who wants ongoing visibility rather than a single snapshot.
#!/usr/bin/env bash
# adb_monitor_diff.sh — Detect newly installed apps since last scan
BASELINE="baseline_apps.txt"
CURRENT="current_apps.txt"
adb shell pm list packages -3 | sed 's/package://' | sort > "$CURRENT"
if [ ! -f "$BASELINE" ]; then
cp "$CURRENT" "$BASELINE"
echo "[*] Baseline created. Run again later to detect changes."
exit 0
fi
NEW_APPS=$(comm -13 "$BASELINE" "$CURRENT")
if [ -n "$NEW_APPS" ]; then
echo "[!] New apps detected since last scan:"
echo "$NEW_APPS"
else
echo "[+] No new apps since last baseline."
fi
cp "$CURRENT" "$BASELINE"
Running this on a schedule (via a cron job on the connected computer, whenever the device is plugged in for charging, for example) turns a reactive scan into an ongoing detection mechanism, catching new installs shortly after they happen rather than waiting for symptoms to appear weeks later.
Security Implications and Best Practices
- Never grant Accessibility Service access to apps unless you fully understand and trust why they need it — this permission is one of the most abused vectors in modern Android banking trojans.
- Regularly audit installed apps using
adb shell pm list packages -3, especially after installing anything outside the Play Store. - Keep Google Play Protect enabled, and treat it as one layer of defense, not the only one.
- Avoid sideloading APKs from unofficial sources unless you can verify their integrity and origin.
- Use ADB scanning as a periodic hygiene check, not just a reactive response after symptoms appear.
Interpreting Results Responsibly
A word of caution worth taking seriously: heuristic scanners like the one above will inevitably produce false positives. A legitimate password manager app requesting accessibility permissions to autofill fields, or a family locator app requesting SMS and location permissions, will show up on a flagged list without being malicious. Treat every flag as a prompt for further investigation, not an automatic verdict. The goal of this kind of tooling is to compress a large, unmanageable surface (every app and permission on a device) into a short, reviewable list — the judgment call about what’s actually malicious still belongs to a human who understands what each app is supposed to do and why.
It’s also worth keeping a personal record of what “normal” looks like for a device you monitor regularly. The first time you run this scanner on a device with dozens of apps installed, expect a noisy result set as you learn which apps legitimately need which permissions. Subsequent runs, especially when combined with the diff-based monitoring approach described above, become far more signal-rich once that baseline is established.
Common Mistakes
- Running the scanner once and assuming the device is permanently clean — malware can be installed at any time afterward.
- Ignoring flagged apps because “it’s probably fine,” without pulling and analyzing the APK.
- Forgetting that ADB access itself is a security-sensitive capability — never enable USB debugging permanently on a device you don’t control, and revoke authorized computers you no longer use (Settings → Developer Options → Revoke USB debugging authorizations).
- Assuming ADB scanning replaces the need for a mobile threat defense (MTD) solution in enterprise/BYOD environments.
When to Escalate Beyond Self-Scanning
There’s a point where DIY ADB scanning stops being sufficient and professional help becomes the right call: if you find evidence of financial fraud, if the device belongs to someone facing targeted harassment or stalking, if sensitive corporate data may have been exposed, or if the malware resists every removal attempt described here. In those cases, a proper digital forensics engagement — one that images the device before any further changes are made — preserves evidence in a way ad hoc scanning and cleanup does not, which matters both for law enforcement involvement and for understanding the true scope of what was accessed.
FAQs
Do I need root access to run this scanner? No — everything in this script works over standard ADB without root, since pm and dumpsys expose enough package and permission metadata for triage purposes.
Can this script detect all malware? No single heuristic-based tool can guarantee complete detection. This script is a triage aid to prioritize which apps deserve deeper analysis, not a definitive malware detector.
Is it safe to enable USB debugging just to run this scan? Yes, as long as you disable it again afterward and only authorize computers you trust, since USB debugging does expand the device’s attack surface while enabled.
What should I do if the scanner flags an app I don’t recognize? Uninstall it if you’re not certain of its origin (adb uninstall com.suspicious.app), especially if it has device admin or accessibility privileges you can’t explain.
Does this work on all Android versions? The core pm and dumpsys commands used here are broadly compatible across modern Android versions (Android 8 through the current 2025 releases), though exact output formatting can vary slightly by OEM and Android version.
Summary and Recommendations
ADB gives you a transparent, scriptable window into what’s actually installed and permissioned on an Android device — far more trustworthy than relying solely on an app running inside the same environment it’s trying to inspect. The scanner script above automates the tedious parts of that inspection, surfacing high-risk permission combinations worth a closer look. Pair it with periodic use, cautious sideloading habits, and deeper static analysis tools like MobSF for anything genuinely suspicious.
C:\adb>adb_malware_scanner.py
File “C:\adb\adb_malware_scanner.py”, line 72
f.write(“\n”.join(results[“apps”]) if results[“apps”] else “None found.”
^^^^^^^^^^^^^
SyntaxError: invalid syntax. Perhaps you forgot a comma?
I will correct it thanks for the notice.
Thanks!