Malware descriptions

SparkKitty, SparkCat’s little brother: A new Trojan spy found in the App Store and Google Play

In January 2025, we uncovered the SparkCat spyware campaign, which was aimed at gaining access to victims’ crypto wallets. The threat actor distributed apps containing a malicious SDK/framework. This component would wait for a user to open a specific screen (typically a support chat), then request access to the device’s gallery. It would then use an OCR model to select and exfiltrate images of interest. Although SparkCat was capable of searching for any text within images, that campaign specifically targeted photos containing seed phrases for crypto wallets. The malware was distributed through unofficial sources as well as Google Play and App Store. Now, we’ve once again come across a new type of spyware that has managed to infiltrate the official app stores. We believe it is connected to SparkCat and also targets the cryptocurrency assets of its victims.

Here are the key facts about this new threat:

  • The malware targets both iOS and Android devices, and it is spreading in the wild as well as through the App Store and Google Play. The app is already removed from the latter.
  • On iOS, the malicious payload is delivered as frameworks (primarily mimicking AFNetworking.framework or Alamofire.framework) or obfuscated libraries disguised as libswiftDarwin.dylib, or it can be embedded directly into the app itself.
  • The Android-specific Trojan comes in both Java and Kotlin flavors; the Kotlin version is a malicious Xposed module.
  • While most versions of this malware indiscriminately steal all images, we discovered a related malicious activity cluster that uses OCR to pick specific pictures.
  • The campaign has been active since at least February 2024.

It all began with a suspicious online store…

During routine monitoring of suspicious links, we stumbled upon several similar-looking pages that were distributing TikTok mods for Android. In these modified versions, the app’s main activities would trigger additional code. The code would then request a Base64-encoded configuration file from hxxps://moabc[.]vip/?dev=az. A sample decoded configuration file is shown below.

The links from the configuration file were displayed as buttons within the app. Tapping these opened WebView, revealing an online store named TikToki Mall that accepted cryptocurrency as payment for consumer goods. Unfortunately, we couldn’t verify if it was a legitimate store, as users had to register with an invitation code to make a purchase.

Although we didn’t find any other suspicious functionality within the apps, a gut feeling told us to dig deeper. We decided to examine the code of the web pages distributing the apps, only to find a number of interesting details suggesting they might also be pushing iOS apps.

iOS app delivery method

And sure enough, visiting the website on an iPhone triggers a series of redirects, ultimately landing the user on a page that crudely mimics the App Store and prompts them to download an app.

iOS app download page

iOS app download page

As you know, iOS doesn’t just let you download and run any app from a third-party source. However, Apple provides members of the Apple Developer Program with so-called provisioning profiles. These allow a developer certificate to be installed on a user device. iOS then uses this certificate to verify the app’s digital signature and determine if it can be launched. Besides the certificate, a provisioning profile contains its expiration date and the permissions to be granted to the app, as well as other information about the developer and the app. Once the profile is installed on a device, the certificate becomes trusted, allowing the app to run.

Provisioning profiles come in several types. Development profiles are used for testing apps and can only be distributed to a predefined set of devices. App Store Connect profiles allow for publishing an app to the App Store. Enterprise profiles were created to allow organizations to develop internal-use apps and install them on their employees’ devices without publishing them on the App Store and without any restrictions on which devices they can be installed on. Although the Apple Developer Program requires a paid membership and developer verification by Apple, Enterprise profiles are often exploited. They are used not only by developers of apps unsuitable for the App Store (online casinos, cracks, cheats, or illegal mods of popular apps) but also by malware creators.

Example of a provisioning profile installed to run a malicious TikTok mod

In the case of the malicious TikTok mods, the attackers used an Enterprise profile, as indicated by the following key in its body:

It’s worth noting that installing any provisioning profile requires direct user interaction, which looks like this:

Profile installation flow

Profile installation flow

Looking for copper, found gold

Just like its Android counterpart, the installed iOS app contained a library that embedded links to a suspicious store within the user’s profile window. Tapping these opened them in WebView.

