Every suspicious APK raises the same operational question before any technical one: is it enough to read the file, or does the sample have to run?
Static analysis examines the package without executing it. Dynamic analysis installs the sample on an instrumented device and records what it does. The two are often presented as competing approaches, or as a maturity ladder in which dynamic analysis is the "advanced" step. Neither framing is useful. They answer different questions, they fail in different ways, and the decision to move from one to the other should rest on a specific gap in the evidence rather than on habit.
Each method establishes different facts and stops at a different point, and a practical rule decides when execution adds information that the file alone cannot provide.
Two methods, two different questions
Static analysis answers what the application is able to do. It reads the manifest, the signing certificate, the compiled bytecode, the native libraries and the embedded resources, and it reports capability: the permissions requested, the components exposed, the code paths present, the infrastructure referenced.
Dynamic analysis answers what the application actually did, on this device, during this run. It observes network connections, file writes, SMS access, decrypted strings and screen activity as they happen.
The distinction matters because the two claims carry different weight. A static finding such as "the application can read SMS" is true of every copy of that APK. A dynamic finding such as "the application read SMS and sent a one-time code to this domain" is true of one execution, under one set of conditions. It is stronger evidence of intent and weaker evidence of completeness.
What static analysis establishes
A well-constructed static pass covers most of what a triage decision requires, and it does so without exposing a device or a network to the sample.
Identity. The signing certificate, its validity window and its signature scheme, compared against the version distributed on Google Play. A banking application whose certificate does not match the Play-distributed certificate is a strong indicator of repackaging, and that finding does not depend on anything the code does.
Declared capability. Permissions and components in the manifest. BIND_ACCESSIBILITY_SERVICE combined with SYSTEM_ALERT_WINDOW and QUERY_ALL_PACKAGES is the established capability set of an overlay banking trojan, described in detail in how Android banking trojans work.
Concealment. String encryption, reflective class loading, packers and native unpacking stubs. Concealment does not reveal behaviour, but it is itself a signal, if not a conclusive one: commercial protectors used by many legitimate applications also encrypt code, so the finding is weighed alongside signing, permissions and provenance.
Supply chain. Third-party SDKs identified by signature. Droidwatch detects 87 SDKs this way and queries OSV.dev live for known vulnerabilities; OSV currently has data for 12 of those 87, because advertising and attribution SDKs are largely closed source.
Infrastructure. Hardcoded URLs, IP addresses, domains and, where the configuration can be decrypted statically, the command-and-control endpoints it contains.
Framework mapping. Findings mapped to MITRE ATT&CK Mobile techniques and to OWASP MASVS categories, so that the result is legible to people who never open the sample.
In Droidwatch this is a pipeline of 28 stages covering more than 25 independent analyses. A 50 MB APK completes in two to five minutes; packages above 100 MB average eight to ten. The narrative that summarises the report is produced by a rules engine rather than a language model: a phase of the attack chain appears in the narrative only when there are findings that support it.
Where static analysis stops
Static analysis establishes capability, and some samples are constructed so that capability on disk reveals very little.
- Dynamic code loading. A dropper ships a minimal APK and retrieves or decrypts the real payload at runtime through
DexClassLoaderor an equivalent. The submitted file is the delivery mechanism, not the malware. - Server-driven behaviour. Many banking trojans download their list of targeted applications and their overlay templates from the command-and-control server after installation. The APK contains the machinery; the targets arrive later.
- Encrypted configuration. Where the key is derived at runtime or fetched remotely, the C2 address may not be recoverable from the file. A good report states that extraction failed rather than implying that no infrastructure exists.
- Reflection and native code. Calls assembled from strings at runtime, or logic moved into a native library, obscure which code paths are real.
None of this invalidates a static verdict. A sample with heavy obfuscation, runtime code loading and REQUEST_INSTALL_PACKAGES can be classified as a dropper without executing it. What static analysis cannot supply in these cases is the second stage itself.
What dynamic analysis adds
Executing the sample under instrumentation fills precisely those gaps. Frida, the open-source dynamic instrumentation toolkit on which Droidwatch's dynamic analysis is built, attaches to the running process and hooks Java methods and native functions. In general, instrumentation of this kind allows an analyst to observe:
- the URLs the application actually contacts, including endpoints assembled at runtime;
- SMS and notification access as it occurs, not merely the permission to perform it;
- cryptographic keys and decrypted strings as they are built in memory;
- the screens the application draws, captured as screenshots;
- the network traffic of the session.
In Droidwatch, what reaches the report from a dynamic run is the Frida output, logcat, screenshots and the network capture.
For a dropper, execution is often the only practical route to the second stage. For a banking trojan with server-driven targeting, execution can reveal which institutions the current campaign is aimed at, provided the C2 infrastructure is still answering.
Where dynamic analysis stops
Dynamic analysis produces stronger evidence of behaviour, and it carries its own blind spots.
- Coverage. A run observes only the code paths that execute during that session. Functionality triggered by a specific command, a date, or a particular installed application may never activate.
- Evasion. Android malware routinely checks for emulators, root, debugging and instrumentation, and some families also check locale, SIM country or elapsed time before activating. A sample that detects the analysis environment can behave as a benign application for the entire run.
- Dependence on live infrastructure. If the C2 server is offline, a sample that depends on it may do nothing observable. An empty dynamic result is therefore weaker evidence of benignity than an empty static result.
- Interaction. Overlays typically fire only when a targeted application is opened. Without that trigger, the most important behaviour does not occur.
- Risk. The sample is live. It reaches whatever the device can reach, and it may attempt persistence.
Side-by-side comparison
| Static analysis | Dynamic analysis | |
|---|---|---|
| Question answered | What the APK is able to do | What it did during one run |
| Requires execution | No | Yes |
| Duration on Droidwatch | 2–5 minutes for 50 MB | Up to 300 s per run (Pro), 450 s (Team) |
| Handles packed or loaded code | Detects it; may not recover the payload | Can observe the payload once loaded |
| Affected by emulator evasion | No | Yes |
| Depends on live C2 | No | Often |
| Risk to the analysis environment | None | Real; requires isolation |
| Platforms on Droidwatch | Android and iOS | Android only |
| Plan on Droidwatch | All plans | From Pro |
Running dynamic analysis on your own emulator
Droidwatch's dynamic analysis executes against the customer's own device or emulator, connected through the Droidwatch agent. No sample executes on Droidwatch infrastructure; the hosted sandbox is not in production. The APK is uploaded for static analysis as usual; the execution itself happens only on the analyst's emulator, and what travels back to Droidwatch from that run is the result: Frida output, logcat, screenshots and the network capture, which then appear in the existing report.
The setup guide covers the full procedure. In outline:
- Install
adband the Frida command-line tools on the analysis machine. - Create an emulator from an image without Google Play.
frida-serverrequires root, and Play-enabled images are production-signed and do not allow it; agoogle_apisimage does. A retail phone is not suitable for the same reason. - Push a
frida-serverbuild to the emulator whose version matches the local Frida client exactly and whose architecture matches the emulator's ABI. - Create an API key with the
read + analyzescope. API keys and dynamic analysis both require the Pro plan or above. - Start the agent, upload the APK as usual, and choose My device in the Dynamic tab.
Because the run happens on the customer's machine rather than under Droidwatch's observation, the dynamic section of the report is labelled analyst-supplied, next to the analyst's name and the date.
The guide's safety rules apply to every run: never execute a sample on a personal phone, isolate the network the emulator can reach, and restore the emulator from a snapshot afterwards, since an uninstall does not remove persistence a sample may have established.
iOS analysis on Droidwatch is static only, across seven modules. No iOS runtime instrumentation exists on any plan.
A practical decision rule
Static analysis first, always. It is fast, it is safe, and for most triage decisions it is sufficient. The SOC triage workflow describes how to reach a classification from static evidence alone.
Dynamic analysis is justified when a specific question remains open and execution could answer it:
- the static report shows dynamic code loading and the second stage is needed for detection;
- the C2 configuration could not be extracted statically and the infrastructure is required for blocking;
- the decision depends on whether a capability is exercised, not merely present;
- the targeted institutions matter to the response and are delivered by the server.
When none of these apply, running the sample adds risk without adding evidence. When one does, a static report states which question is open, and the dynamic run is aimed at answering exactly that. The guide to the Droidwatch report shows where each of these signals appears.
Frequently asked questions
Is dynamic analysis more accurate than static analysis? Neither is more accurate in general. Static analysis is complete with respect to what the file contains; dynamic analysis is precise with respect to what one run did. Evasive samples defeat dynamic analysis; packed samples limit static analysis. Combining the two produces the strongest evidence.
Can malware detect that it is being analysed dynamically? Yes. Checks for emulators, root, debuggers and instrumentation frameworks are common in Android malware. An uneventful dynamic run is not proof that a sample is benign.
Why does the setup require a rooted emulator?
frida-server runs with elevated privileges inside the device in order to attach to other processes. Emulator images that include Google Play do not permit root, which is why the setup guide specifies a Google APIs image.
Where does the sample execute during Droidwatch dynamic analysis? On the analyst's own emulator. The APK is uploaded to Droidwatch as for any static analysis; from the execution, only the findings and artefacts reach the report. No sample executes on Droidwatch infrastructure.
Is dynamic analysis available for iOS?
No. Droidwatch analyses .ipa files statically, across seven modules, on every plan. There is no iOS runtime analysis.