As promised i am back to reverse stuff. This time, and following the previous sequence of posts, i have decided to pick an Android malware for analysis. Without further ado, let us begin.
Family name: Ginmaster (GingerMaster)
GingerMaster was the first Android malware using GingerBreak exploit, an exploit that affects GingerBread (Android 2.3). The malware is capable of downloading, installing and launching APKs without users permission using low level tools like pm (package manager), sh (shell) and am (activity manager). The malware has their classes’ and functions’ names obfuscated using small chains of random characters. Contacted URLs and other relevant strings are in plaintext.
As always, i have uploaded the IDA database to my GitHub repository.
Tools: Android Studio (2.3.2) and sdk tools (e.g. adb, aapt), IDA Pro 6.4.130111-32-bit, JD-GUI 1.4.0, aapt, dex2-jar, apk tool,
Environment: VMware with 64-bit Windows 7
Emulator and Libraries: Nexus 5X, Gingerbread (2.3.3 with GoogleAPIs, API Level 10),
The objective of this post is to understand how the malware works, i.e.:
- Files created
- URLs contacted
- Exfiltrated information
- Services created and what they do
- Usage of GingerBreak, an exploit used to obtain root on Android 2.3 (Gingerbread)
Before diving into tools and code, it is worth checking the activity generated by the malware when executing. We start by creating a emulator and using adb to deploy the application. I would like to see how the application works and the traffic it generates (e.g. using Wireshark). It is cumbersome to track the source of the traffic (i.e. malicious application vs. legitimate emulator behaviour).
client[.]mustmobile[.]com is a domain widely used by the malware and since there is no DNS resolution for it, no further traffic will be seen. As for host indicators, the Android Device Manager is of great help:
The first picture is contents of the SD card. Since i already know that the malware uses the SD card to store files and perform the exploitation we are expected to see files there. install.sh, installsoft.sh, runme.sh and gbfm.sh are of utter importance. It also uses SQLLite to store configurations and lists of packages for download (databases folder).
The malware writes far too much on the logs and Logcat (integrated on Android Studio) is useful to get them. As you can see GameService has been spawned (picture below). The command:
adb shell dumpsys activity services
is helpful to get a dump of the activities and services. We can see there that GameService is running and Web has bound to it (refer to service binding for more information).
Package Structure Analysis
I will assume you read the previous articles and that you are familiar with the usage of the tools i referred there.
As soon as you start looking at the application package you will realise it does not have a lot to look at. Once you convert the dex file to a jar, you will see about 106 classes under the same package com.igamepower.appmaster. You can spot some degree of obfuscation by noticing:
- random name classes (e.g. af.class, e.class, f.class)
- mix of Java and smali code. This is indicative that the conversion from dex to Java failed due to anti-reversing techniques
While the number of classes is high, the absence of multiple packages makes the analysis easier. The first version of Ginmaster i looked at (MD5 17ca4c91367ba4b91bdb6e0b77aaafb6) while having many more packages, was successfully decompiled into Java. I think for learning purposes, analysis of SMALI is a much more interesting exercise.
Looking at the decoded Manifest we can see the following permissions:
|Permission String||Permission (according to docs)|
|READ_LOGS||Allows application to read low-level logs.|
|ACCESS_NETWORK_STATE||Query network information (e.g. check if connected).|
|INTERNET||Allows the creation of sockets.|
|MOUNT_UNMOUNT_FILESYSTEMS||Self-explanatory. The malware requires access to external SD cards.|
|User email, name, etc|
|WRITE_SETTINGS||Allows the modification device settings|
|Allows the creation of a shortcut on Launcher (the board with applications)|
|RECEIVE_BOOT_COMPLETED||Allows application to receive a notification when the device finishes booting|
|RESTART_PACKAGES||Allows the app to end background processes of other apps.|
In terms of string resources we have little to none and they are in chinese. Feel free to use Google translate to check the translation.
In terms of activities/services/receivers, we have:
|Activity||DevelopmentSettings (not found on the package)||action:APPLICATION_DEVELOPMENT_SETTINGS|
The usage of the intent filters you see for GameService is not clear to me. MAIN and LAUNCHER are associated with the activity responsible for the first screen. Services cannot be launched directly through Launcher icons. Upon looking at the Java code for Web, i have seen the service GameService being explicitly launched as i will refer on the next section. I am assuming this was a mistake of the authors that turned out not to crash the application.
The usage of DEFAULT category on Myhall is intended to mark that activity as a potential candidate to receive implicit intents for the MAIN action. i.e, if another application or even this one creates an intent with the action MAIN, all applications with a MAIN action and the DEFAULT category will receive the intent.
GameBootReceiver is a broadcast receiver. Broadcast receivers are used by applications to receive broadcasted intents from other applications (e.g. OS reporting battery status). In this case, BOOT_COMPLETED is an action used on broadcasts to notify applications of a complete system boot (once it is finished).
Finally, DevelopmentSettings has APPLICATION_DEVELOPMENT_SETTINGS action which tells us the class is able to mess with application development settings on Android. This activity was not on the APK.
I will not overview the assets folder just now because i am referring it later. Enough high-level analysis, let us dive into details.
Java SMALI Code Analysis
Unfortunately, this is one of the cases where the analysis of Java will confuse you more than actually help. We need to look at SMALI. We can use IDA to disassemble the .dex file. As previously referred the first Activity to be launched is Web. It starts by collecting device information and some APK details:
- SIM serial number
- Phone number
- Network type
- CPU serial (ignored and set to IMSI if CPU serial is 0000000000000000)
- Pixels (width, height)
- Version code of the APK
- Service channel 1004 (stored as a resource on the APK)
- Current Time
These details are posted to the URL we have seen before: http://client%5B.%5Dmustmobile%5B.%5Dcom/mt.php. Another URL (http://client%5B.%5Dmustmobile%5B.%5Dcom/request/update.do) is beaconed with the same details and the response after parsed is written to /data/data/com.igamepower.appmaster/files/cache/igamepower_file/8888. The purpose of this file is not clear since it is not opened anywhere else. However, the processed response is passed to ac handler with code 0x1 which leads to the download of a package named com.igamepower.appmaster of the version of the current malware is lower than the one hosted on the server (malware update):
Web class is also responsible for spawning GameService service. This service launches a couple of threads to contact the URLs on the following table. The aq thread is responsible for performing the requests while the an handler processes them based on codes. All beacons contain at least the collected data i have previously referred. All the URLs are for resources hosted on http://client.mustmobile%5B.%5Dcom.
|Resource||Data Sent and Purpose||Handler Code and Processing|
|report/first_run.do||Data Sent: Sends device details only.
Purpose: Beaconed when the application runs for the first time.
|Code: 0x1 (default case).
Processing: Nothing is done.
|Data Sent: Package Information.
Purpose: Beaconed when packages are installed or removed. Information about those packages is sent (e.g. name).
|Code: 0x0 (default case).
Processing: Nothing is done.
|request/config.do||Data Sent: Key-value pair action:config.
Purpose: Updates configuration parameters.
Processing: Shared Preferences are updated with fields such as:
|request/push.do||Data Sent: Sends SharedPreferences field soft_last_id.
Purpose: Informs the server of the last id associated with the last software on the downloaded lists of software.
Processing: Seems to be used to pull a list of software. The downloaded metadata is converted into shortcuts that when clicked redirect to the malware activities that display information about them.
|report/install_list.do||Data Sent: Result of “select * from game_package where status=1” is sent. status is set to 1 when there is a package installation.
Purpose: Likely to inform the remote server of the list of packages installed by the malware.
|Code: 0x1 (default case).
Processing: Nothing is done.
|request/alert.do||Data Sent: Sends to the server a field from SharedPreferences: alert_last_id.
Purpose: This seems like a means to pull notifications.
Processing: A notification is shown through GameAlertDialog.
It is GameService which deploys GameBootReceiver. GameBootReceiver is responsible for launching GameService upon boot. What is puzzling about this malware is that onReceive implementation has code to deal with installed and removed packages (i.e. Manifest permissions PACKAGE_ADDED and PACKAGE_REMOVED). However, the manifest states that this receiver is only able to BOOT_COMPLETED.
More network activity may be generated by MyHall. MyHall is a TabActivity which creates multiple tabs within itself that when clicked launch one of the following activities:
- HomeActivity: An activity and a Thread. The thread component is launched within the onCreate method. This thread beacons http://client.mustmobile%5B.%5Dcom/request/index.do and and appears to be used to pull a list of applications to be displayed on the HomeActivity activity (check bv.a with code 0x3E8).
- SearchActivity: The user can use this one to search for applications. The queries are posted to http://client.mustmobile%5B.%5Dcom/client.php?action=softlist&type=search&word=.
- ManagerActivity: Displays packages installed on the phone and shows more to be installed. It also allows the packages to be launched and deleted directly from the activity.
GameInfo queries http://client.mustmobile%5B.%5Dcom/client.php?action=soft&soft_id= to get information about a given application to be displayed to the user. SortActivity2 uses the URL http://client.mustmobile%5B.%5Dcom/client.php?action=softlist to get a list of software.
There is a URL http://apk.mustmobile%5B.%5Dcom/apk/20110705/19225910801.apk that appears on TestView.onClick:
According to OSINT, bdmobile.android.app is Baidu. When a certain button (identified by 0x7f0b0061) on this TestView is clicked, bdmobile.android.app is downloaded and deployed. What puzzles me here is that the activity is not created by any class within the APK so, apparently, there is no way for this branch to be executed.
So far we have overviewed network indicators and some host indicators (i.e. files created). We now know what details are beaconed to the server. GingerMaster has an interesting feature that we have not overviewed yet.
GingerMaster was the first malware leveraging GingerBreak exploit to obtain root permissions on the host. GingerBreak affects Android 2.3 Gingerbread. For it to work, the device must have an SD card inserted and USB debugging must be enabled which explains what i am about to overview. Going back to GameService.onCreate routine we see:
Multiple png files are moved from the assets folder to /data/data/com.igamepower.appmaster/files/ with .sh extensions. Then, the following command is executed:
chmod 775 /data/data/com.igamepower.appmaster/files/gbfm.sh /data/data/com.igamepower.appmaster/files/install.sh /data/data/com.igamepower.appmaster/files/installsoft.sh /data/data/com.igamepower.appmaster/files/runme.sh
When looking at the assets folder inside the APK, we can see four PNG files:
Basically moves /system/bin/sh around.
Install APK passed as argument.
|runme.png||3674d33c271a0c3c8f06c6ff7276e2b8||ELF||/system/bin/sh (see below)|
runme.png is a very simple ELF program (fancy some ARM?):
As far as i understand, the malware uses GingerBreak to install APKs on the host without requiring a specific permission on the Manifest or PlayStore using low level tools such as sh, am and pm. If the malware updates itself, it also leverages the exploit to escalate privileges.
Three classes pay a vital role on the deployment of APKs:
GameService: More specifically the a method. This method is used to download and deploy the APKs using f thread. Below you can see the functions that call a (called DownloadsAndDeploysAPKs on the diagram):
Downloads are therefore performed as a consequence of the events:
- TestView.onClick: As previously referred, this seems to download Baidu. However, i see no traces of TestView being used on the program.
- aa.handleMessage: Associated with the update of the application when http://client%5B.%5Dmustmobile%5B.%5Dcom/request/update.do is beaconed. aa is launched from Myhall.onCreate.
- ao.onClick: Likely associated with the request for an application made on the GameInfo activity, i.e., user checks application information and clicks button to download.
- bg.onClick: Used on SortActivity2 which displays lists of applications. Likely similar to the previous event.
- ca.handleMessage: Associated with the update of the application when http://client%5B.%5Dmustmobile%5B.%5Dcom/request/update.do is beaconed. ca is launched from Web.onCreate.
- cb.onClick: Associated with packages installed from ManagerActivity.
cj: Thread spawned on GameService.onCreate. Its purpose is to trick the user into enabling USB debugging (if not enabled) by showing notifications and launching Application Development Settings. It also checks whether there is an external SD card (remember this?). Once the debugging is enabled, the exploit is launched using the routine e from cj. gbfm.sh is executed. Once the exploit is finished, install.sh is also executed. Other functions within cj, such as c and d are worth mentioning because they are related to the execution of the scripts.
f: This thread is responsible for performing the download of the APK, the writing and the installation using installsoft.sh. Once the APK is downloaded, the thread checks for the ROOT status. ROOT_STATE_GINGER and ROOT_STATE_PERFECT are processed similarly as can be seen below:
ROOT_STATE_SU is processed with:
The code and therefore the purpose is similar (deploy package using/data/data/com.igamepower.appmaster/files/installsoft.sh). What changes is the interpreters used:
- ROOT_STATE_PERFECT: /system/xbin/appmaster/sh
- ROOT_STATE_GINGER: /data/data/com.igamepower.appmaster/sh
- ROOT_STATE_SU: /system/bin/su -c
ROOT_STATE_SU indicates that the application is already running as root and, therefore, it only needs to use the standard /system/bin/su. ROOT_STATE_PERFECT is set when the system is rooted and when the file /system/xbin/appmaster/sh is readable (install.sh executed completely). If the install.sh fails to create /system/xbin/appmaster/sh, ROOT_STATE_GINGER is the root state. The reason for the malware copying /system/bin/sh to /data/data/com.igamepower.appmaster/files/ and /system/xbin/appmaster is not clear to me.
Since the only issue you have to deal with is obfuscated classes, you can analyse this malware without stepping through the code. Also, since the domains used by the malware are already down, you would not be able to see anything meaningful. The malware pulls lots of configurations and without them you are left with a malfunctioning state machine. Analysis of logs using Logcat can still be useful to understand what activities and services are launched for this specific malware since it uses the Logging capabilities a lot.
Even though this was my first attempt at reversing Android malware, i have felt that reading SMALI is much simpler than reading x86 which is why i have relied solely on static analysis and a bit of dynamic analysis by using an emulator. As far as i know, it is not possible to change the instruction pointer and execute selective chunks of code as you can do on x86. We can however take small chunks of SMALI, compile them and execute them.
Stay safe 😉