Suspicious store opened inside a TikTok app

Suspicious store opened inside a TikTok app

It seemed like a straightforward case: another mod of a popular app trying to make some money. However, one strange detail in the iOS version caught our attention. On every launch, the app requested access to the user’s photo gallery – highly unusual behavior for the original TikTok. Furthermore, the library containing the store didn’t have code accessing the photo gallery, and the Android version never requested image permissions. We were compelled to dig a little deeper and examine the app’s other dependencies. This led to the discovery of a malicious module pretending to be AFNetworking.framework. For a touch of foreshadowing, let’s spotlight a curious detail: certain apps referred to it as Alamofire.framework, but the code itself stayed exactly the same. The original version of AFNetworking is an open-source library that provides developers with a set of interfaces for convenient network operations.

The malicious version differs from the original by a modified AFImageDownloader class and an added AFImageDownloaderTool class. Interestingly, the authors didn’t create separate initialization functions or alter the library’s exported symbols to launch the malicious payload. Instead, they took advantage of a feature in Objective-C that allows classes to define a special load selector, which is automatically called when the app is loading. In this case, the entry point for the malicious payload was the +[AFImageDownloader load] selector, which does not exist in the original framework.

Malicious class entry point

Malicious class entry point

The malicious payload functions as follows:

  1. It checks if the value of the ccool key in the app’s main Info.plist configuration file matches the string 77e1a4d360e17fdbc. If the two differ, the malicious payload will not proceed.
  2. It retrieves the Base64-encoded value of the ccc key from the framework’s Info.plist file. This value is decoded and then decrypted using AES-256 in ECB mode with the key p0^tWut=pswHL-x>>:m?^.^)W padded with nulls to reach a length of 32 bytes. Some samples were also observed using the key J9^tMnt=ptfHL-x>>:m!^.^)A. If there’s no ccc key in the configuration or the key’s value is empty, the malware attempts to use the key com.tt.cf to retrieve an encrypted string from UserDefaults – a database where the app can store information for use in subsequent launches.
  3. The decrypted value is a list of URLs from which the malware fetches additional payloads, encrypted using the same method. This new ciphertext contains a set of C2 addresses used for exfiltrating stolen photos.
  4. The final step before uploading the photos is to receive authorization from the C2 server. To do this, the malware sends a GET request to the /api/getImageStatus endpoint, transmitting app details and the user’s UUID. The server responds with the following JSON: The code field tells the app whether to repeat the request after a delay, with 0 meaning no, and the status field indicates whether it has permission to upload the photos.
  5. Next, the malware requests access to the user’s photo gallery. It then registers a callback function to monitor for any changes within the gallery. The malware exfiltrates any accessible photos that have not already been uploaded. To keep track of which photos have been stolen, it creates a local database. If the gallery is modified while the app is running, the malware will attempt to access and upload the new images to the C2 server.
Photo exfiltration and upload

Photo exfiltration and upload

Data transmission is performed directly within the selector [AFImageDownloader receiptID:andPicID:] by making a PUT request to the /api/putImages endpoint. In addition to the image itself, information about the app and the device, along with unique user identifiers, is also sent to the server.

Digging deeper

When we found a spyware component in the modified iOS version of TikTok, we immediately wondered if the Trojan had an Android counterpart. Our initial search led us to a bunch of cryptocurrency apps. These apps had malicious code embedded in their entry points. It requests a configuration file with C2 addresses and then decrypts it using AES-256 in ECB mode. These decrypted addresses are then used by the Trojan to send a GET request to /api/anheartbeat. The request includes information about the infected app. The Trojan expects a JSON response. If the code field is 0, it means communication with that C2 is allowed. The status flag in the JSON determines whether the Trojan can send the victim’s images to the server.

Checking C2 addresses

Checking C2 addresses

