androdd - Decompile APKs and create CFG

androdd is a tool to create a decompiled version of an APK using the available decompilers.

Synopsis

usage: androdd.py [-h] [--version] [--input INPUT] --output OUTPUT
                  [--format FORMAT] [--jar] [--limit LIMIT]
                  [--decompiler DECOMPILER]
                  [file]

Decompile an APK and create Control Flow Graphs

positional arguments:
  file                  resources.arsc or APK to parse

optional arguments:
  -h, --help            show this help message and exit
  --version, -v         Print androguard version and exit
  --input INPUT, -i INPUT
                        resources.arsc or APK to parse (legacy option)
  --output OUTPUT, -o OUTPUT
                        output directory. If the output folder already exsist,
                        it willbe overwritten!
  --format FORMAT, -f FORMAT
                        Additionally write control flow graphs for each
                        method,specify the format for example png, jpg, raw
                        (write dot file), ...
  --jar, -j             Use DEX2JAR to create a JAR file
  --limit LIMIT, -l LIMIT
                        Limit to certain methods only by regex (default: '.*')
  --decompiler DECOMPILER, -d DECOMPILER
                        Use a different decompiler (default: DAD)

It also can generate control flow graphs (CFG) for each method using the graphviz format. The CFGs can be exported as image file directly.

Additionally to the decompiled classes in .java format, each method is given in a SMALI like format (.ag files)

All filenames are sanatized, so they should work on most operating systems and filesystems.

Examples

To get all CFG in png format and limit the processing only to a certain namespace, the following command can be used:

androdd.py -o outputfolder -f png -i someapp.apk --limit "^Lcom/elite/.*"

This will decompile the app someapp.apk into the folder outputfolder and limit the processing to all methods, where the classname starts with com.elite..

A CFG might look like this:

../_images/cfg_example.png

while the .ag file has this content:

# Lcom/elite/MainActivity;->wipeDirectory(Ljava/lang/String;)V [access_flags=private static]
#
# Parameters:
# - local registers: v0...v6
# - v7:java.lang.String
#
# - return:void

wipeDirectory-BB@0x0 : [ wipeDirectory-BB@0x16 wipeDirectory-BB@0x62 ]
    0       (00000000) new-instance         v0, Ljava/io/File;
    1       (00000004) invoke-direct        v0, v7, Ljava/io/File;-><init>(Ljava/lang/String;)V
    2       (0000000a) invoke-virtual       v0, Ljava/io/File;->listFiles()[Ljava/io/File;
    3       (00000010) move-result-object   v2
    4       (00000012) if-eqz               v2, +28
    0:55
    (Ljava/lang/Exception; -> 58 wipeDirectory-BB@0x58)

wipeDirectory-BB@0x16 : [ wipeDirectory-BB@0x1c wipeDirectory-BB@0x62 ]
    5       (00000016) array-length         v4, v2
    6       (00000018) if-lez               v4, +25
    0:55
    (Ljava/lang/Exception; -> 58 wipeDirectory-BB@0x58)

wipeDirectory-BB@0x1c : [ wipeDirectory-BB@0x20 ]
    7       (0000001c) array-length         v5, v2
    8       (0000001e) const/4              v4, 0
    0:55
    (Ljava/lang/Exception; -> 58 wipeDirectory-BB@0x58)

wipeDirectory-BB@0x20 : [ wipeDirectory-BB@0x24 wipeDirectory-BB@0x26 ]
    9       (00000020) if-lt                v4, v5, +3
    0:55
    (Ljava/lang/Exception; -> 58 wipeDirectory-BB@0x58)

wipeDirectory-BB@0x24 :
    10      (00000024) return-void
    0:55
    (Ljava/lang/Exception; -> 58 wipeDirectory-BB@0x58)

wipeDirectory-BB@0x26 : [ wipeDirectory-BB@0x36 wipeDirectory-BB@0x50 ]
    11      (00000026) aget-object          v3, v2, v4
    12      (0000002a) invoke-virtual       v3, Ljava/io/File;->isDirectory()Z
    13      (00000030) move-result          v6
    14      (00000032) if-eqz               v6, +f
    0:55
    (Ljava/lang/Exception; -> 58 wipeDirectory-BB@0x58)

wipeDirectory-BB@0x36 : [ wipeDirectory-BB@0x4a ]
    15      (00000036) invoke-virtual       v3, Ljava/io/File;->toString()Ljava/lang/String;
    16      (0000003c) move-result-object   v6
    17      (0000003e) invoke-static        v6, Lcom/elite/MainActivity;->wipeDirectory(Ljava/lang/String;)V
    18      (00000044) invoke-virtual       v3, Ljava/io/File;->delete()Z
    0:55
    (Ljava/lang/Exception; -> 58 wipeDirectory-BB@0x58)

wipeDirectory-BB@0x4a : [ wipeDirectory-BB@0x20 ]
    19      (0000004a) add-int/lit8         v4, v4, 1
    20      (0000004e) goto                 -17
    0:55
    (Ljava/lang/Exception; -> 58 wipeDirectory-BB@0x58)

wipeDirectory-BB@0x50 : [ wipeDirectory-BB@0x4a ]
    21      (00000050) invoke-virtual       v3, Ljava/io/File;->delete()Z
    22      (00000056) goto                 -6

wipeDirectory-BB@0x58 : [ wipeDirectory-BB@0x24 ]
    23      (00000058) move-exception       v1
    24      (0000005a) invoke-virtual       v1, Ljava/lang/Exception;->printStackTrace()V
    25      (00000060) goto                 -1e

wipeDirectory-BB@0x62 : [ wipeDirectory-BB@0x24 ]
    26      (00000062) invoke-virtual       v0, Ljava/io/File;->delete()Z
    27      (00000068) goto                 -22
    62:67
    (Ljava/lang/Exception; -> 58 wipeDirectory-BB@0x58)