Thursday, March 3, 2011

DroidDream

Hi !

I am analyzing DroidDream with Androguard to check if I need other useful features (and the answer is YES :)), but I can show you how to use it quickly. Moreover it's always interesting to improve his own tool with real examples ;). (Lookout and Aegislab have already published quickly analysis.)

You can use the API or directly the ipython shell with androlyze :
$ ./androlyze.py -s
Androlyze version BETA 0

[~/androguard]
|2>
And now you open the APK, open the Dex and run the analysis to have more information :
[~/androguard]
|2>a = APK("./apks/DroidDream/Magic Hypnotic Spiral.apk" )

[~/androguard]
|3>vm = DalvikVMFormat( a.get_dex() )

[~/androguard]
|4>vmx = VM_BCA( vm )
We can check the AndroidManifest.xml to find entry points :

[~/androguard]
|5>a.get_permissions()
Out[5]:
['android.permission.READ_PHONE_STATE',
'android.permission.CHANGE_WIFI_STATE',
'android.permission.ACCESS_WIFI_STATE',
'android.permission.INTERNET']

[~/androguard]
|6>a.get_activity()
Out[6]: ['com.mikeperrow.spiral.SpiralActivity', 'com.android.root.main']

|7>a.get_receiver()
Out[7]: []

[~/androguard]
|8>a.get_service()
Out[8]: ['com.android.root.Setting', 'com.android.root.AlarmReceiver']

[~/androguard]
|9>a.zip.namelist()
Out[39]:
['META-INF/MANIFEST.MF',
'META-INF/ANDROID.SF',
'META-INF/ANDROID.RSA',
'assets/exploid',
'assets/profile',
'assets/rageagainstthecage',
'assets/sqlite.db',
'lib/armeabi/libandroidterm.so',
'res/drawable/icon.png',
'res/drawable/minispiral.png',
'res/layout/main.xml',
'AndroidManifest.xml',
'classes.dex',
'resources.arsc']



We can assume that "com.android.root.main", "com.android.root.Setting" and "com.android.root.AlarmReceiver" have been injected.

[~/androguard]
|13>vm.get_methods_class( FormatClassToDex("com.android.root.main") )[0].show()
ENCODED_METHOD method_idx_diff=106 access_flags=65537 code_off=0x3344 (Lcom/android/root/main; ()V,)
********************************************************************************
DALVIK_CODE :
REGISTERS_SIZE 0x1
INS_SIZE 0x1
OUTS_SIZE 0x1
TRIES_SIZE 0x0
DEBUG_INFO_OFF 0x8ca0
INSNS_SIZE 0x4

0 0x0 invoke-direct v0 , [meth@ 0 Landroid/app/Activity; () V ]
1 0x6 return-void
********************************************************************************

Ok, not interesting ....

[~/androguard]
|15>vm.get_methods_class( FormatClassToDex("com.android.root.main") )[1].show()
ENCODED_METHOD method_idx_diff=108 access_flags=1 code_off=0x335c (Lcom/android/root/main; (Landroid/os/Bundle;)V,onCreate)
********************************************************************************
DALVIK_CODE :
REGISTERS_SIZE 0x7
INS_SIZE 0x2
OUTS_SIZE 0x3
TRIES_SIZE 0x1
DEBUG_INFO_OFF 0x8ca5
INSNS_SIZE 0x28
ENCODED_CATCH_HANDLER_LIST size=0x1
ENCODED_CATCH_HANDLER size=0x1
ENCODED_TYPE_ADDR_PAIR 95 34