The main functionality of this malware – stealing images from the gallery – works in two stages. First, the malware checks the status flag. If it’s set to allow file uploads, the Trojan then checks the contents of a file named aray/cache/devices/.DEVICES on external storage. The first time it runs, the Trojan writes a hexadecimal number to this file. The number is an MD5 hash of a string containing the infected device’s IMEI, MAC address, and a random UUID. The content of this file is then compared to the string B0B5C3215E6D. If the content is different, the Trojan uploads images from the gallery, along with infected device info, to the command server via a PUT request to /api/putDataInfo. If the content is the same, it only uploads the third image from the end of an alphabetically sorted list. It’s highly likely the attackers use this specific functionality for debugging their malicious code.

Uploading image and device information

Uploading image and device information

Later, we discovered other versions of this Trojan embedded in casino apps. These were loaded using the LSPosed framework, which is designed for app code hooking. Essentially, these Trojan versions acted as malicious Xposed modules. They would hook app entry points and execute code similar to the malware we described earlier, but with a few interesting twists:

  1. The C2 address storage was located in both the module’s resources and directly within the malware code. Typically, these were two different addresses, and both were used to obtain C2 information.
Procedure for obtaining C2 addresses

Procedure for obtaining C2 addresses

  1. Among the decrypted C2 addresses, the Trojan picks the one corresponding to the fastest server. It does this by sending a request to each server sequentially. If the request is successful, it records the response time. The shortest time then determines which C2 server is used. Note that this algorithm could have been implemented without needing to store intermediate values.
Finding the shortest response time

Finding the shortest response time

  1. The code uses custom names for classes, methods, and fields.
  2. It is written in Kotlin. Other versions we found were written in Java.

Spyware in official app stores

One of the Android Java apps containing a malicious payload was a messaging app with crypto exchange features. This app was uploaded to Google Play and installed over 10,000 times. It was still available in the store at the time of this research. We notified Google about it, and they removed the app from the store.

Infected app on Google Play

Infected app on Google Play

Another infected Android app we discovered is named 币coin and distributed through unofficial sources. However, it also has an iOS version. We found it on the App Store and alerted Apple to the presence of the infected app in their store.

Infected app page on the App Store

Infected app page on the App Store

In both the Android and iOS versions, the malicious payload was part of the app itself, not of a third-party SDK or framework. In the iOS version, the central AppDelegate class, which manages the app’s lifecycle, registers its selector [AppDelegate requestSuccess:] as a handler for responses returned by requests sent to i.bicoin[.]com[.]cn.

Checking the server response and sending a photo

Checking the server response and sending a photo

Sample server response

In the response, the imgUrl field contains information about the permission to send photos (1 means granted). Once the Trojan gets the green light, it uses a similar method to what we described earlier: it downloads an encrypted set of C2 addresses and tries sending the images to one of them. By default, it’ll hit the first address on the list. If that one’s down, the malware just moves on to the next. The photo-sending functionality is implemented within the KYDeviceActionManager class.

Retrieving and sending photos

Retrieving and sending photos

Suspicious libcrypto.dylib mod

During our investigation, we also stumbled upon samples that contained another suspicious library: a modified version of OpenSSL’s cryptographic primitives library, libcrypto.dylib. It showed up under names like wc.dylib and libswiftDarwin.dylib, had initialization functions that were obfuscated with LLVM, and contained a link to a configuration we’d seen before in other malicious frameworks. It also imported the PHPhotoLibrary class, used for gallery access in the files we mentioned earlier. Sometimes the library was delivered alongside the malicious AFNetworking.framework/Alamofire.framework, sometimes not.

Unlike other variants of this malware, this particular library didn’t actually reach out to the malicious configuration file link embedded within it. That meant we had to manually dig for the code responsible for its initial communication with the C2. Even though these library samples are heavily obfuscated, some of them, like the sample with the hash c5be3ae482d25c6537e08c888a742832, still had cross-references to the part of the code where the encrypted configuration page URL was used. This function converted a URL string into an NSString object.

Section of obfuscated code for loading the malicious URL

Section of obfuscated code for loading the malicious URL

