Android Stalkerware and Malware Triage with MVT
Triage an Android phone for stalkerware and spyware: sideloaded APKs, accessibility, notification access, device admin, permissions, and MVT with androidqf.
Most Android surveillance tools, from commercial stalkerware sold to jealous partners to banking trojans, do not need an exploit. They need a few minutes with an unlocked phone and a user (or someone else) willing to tap Allow on the right screens: install from unknown sources, accessibility, notification access, device admin, background location. Each of those grants is recorded on the device, which makes triage efficient if you know where to look. This guide gives a practical order of work, from a safe collection to a reviewed shortlist of suspicious apps, using MVT and androidqf plus manual checks.
Nation-state spyware that uses zero-click exploits is a different problem. MVT was built for it and will check published indicators, but a negative result there is weaker evidence; involve specialists when that threat model applies.
Safety and scope first
Stalkerware cases often involve domestic abuse. Removing the app, or even connecting the phone to a computer, can be visible to the person who installed it and can escalate risk. Before touching the device:
- Agree with the device owner (and, where relevant, a support organisation) what will be done and when.
- Decide whether the goal is evidence, removal, or both, and in which order.
- Keep the phone's current state: do not uninstall, disable admins or revoke permissions until collection is complete and the owner has decided.
- Record what you change: enabling Developer options and USB debugging, accepting the RSA key, installing nothing else.
Step 1: collect with androidqf
androidqf ("Android Quick Forensics", from the MVT project) is a small binary that runs on the examiner's computer and collects everything MVT needs over ADB, without installing anything permanent on the phone:
- Package list with installers, first install and update times.
- APKs of non-system apps (optionally all), with hashes.
dumpsysoutput for many services (package, appops, accessibility, device policy, notification, activity, battery).- System settings, properties, running processes, a file listing of shared storage.
- A bugreport, and logcat.
# On the examiner machine, with the phone unlocked and USB debugging authorised
./androidqf # follow the prompts; output goes to a timestamped folder
sha256sum -b androidqf_*/* > androidqf_SHA256SUMS
If androidqf is unavailable, collect manually: pm list packages -f -i -U, dumpsys package, dumpsys appops, dumpsys accessibility, dumpsys device_policy, dumpsys notification, settings list secure|global|system, getprop, and adb bugreport. The bugreport and dumpsys guide lists what each contains.
Step 2: run MVT
The Mobile Verification Toolkit analyses the collection against indicators of compromise (STIX2 files) and heuristics:
pip install mvt
mvt-android download-iocs # fetch public indicator sets
mvt-android check-androidqf -o mvt_out/ androidqf_2026-09-30_101500/
# or, from a bugreport alone
mvt-android check-bugreport -o mvt_out_br/ bugreport.zip
Useful indicator sources include the Echap stalkerware indicators (packages, certificates, domains for known commercial stalkerware) and the Amnesty and Citizen Lab indicators for mercenary spyware. MVT writes JSON results and flags detected items; it also lists apps with risky permissions, apps installed from outside a store, and suspicious settings, which feed the manual review.
A clean MVT result means "no known indicator matched". It does not clear an unknown app.
Step 3: review special access grants
These are the grants stalkerware almost always needs. Check each list and ask the owner about every entry they do not recognise.
Accessibility services
adb shell settings get secure enabled_accessibility_services
adb shell dumpsys accessibility | grep -iA3 'enabled services'
An enabled service can read the screen and act on it. Legitimate users include password managers, automation apps, launchers and screen readers. Details and dating methods are on the accessibility and device admin page.
Notification listeners
adb shell settings get secure enabled_notification_listeners
A listener receives every notification, including message previews and one-time codes. Smartwatch companion apps and some launchers use this legitimately.
Device admin and device owner
adb shell dumpsys device_policy | grep -iE 'admin|owner'
An active admin can resist uninstallation. A device owner on a personal phone is unusual and powerful. Do not deactivate anything yet: a wipe policy could be triggered, and the grant is evidence.
Runtime permissions and App Ops
adb shell dumpsys package com.suspect.pkg | grep -A60 'runtime permissions:'
adb shell cmd appops get com.suspect.pkg
Look for background location, microphone, camera, SMS, call log and contacts on an app that has no reason to need them, and for special accesses such as usage stats, overlay (SYSTEM_ALERT_WINDOW) and install packages. App Ops shows the last access time for each operation; compare it with usagestats to see whether access happened while the app was never on screen. See runtime permissions and appops.
Step 4: find sideloaded and disguised packages
Most stalkerware is not on Google Play; it is installed from a browser download or a file manager.
adb shell pm list packages -3 -i -f -U > third_party.txt # third-party apps with installer
grep -v 'installer=com.android.vending' third_party.txt
For each package not installed by a store, look at:
- Installer and initiator. In packages.xml on Android 11+,
installInitiatornames the browser or file manager. Match it to a download in Chrome or Samsung Internet history. - Name and icon. Generic names ("System Service", "Wi-Fi Update", "Sync Services") and launcher icons that are hidden or disabled.
- Signing certificate. A package pretending to be a Google or OEM component but signed with an unknown certificate is an impostor. See APK signing.
- Install time. Correlate with the time the owner lost physical control of the phone.
- Restricted settings (Android 13+). Sideloaded apps cannot get accessibility or notification access until the user taps Allow restricted settings in the app's info page. If a sideloaded app holds accessibility on Android 13+, someone went through that extra step.
Step 5: look at behaviour over time
Grants show capability; behaviour shows use.
- Usage. usagestats: a surveillance app rarely comes to the foreground except during setup. Its only
ACTIVITY_RESUMEDevents cluster around install time, next to Settings screens for accessibility and device admin. - Background work. Battery history: constant wakelocks, jobs and mobile data for one UID.
- Notifications. Notification history: stalkerware sometimes posts a persistent foreground-service notification with a bland title.
- Network. Domains in the APK's code or preferences, DNS or proxy logs from the network, and the MVT indicator match on domains.
- Accounts. An unexpected account type in the accounts databases, or an added Google account used to track the phone.
Step 6: analyse the APK
For any app you cannot explain, pull its APK and analyse it offline:
adb shell pm path com.suspect.pkg
adb pull /data/app/~~abc==/com.suspect.pkg-xyz==/base.apk suspect.apk
apksigner verify --print-certs suspect.apk
sha256sum suspect.apk
- jadx decompiles to readable Java; look for the accessibility service class, command server URLs, SMS or call recording code.
- Apktool decodes the manifest and resources: requested permissions, services, receivers, hidden launcher activities.
- The hash can be checked against threat intelligence services and indicator lists. Consider the confidentiality of the case before uploading a sample to any public service.
Step 7: deeper extraction when needed
A full file system extraction adds the app's sandbox (its configuration, the queue of data waiting to be sent, logs), system logs, and files MVT cannot reach over ADB. It is worth it when the app is custom, when the case goes to court, or when mercenary spyware is suspected. Use the acquisition guide to choose the method, and keep the phone AFU.
Worked example: a hidden "System Service"
A phone owner reports that a former partner seems to know her movements and messages. Triage over ADB with androidqf and MVT gives:
- MVT matches nothing against public indicators, but lists one third-party app with SMS, call log, location, microphone and notification access.
- Package review:
com.android.sys.service, label "System Service", no launcher activity enabled, installercom.android.chrome,installInitiatorChrome, first install time on a Saturday evening three weeks earlier. - Signer: an unknown self-signed certificate, not Google's or the OEM's, despite the
com.androidprefix. - Special access: an enabled accessibility service and a notification listener from that package; on this Android 14 phone, the restricted-settings App Op shows the override was granted.
- Browser history: Chrome shows a download of an APK from an unfamiliar domain two minutes before the install time.
- Usage: usagestats on the full extraction shows Settings accessibility and app info screens in the foreground in the minutes after install, then never the app itself.
- Behaviour: App Ops shows fine location and microphone accessed repeatedly in the last day; battery history shows constant jobs and mobile data for its UID.
The APK is then analysed offline (jadx shows an accessibility service that reads WhatsApp and Signal screens and a command server domain). The report describes the app's capabilities, the evidence of its installation and configuration on a specific evening, and its recent activity; it does not name who installed it, which is for the investigation to establish from other evidence (who had access to the phone at that time).
Common false positives
- Password managers, automation tools (Tasker, MacroDroid) and accessibility helpers with accessibility enabled.
- Smartwatch and fitness companions with notification access.
- Company management (MDM) as device owner or profile owner on work phones.
- Carrier and OEM apps with extensive permissions preinstalled as system apps.
- Parental control apps installed openly by a parent: legitimate in one context, abusive in another. The technical finding is the same; the report should describe capability and configuration, not motive.
Reporting
- List every app with a special access grant, its installer, install time, signer and your assessment.
- Quote the MVT version, indicator sets and their dates.
- Describe what the app could do (capability) separately from what the evidence shows it did (use).
- Document every change made to the device and who decided on removal.
Checklist
- Plan safety and scope with the owner before touching the phone.
- Collect with androidqf (or manual dumps plus a bugreport), hash everything.
- Run MVT with current indicators.
- Review accessibility, notification listeners, device admin, permissions and App Ops.
- List sideloaded packages; check installer, signer, name, icon and install time.
- Correlate with usage, battery, notifications and browser downloads.
- Analyse unknown APKs offline; escalate to a full file system extraction when needed.