0 0x0 invoke-super v5 , v6 , [meth@ 1 Landroid/app/Activity; (Landroid/os/Bundle;) V onCreate]
1 0x6 new-instance v1 , [type@ 13 Landroid/content/Intent;]
2 0xa const-class v4 , [type@ 50 Lcom/android/root/Setting;]
3 0xe invoke-direct v1 , v5 , v4 , [meth@ 20 Landroid/content/Intent; (Landroid/content/Context; Ljava/lang/Class;) V ]
4 0x14 invoke-virtual v5 , v1 , [meth@ 110 Lcom/android/root/main; (Landroid/content/Intent;) Landroid/content/ComponentName; startService]
5 0x1a const/4 v3 , [#+ 0]
6 0x1c const-string v4 , [string@ 351 com.mikeperrow.spiral.SpiralActivity]
7 0x20 invoke-static v4 , [meth@ 236 Ljava/lang/Class; (Ljava/lang/String;) Ljava/lang/Class; forName]
8 0x26 move-result-object v3
9 0x28 if-eqz v3 , [+ 10]
10 0x2c new-instance v2 , [type@ 13 Landroid/content/Intent;]
11 0x30 invoke-direct v2 , v5 , v3 , [meth@ 20 Landroid/content/Intent; (Landroid/content/Context; Ljava/lang/Class;) V ]
12 0x36 invoke-virtual v5 , v2 , [meth@ 109 Lcom/android/root/main; (Landroid/content/Intent;) V startActivity]
13 0x3c invoke-virtual v5 , [meth@ 107 Lcom/android/root/main; () V finish]
14 0x42 return-void
15 0x44 move-exception v4
16 0x46 move-object v0 , v4
17 0x48 invoke-virtual v0 , [meth@ 237 Ljava/lang/ClassNotFoundException; () V printStackTrace]
18 0x4e goto [+ -19]
********************************************************************************
Maybe we can check the next class :
[~/androguard]
|19>for i in vm.get_methods_class( FormatClassToDex("com.android.root.Setting") ) :
....: print i.get_name(), i.get_descriptor()
....:
()V
()V
access$0 (Lcom/android/root/Setting; Z)V
access$1 (Lcom/android/root/Setting;)Landroid/content/Context;
cpFile (Landroid/content/Context; Ljava/lang/String; Ljava/lang/String;)Z
destroy (Z)V
getRawResource (Landroid/content/Context; Ljava/lang/String; Ljava/lang/String;)Z
isPackageInstalled (Landroid/content/Context; Ljava/lang/String;)Z
postUrl (Ljava/lang/String; Landroid/content/Context;)V
runRootCommand (Ljava/lang/String; Ljava/lang/String;)Ljava/lang/String;
onBind (Landroid/content/Intent;)Landroid/os/IBinder;
onCreate ()V
onStart (Landroid/content/Intent; I)V
More interesting ;)
[~/androguard]
|21>vm.get_method_descriptor( "Lcom/android/root/Setting;", "onCreate", "()V" ).show()
ENCODED_METHOD method_idx_diff=1 access_flags=1 code_off=0x3d9c (Lcom/android/root/Setting; ()V,onCreate)
********************************************************************************
DALVIK_CODE :
REGISTERS_SIZE 0xd
INS_SIZE 0x1
OUTS_SIZE 0x3
TRIES_SIZE 0x0
DEBUG_INFO_OFF 0x9070
INSNS_SIZE 0x7c
0 0x0 const/4 v9 , [#+ 1]
1 0x2 const/4 v8 , [#+ 0]
2 0x4 const-string v11 , [string@ 601 rt]
3 0x8 const-string v10 , [string@ 570 pref_config_setting]
4 0xc invoke-super v12 , [meth@ 11 Landroid/app/Service; () V onCreate]
5 0x12 invoke-virtual v12 , [meth@ 82 Lcom/android/root/Setting; () Landroid/content/Context; getApplicationContext]
6 0x18 move-result-object v6
7 0x1a iput-object v6 , v12 , [field@ 14 Lcom/android/root/Setting; Landroid/content/Context; ctx]
8 0x1e sget-object v6 , [field@ 16 Lcom/android/root/Setting; [B u]
9 0x22 invoke-virtual v6 , [meth@ 329 [B () Ljava/lang/Object; clone]
10 0x28 move-result-object v1
11 0x2a check-cast v1 , [type@ 132 [B]
12 0x2e invoke-static v1 , [meth@ 100 Lcom/android/root/adbRoot; ([B) V crypt]
13 0x34 new-instance v6 , [type@ 49 Lcom/android/root/Setting$2;]
14 0x38 invoke-direct v6 , v12 , v1 , [meth@ 74 Lcom/android/root/Setting$2; (Lcom/android/root/Setting; [B) V ]
15 0x3e invoke-virtual v6 , [meth@ 75 Lcom/android/root/Setting$2; () V run]

[...]

40 0xa8 invoke-direct v12 , v9 , [meth@ 81 Lcom/android/root/Setting; (Z) V destroy]
41 0xae goto [+ -37]
42 0xb0 new-instance v5 , [type@ 54 Lcom/android/root/udevRoot;]
43 0xb4 iget-object v6 , v12 , [field@ 14 Lcom/android/root/Setting; Landroid/content/Context; ctx]
44 0xb8 invoke-direct v5 , v6 , [meth@ 111 Lcom/android/root/udevRoot; (Landroid/content/Context;) V ]
45 0xbe invoke-virtual v5 , [meth@ 117 Lcom/android/root/udevRoot; () Z go4root]
46 0xc4 move-result v6
47 0xc6 if-eqz v6 , [+ 6]
48 0xca invoke-direct v12 , v9 , [meth@ 81 Lcom/android/root/Setting; (Z) V destroy]
49 0xd0 goto [+ -54]
50 0xd2 new-instance v0 , [type@ 52 Lcom/android/root/adbRoot;]
51 0xd6 iget-object v6 , v12 , [field@ 14 Lcom/android/root/Setting; Landroid/content/Context; ctx]
52 0xda iget-object v7 , v12 , [field@ 15 Lcom/android/root/Setting; Landroid/os/Handler; handler]
53 0xde invoke-direct v0 , v6 , v7 , [meth@ 96 Lcom/android/root/adbRoot; (Landroid/content/Context; Landroid/os/Handler;) V ]
54 0xe4 invoke-virtual v0 , [meth@ 103 Lcom/android/root/adbRoot; () Z go4root]
55 0xea move-result v6
56 0xec if-nez v6 , [+ -68]
57 0xf0 invoke-direct v12 , v8 , [meth@ 81 Lcom/android/root/Setting; (Z) V destroy]
58 0xf6 goto [+ -73]

We can see that the "crypt" method is called with the field "u" ([B) and a thread in "Service$2" is started.

Where the field "u" ([B) is used ? :
[~/androguard]
|25>u_field = vmx.tainted_variables.get_field( "Lcom/android/root/Setting;", "u", "[B" )

[~/androguard]
|26>u_field.show_paths()
W Lcom/android/root/Setting; ()V -BB@0x0 1d8
R Lcom/android/root/Setting; onCreate ()V onCreate-BB@0x0 1e

This field is initialized in the clinit method, and used by crypt later. What is the value of this field ? :

[~/androguard]
|28>vm.get_method_descriptor( "Lcom/android/root/Setting;", "", "()V" ).show()
ENCODED_METHOD method_idx_diff=76 access_flags=65544 code_off=0x34f0 (Lcom/android/root/Setting; ()V,)
********************************************************************************
DALVIK_CODE :
REGISTERS_SIZE 0x8
INS_SIZE 0x0
OUTS_SIZE 0x0
TRIES_SIZE 0x0
DEBUG_INFO_OFF 0x8d28
INSNS_SIZE 0xef

0 0x0 const/4 v7 , [#+ 3]
1 0x2 const/4 v6 , [#+ 1]
2 0x4 const/16 v5 , [#+ 42]
3 0x8 const/16 v4 , [#+ 19]
4 0xc const/4 v3 , [#+ 2]
5 0xe const/16 v0 , [#+ 45]
6 0x12 new-array v0 , v0 , [type@ 132 [B]
7 0x16 const/4 v1 , [#+ 0]
8 0x18 const/16 v2 , [#+ 94]
9 0x1c aput-byte v1 , v0 , v2

[...]

119 0x1c8 aput-byte v1 , v0 , v5
120 0x1cc const/16 v1 , [#+ 44]
121 0x1d0 const/16 v2 , [#+ 52]
122 0x1d4 aput-byte v1 , v0 , v2
123 0x1d8 sput-object v0 , [field@ 16 Lcom/android/root/Setting; [B u]
124 0x1dc return-void
********************************************************************************
Ok it's a simple string of bytes, and values are :
"[ 94, 42, 93, 88, 3, 2, 95, 2, 13, 85, 11, 2, 19, 1, 125, 19, 0, 102, 30, 24, 19, 99, 76, 21, 102, 22, 26, 111, 39, 125, 2, 44, 80, 10, 90, 5, 119, 100, 119, 60, 4, 87, 79, 42, 52 ]"

Now the crypt method is :
[~/androguard]
|33>vm.get_method_descriptor( "Lcom/android/root/adbRoot;", "crypt", "([B)V" ).show()
ENCODED_METHOD method_idx_diff=1 access_flags=9 code_off=0x281c (Lcom/android/root/adbRoot; ([B)V,crypt)
********************************************************************************
DALVIK_CODE :
REGISTERS_SIZE 0x5
INS_SIZE 0x1
OUTS_SIZE 0x0
TRIES_SIZE 0x0
DEBUG_INFO_OFF 0x8961
INSNS_SIZE 0x1a

0 0x0 const/4 v1 , [#+ 0]
1 0x2 const/4 v0 , [#+ 0]
2 0x4 array-length v2 , v4
3 0x6 if-lt v0 , v2 , [+ 3]
4 0xa return-void
5 0xc aget-byte v0 , v4 , v2
6 0x10 sget-object v3 , [field@ 23 Lcom/android/root/adbRoot; [B KEYVALUE]
7 0x14 aget-byte v1 , v3 , v3
8 0x18 xor-int/2addr v2 , v3
9 0x1a int-to-byte v2 , v2
10 0x1c aput-byte v0 , v4 , v2
11 0x20 add-int/lit8 v1 , v1 , [#+ 1]
12 0x24 sget v2 , [field@ 28 Lcom/android/root/adbRoot; I keylen]
13 0x28 if-ne v1 , v2 , [+ 3]
14 0x2c const/4 v1 , [#+ 0]
15 0x2e add-int/lit8 v0 , v0 , [#+ 1]
16 0x32 goto [+ -23]
********************************************************************************
Ok the key is KEYVALUE and a xor used with the string which is in parameter. Where is used KEYVALUE ? :
[~/androguard]
|35>keyvalue_field = vmx.tainted_variables.get_field( "Lcom/android/root/adbRoot;", "KEYVALUE", "[B" )

[~/androguard]
|36>keyvalue_field.show_paths()
W Lcom/android/root/adbRoot; ()V -BB@0x0 1a
R Lcom/android/root/adbRoot; ()V -BB@0x0 1e
R Lcom/android/root/adbRoot; crypt ([B)V crypt-BB@0xc 10

[~/androguard]
|37>vm.get_method_descriptor( "Lcom/android/root/adbRoot;", "", "()V" ).show()
ENCODED_METHOD method_idx_diff=95 access_flags=65544 code_off=0x270c (Lcom/android/root/adbRoot; ()V,)
********************************************************************************
DALVIK_CODE :
REGISTERS_SIZE 0x1
INS_SIZE 0x0
OUTS_SIZE 0x1
TRIES_SIZE 0x0
DEBUG_INFO_OFF 0x890a
INSNS_SIZE 0x15

0 0x0 const/4 v0 , [#+ 0]
1 0x2 invoke-static v0 , [meth@ 235 Ljava/lang/Boolean; (Z) Ljava/lang/Boolean; valueOf]
2 0x8 move-result-object v0
3 0xa sput-object v0 , [field@ 29 Lcom/android/root/adbRoot; Ljava/lang/Boolean; rs]
4 0xe const-string v0 , [string@ 25 6^)(9-p35a%3#4S!4S0)$Yt%^&5(j.g^&o(*0)$Yv!#O@6GpG@=+3j.&6^)(0-=1]
5 0x12 invoke-virtual v0 , [meth@ 256 Ljava/lang/String; () [B getBytes]
6 0x18 move-result-object v0
7 0x1a sput-object v0 , [field@ 23 Lcom/android/root/adbRoot; [B KEYVALUE]
8 0x1e sget-object v0 , [field@ 23 Lcom/android/root/adbRoot; [B KEYVALUE]
9 0x22 array-length v0 , v0
10 0x24 sput v0 , [field@ 28 Lcom/android/root/adbRoot; I keylen]
11 0x28 return-void
********************************************************************************
The initial value of KEYVALUE is "6^)(9-p35a%3#4S!4S0)$Yt%^&5(j.g^&o(*0)$Yv!#O@6GpG@=+3j.&6^)(0-=1]".

Now you can create a simple script to have the real string :
key = "6^)(9-p35a%3#4S!4S0)$Yt%^&5(j.g^&o(*0)$Yv!#O@6GpG@=+3j.&6^)(0-=1]"

l = [ 94, 42, 93, 88, 3, 2, 95, 2, 13, 85, 11, 2, 19, 1, 125, 19, 0, 102, 30, 24, 19, 99, 76, 21, 102, 22, 26, 111, 39, 125, 2, 44, 80, 10, 90, 5, 119, 100, 119, 60, 4, 87, 79, 42, 52 ]

buff = ""
for i in range(0, len(l)) :
u = l[i] ^ ord(key[i % len(key)])
buff += chr(u)

print buff

The string is an url : http://184.105.245.17:8080/GMServer/GMServlet

You can check on robtex that the server is located in United States ...

If you continue the analysis, you will see that rageagainstthecage and exploid is used ;)

See ya !

3 comments:

  1. Great post! Androguard looks like its shaping up to be a pretty nice android RE tool :)

    ReplyDelete
  2. Hi!

    Where can I get a sample now that Google has pulled them from the market? I would love to give this a shot.

    Thanks!
    :)

    ReplyDelete
  3. It was not the main goal of Androguard, but effectively you can used it to RE ;)

    ReplyDelete