Using Frida, we can execute any piece of code as a function, but simply converting a string to an NSString object isn’t enough to confirm the library’s malicious intent. So, we followed the cross-references up several levels. When we tried to execute the function that worked with the URL during its execution, we discovered it was making a GET request to the malicious URL. However, we couldn’t get a response right away; the server the URL pointed to was already inactive. To make the function run correctly, we used Frida to substitute the link with a working one, where we knew exactly what data it returned and how it was decrypted. By setting logging hooks on the objc_msgSend call and running the malicious function with a swapped URL, we got the info we needed about the calls. Below is the Frida script we used to do this:

Our suspicions were confirmed: the malicious function indeed loads and decrypts the C2 address configuration from a given URL. It then uses this C2 for sending device data, following the same pattern we described earlier and using the same AES-256 key. Below is an excerpt from the function’s execution logs.

The function execution log above clearly shows it uses an IP address from the encrypted configuration file. Device data is sent to this IP’s /api/getStatus endpoint with arguments familiar from previous samples. We also see that the server’s response contains the code and status fields we’ve encountered before. All of this strongly suggests that this library is also involved in stealing user photos. The only thing we haven’t pinpointed yet is the exact conditions under which this malicious function activates. At startup, the library contacts a C2 whose address in encrypted within it, sending device information and expecting a JSON string response from the server. At the time of this research, we hadn’t found any samples with an active C2 address, so we don’t know the precise response it’s looking for. However, we assume that response – or subsequent responses – should contain the permission to start sending photos.

Another activity cluster?

During our research, we stumbled upon a significant number of pages offering for download various scam iOS apps in the PWA (progressive web app) format. At first glance, these pages seemed unrelated to the campaign we describe in this article. However, their code bore a striking resemblance to the pages distributing the malicious TikTok version, which prompted us to investigate how users were landing on them. While digging into the traffic sources, we uncovered ads for various scams and Ponzi schemes on popular platforms.

Scam platform account on YouTube

Scam platform account on YouTube

Some of these PWA-containing pages also included a section prompting users to download a mobile app. For Android users, the link downloaded an APK file that opened the scam platform via WebView.

App download links

App download links

Beyond just opening scam websites in WebView, these downloaded APKs had another function. The apps requested access to read storage. Once this was granted, they used the Loader API to register their content download event handler. This handler then selected all JPEG and PNG images. The images were processed using the Google ML Kit library designed for optical character recognition. ML Kit searched for text blocks and then broke them down into lines. If at least three lines containing a word with a minimum of three letters were found, the Trojan would send the image to the attackers’ server – its address was retrieved from Amazon AWS storage.

Code snippet for photo uploads

Code snippet for photo uploads

We’re moderately confident that this activity cluster is connected to the one described above. Here’s why:

  1. The malicious apps also focus on cryptocurrency themes.
  2. Similar tactics are employed: the C2 address is also hosted in cloud storage, and gallery content is exfiltrated.
  3. The pages distributing iOS PWAs look similar to those used to download malicious TikTok mods.

Given this connection between the two activity clusters, we suspect the creators of the apps mentioned earlier might also be spreading them through social media ads.

Campaign goals and targets

Unlike SparkCat, the spyware we analyzed above doesn’t show direct signs of the attackers being interested in victims’ crypto assets. However, we still believe they’re stealing photos with that exact goal in mind. The following details lead us to these conclusions:

  1. A crypto-only store was embedded within the TikTok app alongside the spyware.
  2. Among the apps where the spyware was found, several were crypto-themed. For instance, 币coin in the App Store positions itself as a crypto information tracker, and the SOEX messaging app has various crypto-related features as well.
  3. The main source for distributing the spyware is a network of cookie-cutter app download platforms. During our investigation, we found a significant number of domains that distributed both the described Trojan and PWAs (progressive web apps). Users were directed to these PWAs from various cryptocurrency scam and Ponzi scheme sites.

