Introduction
We sometimes come across modified applications when analyzing suspicious files. These are created in response to user requests for more customization options within the app or for new features that the official versions don’t have. Unfortunately, it’s not uncommon for popular mods to contain malware. This often happens because they’re distributed on unofficial websites that don’t have any moderation. For example, last year we found popular WhatsApp mods infected with CanesSpy and distributed this way. Before that, we found ads for WhatsApp mods infected with the Triada Trojan dropper in the popular Snaptube application. However, even official app stores can be infiltrated by infected apps. In 2019, we discovered the Necro dropper hidden within CamScanner, a widely used document scanning and processing app available on Google Play. At the time of the malware discovery, this app had been downloaded to more than 100 million devices worldwide. Sadly, history has repeated itself, and this time the Trojan authors exploited both distribution vectors: the new version of the multi-stage Necro loader infected both apps in Google Play and modified versions of Spotify, Minecraft, and other popular applications in unofficial sources.
Our conclusions in a nutshell:
The new version of the Necro Trojan has infected various popular applications, including game mods, with some of them being available on Google Play at the time of writing this report. The combined audience of the latter exceeds 11 million Android devices.
The new version of the Necro loader, like most payloads it loads, has begun to use obfuscation to evade detection.
The loader, embedded in some applications, used steganography techniques to hide payloads.
The downloaded payloads, among other things, could display ads in invisible windows and interact with them, download and execute arbitrary DEX files, install applications it downloaded, open arbitrary links in invisible WebView windows and execute any JavaScript code in those, run a tunnel through the victim’s device, and potentially subscribe to paid services.
How Necro spreads
Necro loader inside a Spotify mod
In late August 2024, our attention was drawn to a Spotify mod called Spotify Plus, version 18.9.40.5. At the time of writing this, the mod could be downloaded from spotiplus[.]xyz and several related sites that linked to it. The original website claimed that the mod was certified, safe, and contained numerous additional features not found in the official app. We decided to verify the claims about the application’s safety by downloading the latest version from this website (acb7a06803e6de85986ac49e9c9f69f1) and analyzing it.
The mod implements a custom Application subclass that initializes an SDK named adsrun in its
onCreate method. This SDK is intended for integrating several advertising modules into the application: among other things, it initializes a module named Coral SDK. Upon activation, Coral SDK transmits a POST request to a designated command-and-control server. This request contains encrypted JSON data, specifically detailing the compromised device and the application hosting the module. The encryption method employed is a substitution cipher, where the substitution values are generated using a standard Java pseudo-random number generator seeded with a predefined constant. See an example of data sent by the module below.{
“appId”: “REDACTED”,
“channelId”: “com.spoti.plus”,
“androidId”: “REDACTED”,
“isAdb”: false,
“isProxy”: false,
“isSimulator”: false,
“isDebug”: false,
“localShellVer”: 0,
“sdkVer”: 116,
“appVersion”: “1020000005”,
“appVersionName”: “18.9.40.5”
}
The C2 server returns a JSON response with an error code, encrypted with the same method. A value of 0 indicates successful execution. In this case, the response from the C2 will also contain an array of one object with a link to download the image in PNG format and associated metadata: name, MD5, version, and so on. Intriguingly, the downloaded file is termed “shellP”, suggesting it might be a condensed form of “shellPlugin”.
{
“code”: 0,
“result”: [{
“md5”: “F338384C5B4BC7D55681A3532273B4EB”,
“name”: “shellP”,
“sdkver”: 100,
“url”: “hxxps://adoss.spinsok[.]com/plugin/shellP_100.png.png”
}
]
}
Next, the module verifies the integrity of the downloaded image by calculating its MD5 hash and comparing it to the value received from the server. A payload is hidden in this image using steganography, which the module must extract and execute in the next step.
Coral SDK uses a very simple steganographic algorithm. If the MD5 check is successful, it extracts the contents of the PNG file — the pixel values in the ARGB channels — using standard Android tools. Then the
getPixel method returns a value whose least significant byte contains the blue channel of the image, and processing begins in the code.
If we consider the blue channel of the image as a byte array of dimension 1, then the first four bytes of the image are the size of the encoded payload in Little Endian format (from the least significant byte to the most significant). Next, the payload of the specified size is recorded: this is a JAR file encoded with Base64, which is loaded after decoding via DexClassLoader. Coral SDK loads the
sdk.fkgh.mvp.SdkEntry class in a JAR file using the native library libcoral.so. This library has been obfuscated using the OLLVM tool. The starting point, or entry point, for execution within the loaded class is the run method.
Therefore, the security claims made about the application on the mod website can be considered false.
Popular applications in Google Play are infected with Necro
Having searched for the loader in our telemetry, we found other apps infected with Necro, including those available in Google Play at the time of writing this report. Their combined audience numbered more than 11 million Android devices.
Our first find is the Wuta Camera app. Judging by its page in Google Play, it was downloaded at least 10 million times. According to our data, the Necro loader has been embedded in it starting from version 6.3.2.148. The latest version of the app at the time of collecting information, 6.3.6.148 (1cab7668817f6401eb094a6c8488a90c), which was available on Google Play, also had the Necro loader. We reported the presence of malicious code to Google Play, after which the loader was removed from the app in version 6.3.7.138.
The second infected app we found was Max Browser.
This browser, according to Google Play, has been installed more than a million times and, starting with version 1.2.0, also contained the Necro loader. After we reported it, Google took down the infected app from their store.
WhatsApp mods with the Necro loader
We also found WhatsApp mods containing the Necro loader (0898d1a6232699c7ee03dd5e58727ede) in unofficial sources. The infected application is distributed under the package name
com.leapzip.animatedstickers.maker.android. Interestingly, there’s a legitimate app on Google Play with the exact same package name that isn’t a WhatsApp mod, but instead offers a collection of stickers for the messaging app.
The loader contained within the ad module in these applications functions somewhat differently from the sample described above. For instance, the code isn’t obfuscated at all but is protected by the SecAPK code protector. Additionally, the application uses Google’s Firebase Remote Config cloud service as a C2, storing information about files that need to be downloaded and executed.
While examining this loader, we discovered an interesting quirk: the malicious code within it has an 84% or 90% chance of execution. Initially, a random number between 0 and 99 is generated. Subsequently, based on the application package name, a threshold for malware execution is selected: the generated number must exceed either 9 or 15 for the loader to launch. If the number meets this criterion, a corresponding flag inhibiting loader operation is set to
false, and the malicious functionality is executed.
Intermediate payloads downloaded by this loader are not pre-encoded. The Trojan receives both the entry point information for the downloaded file and the download link from its C2 server. According to our data, one of the payloads (37404ff6ac229486a1de4b526dd9d9b6) bore resemblance to a loader found in a modified version of Spotify, albeit with minor variations.
The next-stage payload (shellPlugin) is loaded without the aid of native code.
A different path is used for the POST request to the command-and-control server to retrieve shellPlugin information.
Instead of using the steganographic algorithm, shellPlugin is decoded with Base64.
Other infected applications
This is not an exhaustive list of our findings. In addition to Spotify and WhatsApp mods, as well as apps in Google Play, we found infected game mods, including the following:
Minecraft;
Stumble Guys;
Car Parking Multiplayer;
Melon Sandbox.
Given that various apps from multiple sources, including official ones, were found to be infected, we believe that the developers used an untrusted solution for ad integration. This led to a malicious loader appearing in the apps. Our security solutions detect it with the following verdicts:
HEUR:Trojan-Downloader.AndroidOS.Necro.f;
HEUR:Trojan-Downloader.AndroidOS.Necro.h.
The Necro lifecycle in the wild: how the payload works
During our research, we managed to obtain several samples of payloads that the loader subsequently executes. This particular payload (fa217ca023cda4f063399107f20bd123) exhibits several interesting characteristics that allow us to classify it as belonging to the Necro family:
The loader obtains download information from the C2 domain bearsplay[.]com. According to our telemetry data, the domain has been contacted by Necro-family malware.
According to our data, the C2 domains that this file interacts with are also being used by the Necro and xHelper Trojans.
The functionality of this new payload is very similar to the previous version of Necro (402b91c6621b8093d44464fc006e706a). The code of the Trojans is also similar, but in this new payload, the attackers have used an obfuscator to make it harder for security solutions to detect and analyze.
The payload configuration structure is identical to that of older versions of Necro, including the one we previously discovered in the CamScanner app. The field names in the configuration match the corresponding fields in other Necro versions.
Based on this, we assert that both the examined payload and the original loader belong to the Necro family, which is familiar to us.
Payload structure
Now let’s move on to analyzing the payload. The second stage of the launch process reads a JSON-formatted configuration embedded within the code. An example of the configuration is provided below.
{
“hs”:{
“server”:”https://oad1.azhituo.com:9190″,
“default”:”https://oad1.azhituo.com:9190″,
“dataevent”:”https://oad1.azhituo.com:9190″,
“PluginServer”:”https://oad1.azhituo.com:9190″
},
“ps”:{
“web”:”canna”,
“dsp”:”hatch”
},
“mp”:{
“PMask”:”159″
},
“rp”:{}
}
The
rp switch might contain malicious services to be launched, but it was empty in the samples we analyzed.
The
mp configuration switch holds parameters for the second-stage loader. It’s likely an abbreviation for “module parameters”.
The malicious functionality of Necro is implemented in additional modules that are downloaded from the C2 server. The malware authors frequently refer to these as “plugins” in the code. The
ps configuration field (likely an abbreviation for “plugin stop list”, meaning a list of prohibited plugins) is necessary to block these modules. The switches in this object are the names of plugins that are forbidden to load, and the values are alternative plugins that can be executed instead of the blocked ones if they were loaded. The download ban will be applied if the mp field has the PluginControl flag set to true. However, in the samples we were able to obtain, the restrictions did not apply. Additionally, the mp field may contain the PluginUpdateFeature flag, which controls plugin updates. If this flag is not present, plugins will be updated by default.
The
hs switch in the configuration stores a list of C2 addresses which the Trojan will talk to. Note that the malware logic does not require all addresses to match, although in the sample we examined, they were identical. The Trojan needs each address to perform the following tasks:
server is used to update the PluginServer server address. To do this, the Trojan first sends a POST request containing the ID of the malicious implant and the name of the application package it’s embedded into. After that, the server can send a new PluginServer address. If the address cannot be updated, the value from the configuration set in the code is used.
dataevent is used to store various events related to SDK activity.
default is not used at this stage.
PluginServer instructs the Trojan which plugins to download. Initially, a large amount of data is sent to this server. This includes information about the infected device (screen size, RAM, IMEI, IMSI, operating system version), information about the device’s environment (whether USB debugging mode and developer mode are enabled, if emulator artifacts are detected, etc.), details about the infected app, and so on.
In response, the server sends a list of plugins to download. These are downloaded asynchronously. To do this, the malware registers a broadcast receiver, and a separate thread, which is started for the download, sends a broadcast message when a plugin is ready to be downloaded. The plugins are differentiated by their name, which is also provided by the server.
Plugin encryption and loading
The plugin loading code supports, among other things, the ability to decrypt plugins using various methods. Additionally, payloads can be extracted beforehand using the steganographic algorithm described above if a file with a .png extension was downloaded. The decryption method is specified in the file URL. The following options are available:
new/enc: decryption with a substitution cipher similar to that used for C2 communication
ssd: plugin decryption using the DES algorithm
ori: unencrypted plugin
If no encryption method is specified, the plugin will be decrypted using a substitution cipher. The initial seed for this cipher will be the
PMask parameter (short for plugin mask), which is defined in the mp object within the loader configuration. Once decoded, plugins can be loaded in various ways.
dex: this method loads the plugin using DexClassLoader. The loader provides it with the application and plugin context, and additional plugin information.
res: this method allows loading plugins with new resources. These resources can be used to download more plugins in the future.
apk: a method that allows sending information about a downloaded file to a service via the IPC Binder mechanism. The name of the service is specified in the bird_vm_msg_service property. While it’s not definitively known which services Necro used, we can speculate that this function is used to install arbitrary APK files on the victim’s device.
Types of plugins
To better understand the attackers’ goals, we decided to thoroughly examine the payloads downloaded by the Trojan and, after analyzing telemetry data, found several Necro modules.
ed6c6924201bc779d45f35ccf2e463bb – Trojan.AndroidOS.Necro.g
This is a Necro module named “NProxy”. Its purpose is to create a tunnel through the victim’s device. When launched, the module connects to a server defined in the code.
This server acts as a C2 server that the Trojan talks to via an unidentified protocol implemented over TCP sockets. The C2 sends commands, which the Trojan processes. After processing, the Trojan forwards traffic from one endpoint to another through the victim’s device.
b3ba3749237793d2c06eaaf5263533f2 – Trojan.AndroidOS.Necro.i
We named this plugin “island”. When launched, the plugin generates a pseudo-random number, which it uses as an interval (in milliseconds) between displays of intrusive ads.
ccde06a19ef586e0124b120db9bf802e – Trojan.AndroidOS.Necro.d
This plugin is named “web”, and it is one of the most popular Necro plugins, judging by our telemetry data. Its code contains a configuration similar in structure to the shellPlugin payload configuration in the previous stage. It’s interesting that the code for this plugin contains artifacts of older versions of Necro.
Depending on the value of the
CheckAbnormal flag, the plugin checks for the presence of a debugger in the execution environment and if a phone is connected via USB using ADB. If either condition is met, the Trojan clears the Logcat log to hide traces of its activity. Additionally, the plugin verifies if it has the permission to display windows on top of other applications. After all these checks, it launches a malicious task that runs once every two hours. When the malware starts, it sends a POST request containing details about the infected device to the server server. This is done to get the address of another server, named main URL, which the Trojan will communicate with frequently. If there’s an error when getting this address, the malware will fall back to using a server named default.
The received
main URL serves as the C2 server: it sends a list of pages to the Trojan, which the malware later opens in the background before processing the interactive elements contained on them. This functionality has a couple of interesting features. First, the Trojan code contains some artifacts that indicate it might be running with elevated privileges. However, Android processes with elevated privileges do not allow WebView by default. Privilege checks occur directly when creating an instance of the WebView factory: in privileged processes, it won’t be created. To circumvent this restriction, the Trojan creates an instance of the factory directly using reflection, thus bypassing all checks of the current process.
Secondly, the Trojan can download and run other executables, which are then used to replace links loaded with WebView. Combined with the functionality described above, this theoretically allows to do things like adding any additional information to the URL parameters of a replaced link, such as confirmation codes for paid subscriptions, as well as executing other arbitrary code when loading specific links.
36ab434c54cce25d301f2a6f55241205 – Trojan-Downloader.AndroidOS.Necro.b
This module is named “Happy SDK”. Its code partially combines the NProxy and web modules logic, as well as the functionality of the previous stage of the loader with a few minor differences:
The code lacks the Trojan configuration, and backup C2 servers are located by default in the corresponding methods.
The code corresponding to the “web” plugin lacks the functionality to execute arbitrary code.
Note that we have occasionally encountered this SDK under the name “Jar SDK”. Analysis has shown that Jar SDK is a new version of Happy SDK.
We believe this is a different variant of Necro where the developers have opted for a non-modular architecture in the malicious SDK. This suggests that Necro is highly adaptable and can download different iterations of itself, perhaps to introduce new features.
874418d3d1a761875ebc0f60f9573746 – Trojan.AndroidOS.Necro.j
We dubbed this plugin “Cube SDK”. It’s pretty simple and acts as a helper: its only job is to load other plugins to handle ads in the background.
522d2e2adedc3eb11eb9c4b864ca0c7f – Trojan.AndroidOS.Necro.l
This plugin, in addition to NProxy’s functionality, has an entry point for another plugin we’ve named “Tap”. Judging by its code, the latter is still under development: it contains a lot of unused functionality for interacting with ad pages. Tap downloads arbitrary JavaScript code and a WebView interface from the C2 server, which are responsible for viewing ads in the background. Among other things, the plugin includes
com.leapzip.animatedstickers.maker.android as the package name of the infected app. This confirms that the WhatsApp mod loader described earlier, which uses Firebase Remote Config as a C2, also belongs to the Necro family.
These are all the payloads we were able to find during our research. For simplicity, we’ve combined all the processes described above into a single diagram illustrating all stages of the Necro Trojan.
It’s worth noting that the creators of Necro may regularly release new plugins and distribute them among infected devices, selectively or otherwise, for example, depending on the information about the infected application.
Victims
According to Google Play data, the infected applications could have been downloaded over 11 million times. However, the actual number of infected devices might be much higher, considering that the Trojan also infiltrated modified versions of popular apps distributed through unofficial sources.
KSN data shows that our security solutions blocked over ten thousand Necro attacks worldwide between August 26th and September 15th. Russia, Brazil, and Vietnam experienced the highest number of attacks. The chart below illustrates the distribution of Necro attacks across countries and territories where users most frequently encountered the Trojan.
Necro attacks by country and territory, August 26 through September 15, 2024 (download)
Conclusion
The Necro Trojan has once again managed to attack tens of thousands of devices worldwide. This new version is a multi-stage loader that used steganography to hide the second-stage payload, a very rare technique for mobile malware, as well as obfuscation to evade detection. The modular architecture gives the Trojan’s creators a wide range of options for both mass and targeted delivery of loader updates or new malicious modules depending on the infected application. To avoid being infected with this malware:
If you have any of the aforementioned Google Play apps installed and the versions are infected, update the app to a version where the malicious code has been removed, or delete it.
Download applications from official sources only. Applications installed from unofficial platforms may contain malicious functionality.
Use a reliable security solution to protect your device from attempts to install malware.
Indicators of compromise
Applications infected with the loader
Application
Version
MD5
Wuta Camera
6.3.6.148
1cab7668817f6401eb094a6c8488a90c
6.3.5.148
30d69aae0bdda56d426759125a59ec23
6.3.4.148
4c2bdfcc0791080d51ca82630213444d
6.3.2.148
4e9bf3e8173a6f3301ae97a3b728f6f1
Max Browser
1.2.4
28b8d997d268588125a1be32c91e2b92
1.2.3
52a2841c95cfc26887c5c06a29304c84
1.2.2
247a0c5ca630b960d51e4524efb16051
1.2.0
b69a83a7857e57ba521b1499a0132336
Spotify Plus (spotiplus[.]xyz)
18.9.40.5
acb7a06803e6de85986ac49e9c9f69f1
GBWhatsApp
2.22.63.16
0898d1a6232699c7ee03dd5e58727ede
FMWhatsApp
20.65.08
1590d5d62a4d97f0b12b5899b9147aea
Loader C2 server
oad1.bearsplay[.]com
shellPlugin versions
URL
MD5 of the extracted file
hxxps://adoss.spinsok[.]com/plugin/shellP_100.png.png
fa217ca023cda4f063399107f20bd123
hxxps://adoss.spinsok[.]com/plugin/shellE_30.png
59b44645181f4f0d008c3d6520a9f6f3
Second-stage payload
37404ff6ac229486a1de4b526dd9d9b6
Second-stage payload C2 server
oad1.azhituo[.]com
Plugins (third stage)
Plugin name
MD5
Verdict
NProxy
ed6c6924201bc779d45f35ccf2e463bb
Trojan.AndroidOS.Necro.g
Cube
874418d3d1a761875ebc0f60f9573746
cfa29649ae630a3564a20bf6fb47b928
Trojan.AndroidOS.Necro.j
Island
b3ba3749237793d2c06eaaf5263533f2
Trojan.AndroidOS.Necro.i
Web/Lotus SDK
ccde06a19ef586e0124b120db9bf802e
Trojan.AndroidOS.Necro.d
Happy SDK
36ab434c54cce25d301f2a6f55241205
Trojan-Downloader.AndroidOS.Necro.b
Jar SDK
1eaf43be379927e050126e5a7287eb98
Trojan-Downloader.AndroidOS.Necro.b
Tap
522d2e2adedc3eb11eb9c4b864ca0c7f
Trojan.AndroidOS.Necro.l
Plugin C2 servers
47.88.246[.]111
174.129.61[.]221
47.88.245[.]162
47.88.190[.]200
47.88.3[.]73
hsa.govsred[.]buzz
justbigso[.]com
bear-ad.oss-us-west-1.aliyuncs[.]com