In the previous article, we discussed the packing mechanism of a Bian Lian sample, and how to unpack. This article reverse engineers the payload of the malware. It explains:
- The malicious components the bot implements. Those components can be seen as independent modules, and they are launched at the beginning. Each of them do their job, handle accessibility events which concern and notifies or responds to the C&C. The implementation is clearly organized to easily welcome future modules.
- The communication between the C&C and the bot. The bot understands and responds to several commands. The commands are implemented in the relevant component. The communication protocol is fairly simple: over HTTP (not HTTPS), with a plaintext JSON object as data (no encryption).
- The implementation of each major component.
Three DEXes
To be precise, note the Bian Lian we discuss uses three different DEX:
- The main APK’s DEX — which is responsible for decrypting and loading via multidex the second DEX. For reminder, the APK’s sha256 is
5b9049c392eaf83b12b98419f14ece1b00042592b003a17e4e6f0fb466281368
- The second DEX — which implements the malicious payload of the bot. This is what we discuss in this article. Its sha256 is
d0d704ace35b0190174c11efa3fef292e026391677ff9dc10d2783b4cfe7f961
- A third DEX. It is downloaded by the second DEX from the remote C&C, but is not interesting for the analysis of the malware because it only contains non-malicious utility functions. Its package name is
com.fbdev.payload
.
Reverse engineer is loooong
This reverse engineering took me several days. Actually, between unpacking, reverse engineering and writing the blog, it approximately took me 2 weeks! I am not particularly proud about it, but I often get the question “whow, how long did it take you?” and although I’d love to appear extremely skilled, the reality is that reverse engineering is a long process. It can be compared to puzzles or a plate of spaghetti: at first, you don’t know where to start, you follow a path and often get lost in the middle and soon don’t exactly know what you were searching for 😄
Consequently, I am sharing my JEB project (which contains all the functions I renamed, my comments etc): you can download it here.
Also, the article ends with a few remaining questions on the reverse engineering of the sample. You are welcome to interact if you have an idea.
Now, let’s start!
Overview of malicious components
This malware is a bot, which reports and receives commands from a remote server (C&C). It implements several malicious components:
- Bulk SMS. The attacker specifies the body of a SMS to send, and it is sent to all contacts of the victim’s smartphone.
- Inject. The attacker provides an image to download from the web and inject (overlay) on a given list of apps.
- Install Apps. The attacker specifies a list of applications to install on the phone.
- Locker. This disables the ringer, and displays a text taken randomly from a pool of possible messages.
- Notification Disabler. Disables notifications of given applications.
- PIN code. Steals the lock PIN code for some phone brands. The sample we analyze supports Samsung and Huawei.
- SMS. This is to send specific SMS messages. The attacker specifies the body and phone number to send to.
- Screencast. Takes screenshots of given applications.
- Sound switch. Turn ringer on or off.
- Team viewer. The Team Viewer app is a well known non-malicious app to access your smartphone from any other computer. Here, the attacker uses it to access the victim’s smartphone remotely.
- USSD. The attacker specifies the premium phone number to call. For the victim, this may result in extra cost, depending on his/her subscription.
Communication with the C&C
The URL to the remote C&C is found encrypted in the shared preferences file pref_name_setting.xml
. The algorithm uses slightly modified XOR algorithm with a hard-coded key derived from the string sorry!need8money[for`food
.
The remote attacker and the bot exchange a JSON string, where JSON keys specify actions (or responses) to conduct.
Malicious injections
The bot implements an injection module which overlays attacker chosen images on top of target applications.
First, the bot reports its activity to the C&C. The attacker answers back to the bot with a list of applications it is interested to inject into (see “stockInjects” key):
The bot searches which of these apps are installed on the victim’s phone and reports the information back to the C&C (see “app_list” key).
When an app among this list is launched, the bot requests the C&C an HTML page to overlay.
From victim’s point of view, everything happens fast and it is not easy to detect something fishy is happening: the victim opens his/her mobile banking app. S/he will perhaps notice a quick screen flickering: this occurs when the bot has downloaded the attacker’s HTML and overlays it on top of the real app. See below an example of overlay.
Team Viewer component
The bot support “teamViewerOptions” command which triggers the Team Viewer app to remotely access and control the victim’s smartphone. The C&C sends a username and password, and the bot (1) launches the Team Viewer app (if necessary), (2) accepts the EULA displayed by KLMS Agent on Samsung devices (security framework), (3) enters username and password in Team Viewer and (4) finally connects to the remote end.
This functionality heavily relies on using (abusing) the Accessibility Service.
Disabling notifications
The C&C sends a command “disabledPackages” with a list of package names to disable notifications for. The bot processes those packages one by one, launches the notification settings panel and uses the Accessibility Service API to ensure the notification switch for the app is turned off.
Screencast component
The C&C may also send a “showScreen” which is implemented by the Screencast component of the bot.
First of all, if the device is locked, the bot broadcasts a swipe action to unlock.
Intent intent = new Intent(InjAccessibilityService.broadcast_swipe_unlock); // "broadcast_swipe_to_unlock_action"
intent.putExtra("task", 669);
Context.this.sendBroadcast(intent);
Then, it starts an activity that initiates screen capture.
if(!this.active && this.mediaprojectmgr != null) { activity.startActivityForResult(this.mediaprojectmgr.createScreenCaptureIntent(), 0x1E240); }
This should normally prompt the end user if s/he accepts screen capture: the bot handles this and automatically accepts it on user’s behalf.
When a screenshot is ready, it is sent to the C&C in base64 format.
Unless an error occurs, a new screenshot will be taken in a second. This can get pretty intensive and slow down the phone, which probably explains why the bot displays a fake notification saying the phone is currently updating Google Play!
this.startForeground(0x74A, new Notification.Builder(this.getApplicationContext()).setContentTitle("Google").setContentText("Update Google Play Service").setSmallIcon(0x7F050001).setProgress(0, 100, true).build());
Locker component
When the bot receives the “locked” command with a flag set to True, it sets the ringer to silent mode and displays an activity meant to have the victim believe a recovery is under progress. The displayed messages are initially the following:
Android system corrupted files recovery <3e>
Kernel version 2.1.0.3
DO NOT TURN THE SYSTEM OFF
The mechanism to lock the device is simple: the message is displayed full screen, without navigation buttons, and the bot prevents any window focus change. This results in the user being locked on the given screen.
private void fullScreen() {
this.getWindow().getDecorView().setSystemUiVisibility(0xF06); // SYSTEM_UI_FLAG_FULLSCREEN=4 | SYSTEM_UI_FLAG_HIDE_NAVIGATION=2
}public void onWindowFocusChanged(boolean arg5) {
super.onWindowFocusChanged(arg5);
if(arg5) {
this.fullScreen();
}
}
When the C&C sends a “locked” command with flag to False, the bot simply kills the locking activity and the victim may resume its usage of the phone.
PIN code component
When the bot receives a “action_request_pin” command, it tries to steal the victim’s PIN. Depending on the device, it asks the victim to set a new password and steals it by monitoring the Accessibility API, or it steals the current PIN by overlaying a fake PIN code request window.
If the C&C provides a “approvedPin” command, the bot will additionally try to modify the current PIN with the new value selected by the C&C.
Install component
The C&C may send a list of apps to install via command “apks”. The applications are downloaded from a URL specified in the command. The installation is performed by abusing the Accessibility API. The code is quite lengthy because there are many cases: check the event occurs in the system installer, if the app installer occurs in an alert dialog then automatically click to install. If the system is requesting permission to install from an external source, authorize it etc.
The same component also deals with removal of applications. The command names are misleading “remove_all” uninstalls only Team Viewer, and “remove_by_id” removes a specified app. If the package name is “bot”, then the bot removes itself. A self “cleaning” command!
Sound component
The C&C may turn on or off the ringer via command “soundEnabled” followed by a boolean. Turning the ringer on / off is performed simply by a call to setRingerMode
.
USSD component
The bot may be instructed to call USSD (quick codes). For instance, we see it requests *101# which returns the current subscription rate.
SMS component
The bot has the capability to spy on incoming SMS and report the messages to the C&C. This feature is quite common in malware, and performed by reading the incoming PDU — as usual.
The bot can also be instructed to send SMS specified by the “sms” command. The SMS is sent using the common sendTextMessage
API.
this.sendSms(command.get("id").toString(), command.get("phone_number").getString(), command.get("message").getString()); // calls sendTextMessage
Unsure / Do you know why? Contact me!
When prem_flag
is set, the bot sends a SMS to notify a new victim has “registered” to the botnet. The SMS is sent to phone number “0001”, which is strange because it should not correspond to anything. Unless there is a trick with SMS filtering.
The sound component implements a lengthy onAccessibilityEvent()
method which handles events on settings, policy and sound. I have not understood why this is necessary when setRingerMode
does the job.
Finally, in the SMS component (com.pmmynubv.nommztx.bot.components.h.a
), it is not clear why the bot also implements sending SMS by abusing the SMS application and automatically clicking through the nodes — when sendTextMessage
does the job in far less lines of code 😏
— the Crypto Girl