Our data suggests that the attackers primarily targeted users in Southeast Asia and China. Most of the infected apps we discovered were various Chinese gambling games, TikTok, and adult games. All these apps were originally aimed specifically at users in the regions mentioned above.
Furthermore, we believe this malware is linked to the SparkCat campaign, and here’s our reasoning:

  • Some Android apps infected with SparkKitty were built with the same framework as the apps infected with SparkCat.
  • In both campaigns, we found the same infected Android apps.
  • Within the malicious iOS frameworks, we found debug symbols. They included file paths from the attackers’ systems, which pointed to where their projects were being built. These paths match what we previously observed in SparkCat.

Takeaways

Threat actors are still actively compromising official app stores, and not just for Android – iOS is also a target. The espionage campaign we uncovered uses various distribution methods: it spreads through apps infected with malicious frameworks/SDKs from unofficial sources, as well as through malicious apps directly on the App Store and Google Play. While not technically or conceptually complex, this campaign has been ongoing since at least the beginning of 2024 and poses a significant threat to users. Unlike the previously discovered SparkCat spyware, this malware isn’t picky about which photos it steals from the gallery. Although we suspect the attackers’ main goal is to find screenshots of crypto wallet seed phrases, other sensitive data could also be present in the stolen images.

Judging by the distribution sources, this spyware primarily targets users in Southeast Asia and China. However, it doesn’t have any technical limitations that would prevent it from attacking users in other regions.

Our security products return the following verdicts when detecting malware associated with this campaign:

  • HEUR:Trojan-Spy.AndroidOS.SparkKitty.*
  • HEUR:Trojan-Spy.IphoneOS.SparkKitty.*

Indicators of compromise

Infected Android apps

b4489cb4fac743246f29abf7f605dd15
e8b60bf5af2d5cc5c501b87d04b8a6c2
aa5ce6fed4f9d888cbf8d6d8d0cda07f
3734e845657c37ee849618e2b4476bf4
fa0e99bac48bc60aa0ae82bc0fd1698d
e9f7d9bc988e7569f999f0028b359720
a44cbed18dc5d7fff11406cc403224b9
2dc565c067e60a1a9656b9a5765db11d
66434dd4402dfe7dda81f834c4b70a82
d851b19b5b587f202795e10b72ced6e1
ce49a90c0a098e8737e266471d323626
cc919d4bbd3fb2098d1aeb516f356cca
530a5aa62fdcca7a8b4f60048450da70
0993bae47c6fb3e885f34cb9316717a3
5e15b25f07020a5314f0068b474fff3d
1346f987f6aa1db5e6deb59af8e5744a

Infected iOS apps

21ef7a14fee3f64576f5780a637c57d1
6d39cd8421591fbb0cc2a0bce4d0357d
c6a7568134622007de026d22257502d5
307a64e335065c00c19e94c1f0a896f2
fe0868c4f40cbb42eb58af121570e64d
f9ab4769b63a571107f2709b5b14e2bc
2b43b8c757c872a19a30dcdcff45e4d8
0aa1f8f36980f3dfe8884f1c6f5d6ddc
a4cca2431aa35bb68581a4e848804598
e5186be781f870377b6542b3cecfb622
2d2b25279ef9365420acec120b98b3b4
149785056bf16a9c6964c0ea4217b42b
931399987a261df91b21856940479634

Malicious iOS frameworks

8c9a93e829cba8c4607a7265e6988646
b3085cd623b57fd6561e964d6fd73413
44bc648d1c10bc88f9b6ad78d3e3f967
0d7ed6df0e0cd9b5b38712d17857c824
b0eda03d7e4265fe280360397c042494
fd4558a9b629b5abe65a649b57bef20c
1b85522b964b38de67c5d2b670bb30b1
ec068e0fc6ffda97685237d8ab8a0f56
f10a4fdffc884089ae93b0372ff9d5d1
3388b5ea9997328eb48977ab351ca8de
931085b04c0b6e23185025b69563d2ce
7e6324efc3acdb423f8e3b50edd5c5e5
8cfc8081559008585b4e4a23cd4e1a7f

