dtu
is a toolkit for testing entire Android devices, without requiring root access. The goal is to collect as much data as possible from a generic Android device and store it in formats that are accessible via the command line tool or associated library.
You can install dtu
via nix
or with cargo
. The nix
install will provide you with all of the associated binaries, of which there are quite a few, at known compatible versions if you use the dtuEnv
package.
If you're installing with cargo
, ensure you have the sqlite
development libraries available and just do a simple cargo install
.
After installation, run dtu run-check
to see which required binaries you already have installed (if you used nix
and dtuEnv
, everything should already be available).
Note that dtu
currently is not developed with Windows support in mind.
dtu
allows for some configuration for all projects in the ~/.config/dtu/config.toml
file. This will let you specify your file store implementation which will be used for diffing dtu
runs of different projects. There are two potential ways to specify this either for S3 or your local file system.
Without this configured dtu
won't be able to diff, which will be discussed later.
Every project must specify the DTU_PROJECT_HOME
environmental variable. This is not optional and dtu
won't work without it. I highly recommend using direnv
and setting this in a .envrc
file at the base of your project directory and then forgetting about it. dtu
can even do this for you with dtu gen-envrc
.
Projects can be further configured with a file in $DTU_PROJECT_HOME/config.toml
. This file is documented in the example.
The tl;dr
for staring a project is:
# Pull all files -- this is a resource intensive operation and takes a while
dtu pull
# Populate the graph database. This is also resource intensive and takes a while, you can
# also just do `setup` which is faster but leaves out calls
dtu graph full-setup
# Set up the sqlite database, this is used for a lot of queries throughout the program.
# You can pass `--no-diff`, but emulator diffing is highly recommended.
dtu db setup
# Set up the test application
dtu app setup
# Install the test application on the device
dtu app install
Note this takes a long time: you are pulling, decompiling, and analyzing the device's Java framework in the setup. The first three commands are required for anything else dtu
does. The test application is not required for everything, but should be built and installed since the server is used for a lot of dtu
s functionality.
- Discovery - uses
adb
and some shell commands to find all files of interest. This finds, among other things,apk
,apex
, andjar
files containing framework and application code. - Pull - uses
adb pull
to pull the files off the device to a local file - Decompile - uses various tools to decompile files and convert them to
smali
for later analysis and reverse engineering
Parse the decompiled smali
files and create a Cozo graph database of the entire device's framework and every APK. This takes a while, but once done you are given an inheritance and call graph. dtu
provides some canned queries for this graph database, but it is often used behind the scenes even if you never query it directly. This database is also accessible via the dtu
crate. Note that previous versions of dtu
used Neo4j for the graph database, and some of this code still exists, but development on that halted over a year ago and work would likely need to be done to get it working again.
Set up the sqlite
database. This collects a lot of data from the device, some of which is pulled via adb
when this runs, and stores it for analysis or querying later. The database is saved in dtu_out/sqlite/device.db
and is crucial for diffing devices. If --no-diff
is not provided, this will use the configured file store to find the appropriate device.db
for an emulator at the same API level.
This will create a test application that is installed on the device. This application gives itself all normal level permissions (pulled out of the database just created) and runs a server that the dtu
command line tool interacts with quite a bit for some functionality.
After you're setup you can start actually using dtu
for analysis. How you do this is up to you, but we'll mention some useful tips here.
Note: when you open the diff TUI via dtu diff ui
, type ?
to get some basic help.
The dtu diff
subset of commands work based on diffs with a given "diff source". The primary diff source is an emulator, but it can be any arbitrary device that has previously been analyzed by dtu
and the device.db
saved. Diffing is very helpful and it is sometimes easiest to start your testing with dtu diff ui
and poking at things that are not standard AOSP features. Diffing isn't perfect, but it's a great start. To set up an emulator diff, run all of the dtu
setup steps against an emulator (use --no-diff
for the db setup and setup
instead of full-setup
for the graph db) and store that device.db
in your chosen file store implementation.
The diff UI also supports a few "hook" programs for quick analysis, to make use of them just make sure they're somewhere in your PATH
:
dtu-open-file
program /DTU_OPEN_EXECUTABLE
env var: When in the diff UI, you can often highlight something and hitO
to invoke this program to open the associated file. This program is executed with two arguments: the absolute file path and a "search hint".dtu-clipboard
program /DTU_CLIPBOARD_EXECUTABLE
env var: If you have something highlighted and hitc
, this will send adtu ...
command to interact with the highlighted item via the command line to this program onstdin
.
The command line tool will look for emulator databases in: ~/.local/share/dtu/aosp/{API_LEVEL}/device.db
or your given file store implementations aosp/{API_LEVEL}/device.db
.
Generally you're going to be interested in opening smali
files for reverse engineering and dtu
provides a pretty easy way to find the correct file for a given class: dtu open-smali-file
(this has an alias of dtu of
since it's fairly common to use). Personally I use a custom vim
plugin that may be open sourced as well one day for translating the given smali
file to Java using smali
and jadx
for easier reverse engineering.
The dtu
application provides a TCP server (dtu app start-server
and dtu app forward-server
) that allows you to interact with the device as if you were the application. This is very different from interacting with the device via adb
, which is typically a more privileged context. You may see subtle differences between adb shell service list
and dtu sh service list
due to SELinux context differences for example. Some of the commands for interacting with the device are:
dtu sh
- Run a shell commanddtu provider
- Perform a lot of different operations against providersdtu broadcast
- Send a broadcastdtu start-activity
- Start an activity via anIntent
dtu start-service
- Start a service via anIntent
dtu call
- Invoke a method on a Service via itsIBinder
, this works for system services and application services
Look around dtu --help
for more commands like these, as this documentation could get a bit stale at some point. Many of these commands can have their arguments pre-populated for you via dtu-clipboard
in the dtu diff ui
TUI.
The test application is intended to be modified and rebuilt over and over to run various tests that require Kotlin code to execute instead of the limited functionality provided by the command line tool. There are templates for different tests that can be generated with the dtu app new-*
commands, and tests can be run via the dtu app run-test ...
command.
dtu
can also work, somewhat hindered, based on file system dumps of Android devices. This is useful for cases where you don't have adb
access to the device but can otherwise obtain a full copy if its root file system. To use this feature, check out the example project configuration and specifically the device-access.dump
configuration and can-adb
value.
There are a few limitations due to the static nature of this testing, but it has proven useful in the past.
dtu
is a command line tool and a Rust crate. You can directly access the two databases, the test application server, and other potentially interesting features via this crate. The API should be stable across major releases. We try to maintain backwards compatibility when possible.