A customer forwards an APK supplied by a caller impersonating a bank's fraud department. A threat intelligence channel publishes a package name that impersonates an institution's mobile banking application. An employee installs a file delivered through a smishing campaign framed as a mandatory update.
In each case the SOC faces the same question, and it is not whether the sample is malware. It is whether the organisation should act, and on what evidence.
This document sets out a static triage workflow: a defensible classification plus a set of indicators suitable for detection, produced without a device, an emulator or a laboratory environment.
Scope of triage
Triage answers four questions in sequence:
- Is the application what it claims to be?
- What capabilities does the manifest request?
- Is the code concealing its function?
- What infrastructure does it contact?
Triage does not establish the full attack chain or the operator's post-compromise activity. Those are reverse-engineering objectives, and conflating the two is the principal cause of backlog in mobile triage queues.
A practical boundary: where a classification has not been reached within approximately ten minutes of analyst time, the sample belongs in a reverse-engineering queue rather than a triage queue. Triage is the process that determines which.
Sample handling
Unknown APKs are treated as live malware throughout.
- Analysis is performed in an isolated environment. Triage samples are never installed on a device holding credentials or connected to a production network.
- The SHA-256 is recorded before any other step. It is the only stable identifier the sample carries; package names, application labels and icons are all attacker-controlled.
- The binary is not redistributed. Hashes and indicators are shared; the sample itself is not. Sample-sharing arrangements are a legal question rather than a technical one.
- Provenance is recorded. The same APK recovered from a customer handset and obtained from a public malware feed represent different incidents.
Step 1 — Identity verification
Analysis begins with the components an attacker must expose for the package to install at all.
Package name. The package is compared against the legitimate application's package on Google Play. Repackaged banking applications rarely reuse the exact package name; they use a near-match, a reordered domain, or a random string. A package name absent from Play whose application label corresponds to a known financial institution is sufficient grounds for escalation on its own.
Signing certificate. This is the strongest identity signal available in an APK. Four properties are examined:
- Signature scheme. v1-only signing on a modern application is anomalous. v2 and v3 are the norm.
- Certificate subject. A debug certificate (
CN=Android Debug) on an application presenting as a banking product is disqualifying. - Validity window. A certificate issued days before the sample appeared indicates a disposable campaign identity. A thirty-year self-signed certificate generally indicates default tooling, a pattern present in both malware and poorly maintained legitimate applications.
- Reuse. A certificate shared across ostensibly unrelated applications establishes campaign linkage, and is frequently the most productive pivot available from a single sample.
Play verification. Where the package exists on Play but the certificate does not match the Play-distributed certificate, the sample is a repackaged application. This is a fraud incident rather than a malware finding, and it belongs with the brand protection function immediately.
In Droidwatch these outputs resolve before the remainder of the analysis completes.
Step 2 — Manifest analysis
Permissions constitute a statement of intended capability. For triage purposes, what an application is able to do is usually sufficient.
Permissions that warrant close reading:
| Permission | Significance |
|---|---|
BIND_ACCESSIBILITY_SERVICE |
The highest-signal permission in Android malware. Accessibility services read screen content and inject input, which is the basis of overlay attacks and on-device fraud. |
SYSTEM_ALERT_WINDOW |
Draws over other applications. Combined with accessibility, this is the standard overlay-phishing pairing. |
RECEIVE_SMS / READ_SMS |
OTP interception. In a banking context this should be treated as the application's purpose until established otherwise. |
BIND_NOTIFICATION_LISTENER_SERVICE |
Reads notification content, including one-time codes that never reach the SMS database. |
REQUEST_INSTALL_PACKAGES |
Installs further applications. This is the defining characteristic of a dropper. |
BIND_DEVICE_ADMIN |
Resists uninstallation; can lock or wipe the device. |
QUERY_ALL_PACKAGES |
Enumerates installed applications, typically to select the appropriate banking overlay. |
A single dangerous permission is a question. BIND_ACCESSIBILITY_SERVICE combined with SYSTEM_ALERT_WINDOW and QUERY_ALL_PACKAGES is the established capability set of an Android banking trojan.
Components are read alongside permissions:
- Exported components. An exported
ServiceorBroadcastReceiverwithout a permission guard is attack surface, including in legitimate applications. RECEIVE_BOOT_COMPLETEDreceivers. Persistence across reboot.android:debuggable="true"in a release build. Either careless malware construction or a significant defect in a legitimate application.android:allowBackup="true"in combination with sensitive local storage.- Cleartext traffic.
cleartextTrafficPermitted="true"or a permissivenetworkSecurityConfigindicates inspectable traffic, and constitutes a MASVS-NETWORK failure.
Step 3 — Code concealment
The objective at this stage is not to read the code but to establish whether the code is constructed to resist reading.
- Obfuscation. Identifier mangling alone is unremarkable; most release builds ship through R8 or ProGuard. String encryption, reflective class loading and control-flow flattening are not expected in a banking application.
- Dynamic code loading.
DexClassLoader,PathClassLoaderover a file retrieved at runtime, or a payload decrypted from assets. This is the dropper pattern: the submitted APK is the delivery mechanism rather than the malware. - Native libraries. A shared object in an application with no plausible requirement for native code warrants a note. Packers frequently conceal the payload behind a native unpacking stub.
- Asset blobs. Large encrypted or high-entropy files in
assets/that the manifest does not account for.
A sample exhibiting heavy obfuscation, runtime code loading and REQUEST_INSTALL_PACKAGES can be classified without reading a single method.
Step 4 — Infrastructure extraction
All hardcoded endpoints are extracted: URLs, bare IP addresses, domains present in string tables, and, where the configuration is encrypted, the decrypted configuration.
The relevant outputs are:
- C2 endpoints and the surrounding protocol pattern.
- Domain age and registration. A domain registered in the preceding week serving an application that impersonates a long-established institution is itself a conclusive finding.
- Telegram bot tokens, dead-drop URLs and hardcoded chat identifiers. Low-sophistication campaigns rely on these consistently, and they pivot readily.
- Infrastructure reuse. A single IP address serving several unrelated APK families indicates a campaign rather than a coincidence.
These indicators are the component of triage that reaches the detection stack. A classification protects one customer; a C2 domain entered into a DNS blocklist protects every user behind it. Droidwatch emits them as a STIX 2.1 bundle so that the transition from sample to detection rule does not require manual transcription.
Step 5 — Framework mapping
Mapping is what makes a mobile finding legible to stakeholders who never examine the sample.
Techniques encountered repeatedly in this class of sample:
| Behaviour | MITRE ATT&CK Mobile |
|---|---|
| Overlay screens capturing credentials | T1417.002 — GUI Input Capture |
| Keylogging via accessibility services | T1417.001 — Keylogging |
| Automated input for on-device fraud | T1516 — Input Injection |
| SMS reading or interception | T1582 — SMS Control |
| Notification access | T1517 — Access Notifications |
| Harvesting contacts, call logs and messages | T1636 — Protected User Data |
| Device administrator escalation | T1626.001 — Device Administrator Permissions |
| Security tooling evasion | T1629 — Impair Defenses |
| Packing or string encryption | T1406.002 — Software Packing |
| Persistence across reboot | T1624.001 — Broadcast Received |
| Second-stage payload retrieval | T1544 — Ingress Tool Transfer |
| Encrypted command-and-control channel | T1521 — Encrypted Channel |
For application security functions, the same findings map to OWASP MASVS categories: MASVS-NETWORK for cleartext transmission and pinning failures, MASVS-STORAGE for exposed local data, MASVS-CODE for dynamic loading, MASVS-RESILIENCE for anti-tampering deficiencies. MASTG supplies the corresponding test procedure where a result must be demonstrated.
Droidwatch produces both mappings on every run, alongside a classifier signal measured at F1 macro 0.9873 on a 1,661-sample holdout, trained on 6,642 samples from CICMalDroid 2020. The classifier contributes to the verdict; the findings above are what a report defends.
Step 6 — Classification and escalation
Droidwatch scores risk from 0 to 100, where a higher score indicates greater risk. Four outcomes, each with a defined owner:
| Verdict | Score | Definition | Routing |
|---|---|---|---|
| Malicious | 65 and above | Identified family, or a capability set with no legitimate interpretation | Incident response immediately; indicators to the SIEM |
| High Risk | 40–64 | Dangerous capabilities with identity anomalies; family unconfirmed | Incident ticket plus reverse-engineering queue |
| Suspicious | 20–39 | Anomalies without a coherent malicious pattern; frequently adware or a poorly constructed legitimate application | Watchlist; re-analyse on recurrence |
| Benign | Below 20 | Nothing beyond the norm for the application category | Close with the report attached |
The artefact matters more than the label. A report stating "malicious" is an assertion. A report containing the hash, the certificate analysis, the permission set, the C2 domains, the ATT&CK mapping and the reasoning behind the score is evidence, and evidence is what withstands review weeks later. Droidwatch exports this as PDF, DOCX, JSON, CSV or STIX 2.1.
Limitations of static triage
- Static analysis establishes capability, not behaviour. An application able to intercept SMS may never do so, or may do so only on instruction from its C2. Where a decision depends on runtime behaviour, dynamic analysis is required.
- Encrypted configuration may not yield. Some packers require execution. Where configuration extraction fails, the report states so rather than implying the absence of findings.
- Droidwatch dynamic analysis is Android-only and executes against the customer's own device or emulator, connected through the Droidwatch agent. No sample executes on Droidwatch infrastructure. This is the intended design for organisations that cannot submit customer-supplied samples to a third-party sandbox, and it requires configuration on the customer side. It is available from the Pro plan.
- iOS analysis is static only. Seven modules run against an
.ipa: Mach-O binary analysis,Info.plist, entitlements, App Transport Security configuration, class-dump, linked frameworks and declared privacy manifests. No iOS runtime instrumentation exists on any plan.
Executing the workflow on the platform
The six steps above describe the analytical process. The mechanics are a single submission:
- Submit the
.apk(or.xapk,.aab,.dex,.ipa) to the analyser. A 50 MB APK completes in two to five minutes; packages above 100 MB average eight to ten. - Review the report: verdict and score, findings ranked by severity, certificate and Play comparison, ATT&CK Mobile mapping, MASVS coverage, extracted indicators.
- Export in the format the recipient requires — STIX 2.1 for the SIEM, PDF or DOCX for the incident record.
At volume the workflow runs through the API: POST /api/upload returns an upload_id; POST /api/analyze returns a job_id and a run_id; GET /api/jobs/{job_id} is polled until the status is done or failed; the report is retrieved from GET /api/runs/{run_id}/artifact/report.json. Authentication accepts an X-API-Key header or a bearer token. Where a file has been analysed previously the response carries cached: true with a null job_id, and no polling is required. The quickstart documents the full sequence.
Frequently asked questions
How long should APK triage take? Approximately ten minutes of analyst time to reach a classification. Samples that consistently exceed this belong in a reverse-engineering queue.
Is VirusTotal sufficient for this workflow? VirusTotal answers whether a hash has been observed and how participating engines classified it, and is the appropriate first lookup. It does not provide the permission set, certificate anomalies, ATT&CK mapping or the reasoning required to produce an incident report. The two tools occupy different positions in the workflow. A detailed comparison is available.
Why not operate MobSF directly? MobSF is a capable analysis engine and a significant part of the mobile security discipline was established on it. The cost is operational rather than analytical: container orchestration, worker scaling, dependency maintenance, and the absence of multi-tenancy, role-based access control and audit logging in multi-client environments. The full comparison documents the trade-off.
What is the outcome when a sample proves benign? A signed report establishing that conclusion, produced in ten minutes. Negative results are a necessary output of any triage process.
Indicators from samples analysed on the platform are published in the public threat feed under CC BY 4.0. Handling and disclosure practices are documented on the trust page.