Obfuscated malicious iOS libraries

0b7891114d3b322ee863e4eef94d8523
0d09c4f956bb734586cee85887ed5407
2accfc13aaf4fa389149c0a03ce0ee4b
5b2e4ea7ab929c766c9c7359995cdde0
5e47604058722dae03f329a2e6693485
9aeaf9a485a60dc3de0b26b060bc8218
21a257e3b51561e5ff20005ca8f0da65
0752edcf5fd61b0e4a1e01371ba605fd
489217cca81823af56d141c985bb9b2c
b0976d46970314532bc118f522bb8a6f
f0460bdca0f04d3bd4fc59d73b52233b
f0815908bafd88d71db660723b65fba4
6fe6885b8f6606b25178822d7894ac35

hxxps://lt.laoqianf14[.]top/KJnn
hxxps://lt.laoqianf15[.]top/KJnn
hxxps://lt.laoqianf51[.]top/KJnn
hxxps://yjhjymfjnj.wyxbmh[.]cn/2kzos8?a45dd02ac=d4f42319a78b6605cabb5696bacb4677
hxxps://xt.xinqianf38[.]top/RnZr

Pages distributing Trojans

hxxps://accgngrid[.]com
hxxps://byteepic[.]vip

C2 and configuration storage

C2:
23.249.28[.]88
120.79.8[.]107
23.249.28[.]200
47.119.171[.]161
api.fxsdk.com

Configurations
hxxp://120.78.239[.]17:10011/req.txt
hxxp://39.108.186[.]119:10011/req.txt
hxxps://dhoss-2023.oss-cn-beijing.aliyuncs[.]com/path/02WBUfZTUvxrTMGjh7Uh
hxxps://sdk-data-re.oss-accelerate.aliyuncs[.]com/JMUCe7txrHnxBr5nj.txt
hxxps://gitee[.]com/bbffipa/data-group/raw/master/02WBUfZTUvxrTMGjh7Uh
hxxps://ok2025-oss.oss-cn-shenzhen.aliyuncs[.]com/ip/FM4J7aWKeF8yK
hxxps://file-ht-2023.oss-cn-shenzhen.aliyuncs[.]com/path/02WBUfZTUvxrTMGjh7Uh
hxxps://afwfiwjef-mgsdl-2023.oss-cn-shanghai.aliyuncs[.]com/path/02WBUfZTUvxrTMGjh7Uh
hxxps://zx-afjweiofwe.oss-cn-beijing.aliyuncs[.]com/path/02WBUfZTUvxrTMGjh7Uh
hxxps://dxifjew2.oss-cn-beijing.aliyuncs[.]com/path/02WBUfZTUvxrTMGjh7Uh
hxxps://sdk-data-re.oss-accelerate.aliyuncs[.]com/JMUCe7txrHnxBr5nj.txt
hxxps://data-sdk2.oss-accelerate.aliyuncs[.]com/file/SGTMnH951121
hxxps://1111333[.]cn-bj.ufileos[.]com/file/SGTMnH951121
hxxps://tbetter-oss.oss-accelerate.aliyuncs[.]com/ip/CF4J7aWKeF8yKVKu
hxxps://photo-php-all.s3[.]ap-southeast-1.amazonaws[.]com/app/domain.json
hxxps://c1mon-oss.oss-cn-hongkong.aliyuncs[.]com/J2A3SWc2YASfQ2
hxxps://tbetter-oss.oss-cn-guangzhou.aliyuncs[.]com/ip/JZ24J7aYCeNGyKVF2
hxxps://data-sdk.oss-accelerate.aliyuncs[.]com/file/SGTMnH951121

Paths

/sdcard/aray/cache/devices/.DEVICES

SparkKitty, SparkCat’s little brother: A new Trojan spy found in the App Store and Google Play

Your email address will not be published. Required fields are marked *

 

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Reports
Subscribe to our weekly e-mails

The hottest research right in your inbox