Android/BianLian payload

@cryptax
9 min readJan 17, 2022

--

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:

  1. 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
  2. The second DEX — which implements the malicious payload of the bot. This is what we discuss in this article. Its sha256 is d0d704ace35b0190174c11efa3fef292e026391677ff9dc10d2783b4cfe7f961
  3. 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.

Decrypting the preferences entry “admin_panel_url_”
The XOR key is composed of characters !8[`. For example “IL/p:/trI]:cNT7iDJhQ53iNV]9sHL>” decrypts to hxxp://rheacollier31532.website

The remote attacker and the bot exchange a JSON string, where JSON keys specify actions (or responses) to conduct.

List of commands understood by the BianLian bot. The commands are keys within a JSON object, and values specify command arguments. The JSON object is sent or received from the C&C.
List of Bian Lian bot responses to commands.

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):

In this case, the C&C was interested in many mobile turkish bank apps.

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).

For example, in this case, the bot notifies the C&C 3 interesting mobile apps are installed.

When an app among this list is launched, the bot requests the C&C an HTML page to overlay.

In this network capture, the bot requests an HTML page to display above the bank’s application.

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.

Beware the malicious overlay! This screenshot was taken on an infected Android emulator. If we are cautious, we can spot the trick here because the overlay is not perfect: the real app is running behind (we see the real logo at the top) and the malicious page is overlaid in front. This is actually not an image but an entire HTML page, with hard-coded embedded logo images, layout and JavaScript. The card number, expiration date & CVV are sent back to the C&C.

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.

Decompiled code of the malware’s team viewer component. The Accessibility Service is used to see which node/view is currently displayed, locate the relevant button and automatically click on it. Team Viewer is automatically configured by automatically entering username/password inside the right text views of the application.
To abuse Accessibility Services, the malware requests initial permissions. Yes, in theory, an end-user should not click “OK” to such a request, but let’s be honest, there are many pop-ups on a smartphone & it’s not always clear to the end-user what they are authorizing. That’s how we end up with an infected smartphone…

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.

This is the part of the bot’s code that disables notification for an app. The bot opens the notification settings for a given app. At this point, the method above gets called. It checks whether the notification switch is already checked or not. If checked, it unchecks it. If not checked, it leaves it unchecked and continues to the next app.

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 screen capture is requested, the system normally displays a system UI pop-up asking for confirmation. The code above checks this is the confirmation pop-up, that it requests screen capture for the Video Player (the sample poses as a Video Player app) and automatically confirms & remembers the choice.

When a screenshot is ready, it is sent to the C&C in base64 format.

Encode bitmap in Base64 and send it to C&C. If upload fails, stop screen cast service.

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.

Task of the PIN code component

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.

Automatically authorizing install of APKs from external sources

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!

Processing C&C commands to delete applications

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.

Code calling a given phone number (USSD)

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.

Code in com.pmmynubv.nommztx.bot.components.h.k

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.

Code in com.pmmynubv.nommztx.bot.components.g.a

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

--

--

@cryptax

Mobile and IoT malware researcher. The postings on this account are solely my own opinion and do not represent my employer.