RootSmart Android Malware
Android’s increasing popularity, combined with the possibility to create alternative markets, makes this platform a fertile ground for malware authors. While most of these applications just exploit the inexperience of the average user that is looking for free software, others are pretty smart and use more sophisticated techniques to take, and keep, control of the infected devices.
Lately it came to my attention that a new malware was taking advantage of the famous GingerBreak exploit to gain root privileges on infected phones. RootSmart, the name given to the malware by the people who identified it first, is the second application found in the wild making use of an exploit (the first one was GingerMaster detected back in August 2011).
RootSmart is actually, well… smart, kind of. The exploit is not embedded into the package, probably in an attempt to appear less suspicious to the AV systems, but is downloaded from a remote webserver alongside other malicious packages. Additionally, a bit of cryptography is used to deter the analyst from reverse engineering the application.
Let’s dig in.
The sample I was able to retrieve has the following parameters:
- File: com.google.android.smart.apk
- File size: 314.445 bytes
- MD5: F70664BB0D45665E79BA9113C5E4D0F4
- SHA1: 67CF01EE7FF0E65CB7EC78CDBD274077153ADD4E
At the time of writing, the detection rate on VirusTotal is 8/43 (identified as Android.RootSmart or Android.BMaster).
Android needs to gather some essential information from every application before the underlying OS can be able to run them. This information is stored in the manifest file, and that’s where we’ll start our journey.
First of all we’ll have to unpack the .apk and transform the manifest from binary XML into a readable version. To do that we’ll use a really handy tool called android-apktool (http://code.google.com/p/android-apktool/).
Type the following command:
[sourcecode]java –jar apktool.jar d <.apk name> <destination dir>
After processing we’ll find our manifest file in the destination directory, together with a full disassembly of the whole .dex file. We’ll take care of that in a moment, for now let’s stay focused on the manifest:
We see that the application requires a lot of permissions; this should already alert the user that something is wrong. Some of them are required by any sync provider (WRITE_SYNC_SETTINGS, GET_ACCOUNTS etc…) but some others are more interesting.
This package wants to access the Internet, apparently even by turning on the Wi-Fi directly (CHANGE_WIFI_STATE). It’s also interested in our exact position (ACCESS_FINE_LOCATION), but what should draw our immediate attention are two permissions: MOUNT_UNMOUNT_FILESYSTEMS and READ_LOGS. The application is screaming: “Hey, I want to run GingerBreak!” The exploit needs access to the log file in order to be able to retrieve the address where vold crashed, this same address will be used later on to overwrite the GOT. Moreover we see that the permission RECEIVE_BOOT_COMPLETED is required, this really sounds like a boot service ready to run every time we turn our phone on.
We are not done yet. An important part of the analysis is to identify the listeners associated to each intent; from the manifest we understand that:
- .WcbakeLockReceivecr: gets called when the user starts interacting with the phone.
- .BcbootReceivecr: is called when the phone boots.
- .ScbhutdownReceivecr: is called when we shut down the phone.
- .PcbackageAddedReceivecr: is called when we install a new application.
- .LcbiveReceivecr: is called (also) when we reboot and when we make a new phone call.
We’ve been able to identify at least the data the malware is interested in, and where it is managed. With a clearer picture we are now ready to proceed with the analysis of the application.
Fire up your emulator and install the application. There are mainly two ways to proceed, the first one is with a direct installation through ADB:
[sourcecode]adb install suspect.apk[/sourcecode]
The second one is by downloading and installing the package as you would do with any other application. In this case we’ll also be able to directly check the required permissions:
This should already ring a bell: more or less permission is being required. Notice also, it is using the same “Settings” icon that comes with the genuine application. The main difference is that its name will be in Chinese. There is nothing wrong with it; however, this malware is in fact specifically targeted to the Chinese market.
Trying to open the application will result in the following window from the genuine application:
The main program clearly is a legitimate one, repackaged with a malicious boot service. We know that there’s no “official” way to run a boot service right after the service installation, so the program has to “hook” into some event to be able to start. The first one will be BOOT_COMPLETED. We can see from the manifest that this intent is managed from the class com.google.android.smart.BcbootReceivecr. At this point we have enough elements to be able to begin our code analysis.
We need to disassemble the application in order to be able to analyze the code. For this task we’ll use three handy tools: dex2jar, JD-GUI and Baksmali. The first tool is used to convert the .dex file into a .jar package, the second one is a decompiler, used to reconstruct the Java source code, the third is a disassembler that’s able to convert the .dex file into a human readable (sort of) Dalvik code. If you’re wondering why we should use a disassembler when we have a full featured decompiler, here’s the answer: JD-GUI is really handy, but unfortunately still under development. For this reason it’s still easy to fool (on purpose or by chance) and we won’t be able to use it for a full and complete analysis.
First step: convert the .apk to a .jar package:
Second step: open it using JD-GUI:
It’s now obvious that we are dealing with three packages: the malware com.google.android.smart, the legitimate application com.bwx.bequick (it’s called QuickSettings on the genuine Android Market) and another package just called a (most likely this is an imported library used to manage SOAP requests).
Let’s examine the class that deals with the BOOT_COMPLETED intent. Fortunately for us, this part has been correctly decompiled:
The package checks to see if the application is in “hibernate” state. If it’s not it starts the service from the McbainServicce.class, keeps an eye on the setAction() and then moves to the class that manages the creation and destruction of the service:
What’s happening here?
- The SharedPreference “last_check_live_time” is initialized to the current time
- Flag “hibernated” is checked, if true the application stops
- If the flag “first_start_time” is initialized then the application starts parsing the action
Preferences are stored in two XML files: mms_localinfo.xml and mms_settings.xml. All of them are in clear text and can be easily retrieved. The action sent to the “action manager” class executes the following code:
Names are obfuscated, but it’s not a bad thing. After all meaningless names are better than misleading names. So the code tells us that a 1 minute alarm is set. After 1 minute a new action “action.check_live” will be broadcasted. This function, guess what…does something interesting:
Among other things the OS version is checked against “2.3.4”, then the existence of a file called shells is checked. What for? Apparently an exploit is run, at least judging from the name left in the code. The class called f sets the right permissions on the file, executes it through McbainServicce.class Boolean a(String) and then performs a cleanup:
That’s smart. In this way the malware is able to install its own shell into the system, and then it can use the root access to silently install other packages. So far we have no trace of an exploit embedded into the package, thus we conclude that the exploit is downloaded from some server.
Where exactly? We just need to go back where the application checks for the existence of the “shells” file. If this file is not found the method i.(this.a).a() is called, but exploring this function using JD-GUI is not possible because it wasn’t able to decompile it.
That’s not going to stop us: let’s just disassemble the package using Baksmali. Open the .apk package with any file compressor and extract the classes.dex file, then:
[sourcecode]java –jar –a 8 classes.dex –o baksmalied
We can now open the i.smali file to understand what the method a() does. This is a stripped version of the original disassembly:
It roughly translates to: check for the existence of “shells”, if you’re not able to find it, create the URL in this way:
[sourcecode]String url = "/androidService/" + "resources/commons/shells.zip"
It’s not really a URL. We are missing the address right? The address is extrapolated from the following raw resource: res/raw/data_3. The binary content is the following:
Clearly it’s not a plain-text URL, and indeed we are right, this is an encrypted text that is decrypted inside the method String s.a().
We all love Dalvik opcodes right? Not really, but this time we have no excuses, JD-GUI is not helping us and, unless we have a full cryptographic engine embedded in our brain, we’ll have to do some old-school decompilation. The original bytecode looks like this (shown just in part):
After analyzing every line carefully, we can reconstruct the original source code, which is exactly:
After rewriting the code it is possible to run it to recover the original URL.
It’s worth spending a couple of words on this part of the code: we have to retrieve the exploit from a webserver, but the URL is not in clear form. There is an encrypted resource file. The encryption key is not hardcoded, but it’s generated at runtime… How? A pseudo-random number generator based on SHA1 is initialized using a seed stored in the manifest. You can see it below:
From the disassembly we find that the “package_id” parameter is retrieved and it’s used to feed the PRNG. The output is used to initialize the 128-bit key used by an AES cipher and ultimately used to decrypt the URL that turns out to be: go.docrui.com. Our final path is:
This was a smart move by the authors. They made the reverse engineering of the application a bit harder using this trick. After the file has been retrieved using the v class that handles all the standard HTTP requests, its MD5 hash is checked inside i.a():
const-string v3, “6bb75a2ec3e547cc5d2848dad213f6d3”
After retrieving the file and checking it, this same package is unpacked from s.a(String, String) method and the resulting files used accordingly. The package contains three files:
- exploit: GingerBreak compiled out-of-the-box, check it with any hex-editor
- install: used to install a shell
- installapp: used to copy around a suid root file
While GingerBreak is well known and documented, it is interesting to take a look at the scripts. We start from install:
The script is used to remount the filesystem in read-write mode, and then a new directory is created: /system/xbin/smart. Inside the new directory a root shell is created. Then the filesystem is remounted in read-only. The installapp script looks like this:
In this case we have a helper script that is able to write a file anywhere granting the +s mode to it. This same process is carried out not only when the phone is booting up, but even after making a phone call. The malware uses this technique to have another chance of starting before the user reboots the phone.
RootSmart is able to handle a variety of actions, all of them sent via web from the C&C server. What are its capabilities? Let’s make a quick summary of all the available commands:
- action.host_start: marks the malware as running
- action.boot: sets a 60 second alarm that checks if the phone has been exploited
- action.shutdown: sets the amount of time the backdoor has been running and if the phone has been exploited
- action.screen_off: checks the power state, keeping the device on when needed
- action.install: downloads and installs the exploit and root shell
- action.installed: retrieves phone information and does the final setup of the backdoor
- action.check_live: schedules an hourly self-check and detects OS version
- action.download_shells: downloads the shell package from the remote server
- action.exploid: unpacks shell file, runs the exploit, sets the result and does the cleanup
- action.first_commit_localinfo: sets a flag with the local time off first connection to remote server
- action.second_commit_localinfo: like above, with some other internal flag initializations
- action.load_taskinfo: gets phone’s IMEI and retrieves package’s information
- action.download_apk: downloads the requested apk and installs it (silently, if we have root)
Every action is managed from the main McbainServicce class and from every action received, a new thread is started. What about the other receivers we have extracted from the manifest? Let’s check them quickly:
- .McbainServicce: dispatches the actions, it’s the malware core class
- .WcbakeLockReceivecr: activated when the user is active, sends an action.install
- .BcbootReceivecr: sends an action.boot to the action manager when the phone is booted
- .ScbhutdownReceivecr: is called when we shut down the phone to close the backdoor
- .PcbackageAddedReceivecr: monitors the installation of any new application
- .LcbiveReceivecr: called in different situations, starts the backdoor if it’s not yet running
Some more classes are of course used to manage webserver requests or packages installation. Should you be interested in the technical details, I’ll give you some pointers:
- x.class: manages all the preferences and flags set and read by the backdoor
- e.class: manages and creates the “custom” headers for requests to the C&C
- l.class e.class c.class: manage the installation of a new .apk
- v.class: manages requests received from the server
It’s time now to let the malware run, of course while logging the traffic requests made by the application. We can choose to reboot the phone, or start a new phone call; in any case, we will notice that the first thing sent over the Internet is a SOAP request containing some interesting data:
Even though nobody likes SOAP we’ll have to deal with it. The first request is a kind of identification packet, sending to remote server the following data: IMEI, IMSI, OS Version, CID, LAC, MNC (cell tower info), rooting status and some information about the malware itself – even its own version, which might indicate that the package could be remotely upgraded. All of this information is acquired by the g() class:
A curious note: check the User-Agent used to send the requests…
The server response is:
At this point the backdoor will connect back to the server, at regular intervals, to receive commands.
From the capabilities found during the analysis we know that the application is able to download and install additional malware packages. If you’re willing to, you can keep monitoring the traffic, until some action is sent from the server.
From what I’ve seen, DroidLive is downloaded, but this is subject to change and it all depends on the settings set by the C&C server owners. One hint: try to connect using a Chinese proxy. Foreign phones don’t seem to gain a lot of attention from the server guys. And it makes sense if the malware downloaded after the first run does premium-SMS sending to Chinese numbers.
The code is similar to Android DroidLive malware in many parts, except for the fact that a lot of features are not present. Most likely this application is a stripped-down DroidLive with exploiting capabilities used as a first stage infector to open the gate to other malware. Currently the botnet behind RootSmart seems to be quite large. According to Symantec (http://www.symantec.com/connect/blogs/androidbmaster-million-dollar-mobile-botnet) between 10.000 and 30.000 devices seem to be active.
So my advice is, of course, to pay attention to what you download, always use an official market (even though official doesn’t always equal secure), be careful with required permissions and, if possible, keep your phone up to date and… Unrooted ;-).