Sample used in the analysis:
Multiple applications available in the official Android Market were found to contain malware which could compromise a significant amount of personal data. More than 50 applications were found to be infected with a new type of Android malware called DroidDream. Similar to previous instances of Android malware that have been found on alternative Android app markets, the authors of DroidDream hid the malware in seemingly legitimate applications to trick unsuspecting users into downloading the malware—a growing trend in mobile threats.
How it starts
The malware activity uses little obfuscation to hide itself. It comes in the form of a repackaged legitimate application, the legitimate application often being paid. Within the application, the malware hides by embedding itself using the namespace com.android.root.
In the DroidDream sample we analyzed (Bowling Time), the malware cannot start automatically: it requires the user to manually run the infected application. Additionally, the malware has modified the AndroidManifest.xml to launch itself prior to the primary app’s activity.
Inside the com.android.root.main activity we can see that the malware will start its own service and then launch the host application’s primary activity.
The service invoked is labeled as com.android.root.Setting. The Setting service will notify the command and control server and attempt to root the device. First the malware will contact the command and control server identifying the compromised device. The following is a decrypted request that is sent to the server:
We can see here that the malware is exposing unique identifiers for the device: IMEI, IMSI and device model and SDK version. The Partner and ProductId are both specific integers to the DroidDream variant and do not change device to device. The following is a decrypted response from the server:
The above is a response from the C&C , which is parsed by the malware and saved. If the response is the same as above, then it will save the value to shared preferences as pref_config_setting -> done with a value of ‘1’. This value is checked on later attempts to check into the server. If done is set to ‘1’ then the malware will not check-in, resulting in the application only performing one check-in.
The crypto used for requests and responses is a simple XOR with an embedded key, implemented in com.android.root.adbRoot.crypto. A quick pass at the dalvik code will result similar code as shown below:
We see this function being used to decrypt the URL which is stored in the byte array u in the com.android.root.Setting class. This is the command and control server which the malware will be communicating with:
The rest of the service implements the infection cycle. It checks to see if the device is infected already by checking for the presence of /system/bin/profile. If the file does exist, it will not re-infect the device, otherwise it will continue the infection process.
Attempts to Root Device
Two attempts are made to root the device, both relying on exploits developed by Sebastian Krahmer. The first attempt uses “exploid” to attempt to exploit a vulnerability in udev event handling in Android’s init. If exploid fails to do the job, DroidDream attempts to use rageagainstthecage, leveraging a vulnerability in adbd’s attempt to drop its privileges. The exploitation process is highlighted by the code below:
After both of the steps above have completed, the malware checks to see if the package com.android.providers.downloadsmanager is installed. If this package is not found it will install the second payload, which is bundled as sqlite.db. This part of the malware will be copied to the /system/app/ directory, installing itself as DownloadProviderManager.apk. Copying the file using this method, to this directory will silently install the APK file, and not prompt the user to grant permissions as in a standard app installation process.
After the above steps have completed, this payload is done. There is nothing else that the payload has been designed to do – it only implements this one mode of infection then waits for the second payload it installed, DownloadProviderManager.apk, to do the rest of the work. This may have been a choice implemented by the malware authors to keep the infection code separate from the other commands, keeping the infection packages smaller.
Analysis on Payload Two
Once the second stage payload is delivered and installed by the primary infector, it sits and waits silently to be activated. There is no icon on the application tray, and it cannot be found by other user-managed applications on the file system since it is installed on the /system partition. Unlike the previous stage, it is not executed by the user, but triggered by Intents it listens for on the device. As we see in AndroidManifest.xml, entry points consist of a receiver for BOOT_COMPLETED and PHONE_STATE intents as well as a single service:
When either Intent is fired, com.android.providers.downloadsmanager.DownloadCompleteReceiver starts. The flow of this receiver is rather simple. First, it checks its internal SQLite database to determine if it’s already performing a sync. If not, it proceeds if the current date is greater than or up to 5 days preceding the value of its “NextConnectTime” preference.
If the connect time is within the functional range, it launches its internal service, and if the receiver was triggered by DOWNLOAD_COMPLETED, it passes on the data from this intent to an internal handler for processing.
DownloadManageService controls a timer-scheduled task, initializes the SQLite tables and manages the download handler. It schedules the task com.android.providers.downloadsmanager.d to run for two hours at a time, with a delay of two minutes between executions. This is evident in the onCreate() method of DownloadManageService as shown below:
The malware has been very aptly named “DreamDroid” both for the structure of package naming and constraints its author(s) placed on its execution. We can see this in the first few lines of the scheduled thread:
The thread checks the database of scheduled downloads to see if there are any entries that have not started or completed. If downloads have not been started, it will initiate them. If there are stale or completed downloads, it will remove them. Downloading is accomplished by the Android Download Provider by passing a URI to content://downloads/download.. Listening for the DOWNLOAD_COMPLETED Intent as described above, allows the malware to be notified when the download has completed. More on this later.
- ProductID – Specific to the DroidDream variant
- Partner – Specific to the DroidDream variant
- Model & SDK value
- UserID – Though this does not appear to be fully implemented
After gathering the data, it attempts to enumerate packages it has installed, but not yet reported back to the server. If there are any packages to report on, it builds and transmits a “Command 2” payload with the number of total packages and each individual package name that has been installed by DroidDream.
After the command is initialized, it transmits the data to its C&C, formatting the gathered ContentValues as XML and encrypting them. The encrypted string is transmitted to the same C&C as the previous payload using the same XOR scheme and key used in the infector payload. Code for this transaction follows:
We find the communication service and command engine in com.android.providers.downloadsmanager.a.e. Inside the a(Int command, ContentValues content) function, the request is turned into XML, encrypted, sent to the server and its response is parsed. The response may contain a NextConnectTime, which is then saved to the shared preferences. The response can also contain a DownloadUrl and PackageName.
It appears that there is incomplete functionality here to monitor ratings, comments, asset IDs, and install states. We speculate that the author(s) intended to monitor Market activity and potentially rate/comment on downloaded applications.
We previously mentioned receipt of DOWNLOAD_COMPLETE Intents as an entry point. We have already outlined that the Intent is caught and passed onto the handler. That handler verifies that the application was pending for download, and (if not) ignores supplied data. When an expected download has completed, it attempts to install the software and change the status of the application in the SQL database.
The install method is similar to the one used in payload one — a silent install to the /system/app directory – with the addition that it removes the downloaded APK from its temporary download location. The silent install is performed by remounting the /system directory writable, then cat’ing the package into the /system/app directory. From there, it’s picked up by the package manager and installed automatically without prompting the user or notifying them of a new application. Once downloaded and copied, the downloaded file is removed. The interesting code from the handler, found in com.android.providers.downloadsmanager.a.e is highlighted below:
After analyzing the entire package, it’s clear that the second stage is capable of downloading and installing anything that the author(s) choose to serve it. The initial payload escalates privileges and installs this agent. The agent periodically checks in with its C&C and updates installed components as instructed. Though we have not observed third stage payloads, possibilities are effectively limitless. Coupled with the setuid back door, we have a powerful zombie agent that can install any payload silently and execute code with root privileges at will.