Spymax is a mobile Remote Administration Tool (RAT) that enables an attacker to control victims’ devices through an Android malware. Once the malware is installed on a phone, the attacker can execute many attacks that highly impact the confidentiality and integrity of the victim’s data, as well as the victim’s privacy. It is powerful, widely available, and does not require root privileges on the victim’s device. In this blogpost, I show the capabilities of this RAT and analyze how its Android malware works.
Reports about Spymax go back to at least 2019, but it got more popular in 2020. Remember 2020? Probably not your favorite year, unless you’re a Corona virus. Attackers exploited the panic to trick victims to install COVID-related apps injected with Spymax malware. Since then, it kept getting popular. It is alarming that Spymax RAT is widely available on the internet. Its 4th version Spymaxv4 can be easily downloaded from several forums and websites. Any inexperienced attacker can install the “cracked” Spymax RAT on their computer and rely on their social engineering skills to infect victims’ phones. But keep in mind that these “cracked” Spymax versions are probably not the original RAT and that they probably contain other malware that might infect the attacker’s computer.
Spymax’s arsenal of attacks include:
- Stream live video from the phone’s cameras
- Capture live audio from the phone’s microphone
- Track user’s location
- Ransomware: encrypt user’s data
- Capture the victim’s secrets using keylogging and capturing clipboards
- Upload and download files from the mobile device
- Capture user’s SMS, contacts, installed apps, and call logs
- Initiate calls from the victim’s phone
- Execute some commands on the victim’s phone
None of these attacks require root privileges, therefore they work successfully on unrooted devices. Moreover, Spymax works pretty well on Android 9 and below. However, my attacks on an Android 10 device were also successful.
In my research I used Spymaxv2 and Spymaxv4 RAT. Both versions run on Windows only, therefore I ran them on a Windows 10 Virtual Machine. I also used 2 devices to simulate victims: The first is a rooted Nexus 5 device running Android 8, and the other is a Pixel 4a device running Android 10. The VM and both devices are connected to an access point running on my host.
RAT and C&C
Spymax RAT is very easy to use. The main window displays the connected victims and allows the attacker to execute attacks with a right click. Of course, Spymax RAT comes with a Command and Control Server (C&C), which allows the attacker to send commands to the malware.
The malicious app (malware)
The attacker can build Spymax malware from the Build menu. Spymax offers to build a stand-alone APKs that contain only the malware, or bind the malware to a benign app’s APK file. In this blogpost, I analyze the stand-alone APK. In both cases, the address and the port of the C&C are hard-coded in the malware. Additionally, the attacker can change the package name of the app.
After building the malicious app that contains the malware, it is up to the attacker’s social engineering skills to get the app installed on the victim’s device. For example, phishing or spear phishing attacks can trick victims to install the malware on their devices, like what happened in 2020. Alternatively, if the attacker has a physical access to the victim’s device, they can install the malware on it and grant it the necessary permissions. This is a common way to install spyware after all.
I decompiled the APK to analyze its code. Some critical methods such as doInBackground were not successfully decompiled, even using different Android and Java deobfuscators. Moreover, most of the app’s critical class and function names are obfuscated, therefore I renamed them in this blogpost to make it easier to follow. At the end of this blogpost, I match the short names with the real names in the APK, which might help in case you want to research Spymax further. Furthermore, I used Frida to analyze the app dynamically.
A quick static analysis of the app shows that it expectedly requires many permissions, such as access to camera, microphone, storage, location and others. Additionally, the service AccessibilityService requires the “android.permission.BIND_ACCESSIBILITY_SERVICE” permission for keylogging attacks.
Run Spymax run
Spymax app asks for a long list of permissions when the victim starts it for the first time. Additionally, the main activity SpymaxMainActivity starts the main Service MainService. Afterwards, the app does not need to be started anymore by the user. Whenever the phone boots up, Spymax’s boradcast receiver BootReceiver catches the broadcast intent “android.intent.action.BOOT_COMPLETED”, therefore the app automatically starts. BootReceiver eventually starts MainService.
This behavior is found in many apps (malicious or not), which want to start automatically once the phone boots up. However, I was expecting more persistence techniques from the app. Unlike other malware and spyware apps, the Spymax app neither hides itself after the first run, nor does it implement techniques to restart itself once terminated.
MainService completes the initiation routine of the app, which includes 2 main actions:
1. Initiate the connection with Command and Control server (C&C)
Class TxRx acts as the interface between the app and C&C. It takes care of maintaining the connection, as well as sending and receiving data from/to C&C. Its method cnn runs a Thread to (re)initiate the main TCP socket TxRx.k that handles the main communication, as shown in the figure below. Click on the figure to open it in full size.
From now on, TxRx.in and TxRx.out hold incoming and outgoing data. Moreover, the method cnn starts the method rc, which runs another Thread to receive data from C&C.
2. Start the main brain of the malware
MainService contains an inner class ta, whose doInBackground method acts as the main brain of the Spymax app. It is an AsyncTask that runs in a separate thread to take actions based on the commands received from C&C as we will see later.
Now the Spymax app is ready for the attacker’s wishes, so let’s see what happens when the connection establishes with the C&C.
After the connection is established with C&C, the app listens to the received commands and handles them. The flow goes as follows:
1. TxRx.rc() receives the message
As mentioned before, the method TxRx.rc listens to any incoming messages received by the main Socket TxRx.k. Messages between the app and C&C are compressed in gzip format. Therefore, they are first decompressed using the UtilClass.dZp method. Then the decompressed message is cast into a RxCommand object. Any RxCommand object has 2 parameters:
- Byte Array byt – holds all bytes of decompressed message, including files sent by C&C
- String str – the decompressed message converted to String. It usually holds the command sent by C&C
Finally, the method TxRx.rc adds the received command object to the List MainService.Li, which acts as a queue of the received commands that are not yet executed.
The following snippet of rc method highlights its role:
2. Handle the command
Now it’s the brain’s time! MainService.ta.doInBackground method pulls the received command object RxCommand from the list MainService.Li. As we see below, the command string has “x0F0x” as a main delimiter. The RxCommand.str parameter holds the main command, e.g.:
• 0x0F0xplugens.angel.plugens.appsx0F0x8x0F0xrm -r x0F0xdexx0F0xping -c 1 -W 15 x0F0x1x0F0x2x0F0x3x0F0x4x0F0x5x0F0x6x0F0x7x0F0x8x0F0x9x0F0x10x0F0x11x0F0x-2x0F0x-1
The command usually starts with an integer, which defines the main purpose of the command:
0: install an extra APK
1: call a function from an extra APK
2: start capturing camera
3: start capturing GPS location
8: Start keylogger
… And so on.
According to this integer, doInBackground initiates the right component to execute the C&C command.
3. Send result
After the command is executed, the response is compressed and structured using the method UtilClass.f. Afterwards it is sent to C&C via TxRx.se, as shown in the following snippets.
After clarifying the main flow of handling commands, let’s take a look at a couple of scenarios:
Scenario 1: Download APKs
After the app is installed and the connection is established with C&C, the app downloads additional DEX code from C&C in form of APK files, which allows it to execute several attacks. It is quite usual for a mobile malware to start as a benign dropper app, in order to pass scanning algorithms such as Google Play protect. Then it downloads the malicious code from its C&C after installation. But in Spymax’s case, the dropper APK is already capable of performing serious attacks such as streaming from the phone’s camera, capturing location, and keylogging.
Anyway, every time the app starts, it downloads 8 extra APKs from C&C. These APKs deliver the code of the attack groups of apps, calls, contacts, files, info, microphone, SMS, and terminal. For example, the attack group “files” allows the attacker to download, upload, encrypt and decrypt files on the victim’s phone.
Let’s take the attack group “contacts” as an example, which captures and manipulates the victim’s contacts. The corresponding command from C&C to install the APK of “contacts” is translated to the following RxCommand Object:
• RxCommand.str: 0x0F0xplugens.angel.plugens.contactsx0F0x8x0F0xrm -r x0F0xdexx0F0xping -c 1 -W 15 x0F0x1x0F0x2x0F0x3x0F0x4x0F0x5x0F0x6x0F0x7x0F0x8x0F0x9x0F0x10x0F0x11x0F0x-2x0F0x-1
• RxCommand.byt: holds the APK itself
The received command is handled by doIntheBackground method as follows:
1. RxCommand.str is split with the delimiter “x0F0x”
2. The value of the first substring (the starting integer) is checked
3. Since it is equal to 0 in this case, Spymax app needs to install the recently received APK
4. Therefore, the name of the method “plugens.angel.plugens.contacts” and the APK bytes are passed to the method ClassLoader.sl, which in turn:
- Stores the APK in the external storage. The path of my app for this APK was /storage/emulated/0/oe1QG/fBrLA2
- Converts the downloaded DEX to a class using dalvik/system/DexClassLoader
- Then deletes the downloaded APK from external storage, in order to remove its traces
5. The loaded class is cast into a DexClass object, which has 2 parameters to hold the loaded class “plugens.angel.plugens.contacts” and its name respectively
6. The DexClass object is added to the list MainService.Lcl, which holds the downloaded code of attack groups after being cast to DexClass objects
The following figure highlights these steps in doInBackground
Sweet! The APKs are installed and Spymax app is now fully ready and loaded to fire any weapon in its arsenal.
Scenario 2: Execute Dex
Let’s continue with the case of “contacts” attacks. When the attacker wants to capture all contacts stored in the victim’s phone, the app receives the following command:
As mentioned above, doInBackground splits the command string with the main delimiter “x0F0x” into the following:
- 1: Execute an attack from a Loaded Class
- plugens.angel.plugens.contacts: Name of the loaded class: doInBackground method searches in MainService.Lcl for the DexClass object of this name
- method: Name of the function of the loaded class to be executed
- 3EMR853: Honestly, I wasn’t interested in this parameter 🙂
- contacts: String Argument of the executed method
Let’s take a look at the class plugens.angel.plugens.contacts. In the method method(), the string parameter paramString is split with the delimiter SPL_DATA (=x0D0x). Then it is checked in a switch case to know which contact attack it should execute.
Since the command here is just called “contacts”, it executes the following query to capture all contacts
Eventually, the app captures all contacts and sends it to C&C as the following string. The victim’s device has 2 contacts: Test1 and Test2. They are separated by the delimiter SPL_LINE (=x0L0x) and their parameters are separated by SPL_ARRAY (=x0A0x).
The following figure shows the overview of the whole process in doInBackground
Each attack of Spymax is an interesting case on its own. Unfortunately, it would be too much for a single blogpost to analyze other interesting attacks such as live video, ransomeware and remote shell.
Are we doomed?
Spymax was successful for a long time to evade Google Play Protect and other antivirus solutions. Now it is immediately detected as a malicious app by Play Protect once it is installed on any Android device, even old Android 8 devices. However, it’s a never ending cat-and-mouse game, and I will not be surprised if future versions of Spymax implement new ways to evade Play Protect again. It has also been common to hear about malware that found its way on Play Store and managed to get millions of downloads.
So…. to answer the question: No, we are not doomed, but we are not very safe either. Here is the usual prescription to protect yourself as much as possible from mobile malware:
- Don’t install any apps from unknown sources.
- Don’t disable Play Protect on your phone.
- Don’t enable “Accessibility Service” to any app, unless you really trust it, otherwise you render yourself vulnerable to keylogging attacks.
- Don’t install apps that require many unnecessary permissions even from Google Play store.
- And even though it did not matter with Spymax, but DON’T ROOT YOUR PHONE.
Original names of functions in APK
- SpymaxMainActivity: snkgiankwkgadg3758
- MainService: fbrtiekisdyeitmavzhjjhdzbguqndztwhahvawxyuq37511
- UtilClass: srbjtvpeeibtffvdkkorcxuasnlhmvfhcjdiunfzawyyejywajoflgvuxbrfjhrictqvcmiwfoqgyvvipogdhzvwniltwz3753
- TxRx: cggcdcvmyqax3752
- ClassLoader: fbrtiekisdyeitmavzhjjhdzbguqndztwhahvawxyuq37510
- AccessibilityService : fbrtiekisdyeitmavzhjjhdzbguqndztwhahvawxyuq37512
- RxCommand: qlwzaajkjsskv3757
- DexClass: vmrfpprwvisfdurzmoyaazwoodjsmphamvqhqtkavrfjntebididalowqdqlgz3750
If you are interested in other blogposts related to mobile security, you can check the following blogposts:
If you want to know more about Spymax, the following blogpost focuses on Spymax’s communication with C&C very well:
Would you like to share your experience with similar Android malwares? I would be delighted by your comments 🙂