Technical Analysis of SpyNote

Published on
September 2025
Technical Analysis of SpyNote

Abstract

This report provides a detailed analysis of an Android application file identified as a sophisticated Remote Access Trojan (RAT). Static and dynamic analysis techniques revealed the application to be a variant of the well-known SpyNote malware family. The malware disguises as a benign utility but, upon installation, deploys extensive spyware capabilities, including keylogging, video/audio surveillance, and data exfiltration. It establishes a persistent, low-level TCP connection to a Command and Control (C2) server for communication, using a custom binary protocol with GZIP compression. The sample exhibits strong anti-analysis features, including emulator detection, to hinder investigation. This analysis outlines the malware's architecture, communication protocol, and key malicious functionalities.


File Exploration

First thing I need in the task is to find out what file types or architecture with which I am working. File utility is a great choice for such cases.

  • Archive file: RAR archive data, v5
  • B35d… : Zip archive data, at least v2.0 to extract, compression method=deflate

As I know one of the files is an APK so this must be the target one but for additional confirmation stage I can check manually the headers of that file.

Figure 1: File hex view

As seen a PK magic bytes with AndroidManifest.xml confirms that I am dealing with APK.


XML Analysis

On dealing with APK, the first thing that comes to mind is the manifest file which can contain many interesting things and give clues for analysis. As this file is not a regular xml format it must be parsed with some tool, I prefer using “jadx-gui” all you need in one place. I can also use apktools as a second option sometimes.

Figure 2: Permissions from xml 1

Figure 3: Permissions from xml 2

From xml we can find the following:

Malware Classification
  • Surveillance and Data Exfiltration: The program requests permissions to READ_SMS, READ_CALL_LOG, READ_CONTACTS, GET_ACCOUNTS, CAMERA, RECORD_AUDIO, ACCESS_COARSE_LOCATION, and ACCESS_FINE_LOCATION. This combination allows it to steal a vast amount of personal and sensitive information, including communications, contact lists, account credentials, and real-time location. The ability to use the camera and microphone turns the device into a potent spying tool.
  • Remote Control: Permissions like SEND_SMS, CALL_PHONE, SET_WALLPAPER, and the presence of numerous services and receivers that respond to system events (BOOT_COMPLETED, SCREEN_ON/OFF) strongly suggest it can be controlled remotely by a Command and Control (C2) server.
  • Persistence and Evasion: The RECEIVE_BOOT_COMPLETED permission ensures the malware starts automatically after the device reboots, making it persistent. The use of DISABLE_KEYGUARD and SYSTEM_ALERT_WINDOW allows it to overlay other apps and interfere with the user interface, a common tactic for phishing and hiding its activities. The various activity-alias elements, especially the one that is initially disabled (FirstLauncherAlias), suggest tactics to hide the app's icon after the initial launch. The app also requests REQUEST_IGNORE_BATTERY_OPTIMIZATIONS to ensure it can run continuously in the background.
  • Advanced Capabilities (Keylogging and VPN): The declaration of a KeyboardService (android.permission.BIND_INPUT_METHOD) points to keylogging capabilities, allowing it to capture everything the user types, including passwords and messages. The FirewallServices with android.permission.BIND_VPN_SERVICE permission is highly suspicious and could be used to intercept all network traffic from the device.

Based on the extensive and alarming permissions requested, the application can be classified as Spyware with RAT (Remote Access Trojan) capabilities.

Functional Capabilities Summary
  • Victim Identification: The malware gathers a comprehensive profile of the victim. Upon installation, it can immediately access and exfiltrate:
    • Device Identifiers: While not explicitly listed in this manifest, the READ_PHONE_STATE permission is often used to get IMEI, IMSI, and other unique identifiers.
    • User Accounts: GET_ACCOUNTS retrieves all configured accounts on the device (Google, social media, etc.).
    • Personal Information: READ_CONTACTS, READ_CALL_LOG, and READ_SMS provide a detailed social graph and communication history.
    • Location Data: ACCESS_FINE_LOCATION gives precise geographical location.
  • C2 Communication Protocol:
    • The malware uses standard internet access (android.permission.INTERNET) and allows unencrypted traffic (android:usesCleartextTraffic="true"), which is a significant security flaw that could be exploited for analysis.
    • Communication is likely initiated by the initializeService or one of the other background services. These services will run persistently, listening to commands from the C2 or periodically sending out stolen data.
    • The presence of meta-data for Google Maps (com.google.android.maps.v2.API_KEY) with a suspicious-looking key (qjjdvfkgizhshevmmocraufcxdvasdvqcjnkzoqbfrcgqrcekb14) is a strong indicator. While it seems like a Google Maps API key, it could be a hardcoded key or identifier used in the C2 communication protocol itself (e.g., for authentication or encryption).
    • The various custom intent-filter actions (e.g., nervous.missing.somerset.RestartSensor) suggest the C2 can trigger specific components or actions within the malware through broadcasted intents, possibly via other malicious apps or push notifications.

Strings analysis

A quick strings analysis may give additional pieces of information.

Interesting strings are found at the like some Azure messages and list of IP addresses

1[.]0[.]0[.]0/8
100[.]0[.]0[.]0/10
100[.]128[.]0[.]0/9
101[.]0[.]0[.]0/8
102[.]0[.]0[.]0/7
104[.]0[.]0[.]0/5
11[.]0[.]0[.]0/8
11000011
112[.]0[.]0[.]0/5
12[.]0[.]0[.]0/6
120[.]0[.]0[.]0/6
124[.]0[.]0[.]0/7
126[.]0[.]0[.]0/8
128[.]0[.]0[.]0/3
16[.]0[.]0[.]0/4
160[.]0[.]0[.]0/5
168[.]0[.]0[.]0/8
169[.]0[.]0[.]0/9
169[.]128[.]0[.]0/10
169[.]192[.]0[.]0/11
169[.]224[.]0[.]0/12
169[.]240[.]0[.]0/13
169[.]248[.]0[.]0/14
169[.]252[.]0[.]0/15
169[.]255[.]0[.]0/16
170[.]0[.]0[.]0/7
172[.]0[.]0[.]0/12
172[.]128[.]0[.]0/9
172[.]32[.]0[.]0/11
172[.]64[.]0[.]0/10
173[.]0[.]0[.]0/8
174[.]0[.]0[.]0/7
176[.]0[.]0[.]0/4
192[.]0[.]1[.]0/24
192[.]0[.]128[.]0/17
192[.]0[.]16[.]0/20
192[.]0[.]3[.]0/24
192[.]0[.]32[.]0/19
192[.]0[.]4[.]0/22
192[.]0[.]64[.]0/18
192[.]0[.]8[.]0/21
192[.]1[.]0[.]0/16
192[.]128[.]0[.]0/11
192[.]16[.]0[.]0/12
192[.]160[.]0[.]0/13
192[.]169[.]0[.]0/16
192[.]170[.]0[.]0/15
192[.]172[.]0[.]0/14
192[.]176[.]0[.]0/12
192[.]192[.]0[.]0/10
192[.]2[.]0[.]0/15
192[.]32[.]0[.]0/11
192[.]4[.]0[.]0/14
192[.]64[.]0[.]0/10
192[.]8[.]0[.]0/13
193[.]0[.]0[.]0/8
194[.]0[.]0[.]0/7
196[.]0[.]0[.]0/7
198[.]0[.]0[.]0/12
198[.]128[.]0[.]0/9
198[.]16[.]0[.]0/15
198[.]20[.]0[.]0/14
198[.]24[.]0[.]0/13
198[.]32[.]0[.]0/12
198[.]48[.]0[.]0/15
198[.]50[.]0[.]0/16
198[.]51[.]0[.]0/18
198[.]51[.]101[.]0/24
198[.]51[.]102[.]0/23
198[.]51[.]104[.]0/21
198[.]51[.]112[.]0/20
198[.]51[.]128[.]0/17
198[.]51[.]64[.]0/19
198[.]51[.]96[.]0/22
198[.]52[.]0[.]0/14
198[.]56[.]0[.]0/13
198[.]64[.]0[.]0/10
199[.]0[.]0[.]0/8
2[.]0[.]0[.]0/7
200[.]0[.]0[.]0/7
202[.]0[.]0[.]0/8
203[.]0[.]0[.]0/18
203[.]0[.]112[.]0/24
203[.]0[.]114[.]0/23
203[.]0[.]116[.]0/22
203[.]0[.]120[.]0/21
203[.]0[.]128[.]0/17
203[.]0[.]64[.]0/19
203[.]0[.]96[.]0/20
203[.]1[.]0[.]0/16
203[.]128[.]0[.]0/9
203[.]16[.]0[.]0/12
203[.]2[.]0[.]0/15
203[.]32[.]0[.]0/11
203[.]4[.]0[.]0/14
203[.]64[.]0[.]0/10
203[.]8[.]0[.]0/13
204[.]0[.]0[.]0/6
208[.]0[.]0[.]0/4
224[.]0[.]0[.]0/4
32[.]0[.]0[.]0/3
4[.]0[.]0[.]0/6
64[.]0[.]0[.]0/3
8[.]0[.]0[.]0/7
96[.]0[.]0[.]0/6

This list can simply contain some c2 server IPs which are worth analyzing in future stages or may be just Version Updates.


Finding highlights

  1. Package Name (nervous.missing.somerset): The name itself seems intentionally evocative of something being wrong or lost. The sub-packages are clearly obfuscated and randomly generated, a classic malware trait.
  2. AccessibilityService (AccessService): This is one of the most critical and dangerous permissions. An accessibility service can read the screen content of any app, simulate user clicks, and input text. This is the primary mechanism for stealing credentials from banking apps, social media, and more.
  3. KeyboardService: As mentioned, this is a keylogger. Analyzing its implementation will reveal how it captures and where it sends the keystrokes.
  4. FirewallServices (VPN): Intercepting all device traffic is an incredibly powerful capability. That must be investigated to reveal how this VPN is configured and where it routes the traffic. It might be routing traffic through a server controlled by the attacker.
  5. Obfuscated Component Names: All the important services and activities have long, random-looking names. This is a deliberate attempt to hinder analysis.
  6. meta-data API Key: The hardcoded "API Key" is a huge red flag. It is almost certainly not a real Google Maps key but rather a static key used for C2 communication. It could be an XOR key, part of an authentication token, or an identifier for this specific bot variant.
  7. <queries> Block: The list of queried packages is very revealing. It checks for:
    • Other apps from the same developer (nervous.*).
    • Social media and communication apps (messenger.com, com.whatsapp.*, com.instagram.android).
    • Security and permission management apps from various phone manufacturers (com.miui.securitycenter, com.huawei.systemmanager, com.coloros.safecenter, etc.). This is likely to tailor its persistence or exploitation techniques to the specific device brand.
    • Many heavily obfuscated package names, which could be other malware components or apps it intends to target or avoid.

Decompiled Code Analysis

Now jadx-gui will come to the playground one more time.

First, I need to determine a goal to follow to just save time and effort and not to get lost in the whole program.

  • Locate the C2 Server Address.
  • Reveal the communication protocol and algorithm.
  • Confirm info stealing and remote access assumptions.
  • Reveal the full malicious functionalities.
MyApplication Analysis

A good place to start is MainActivity. It is like the entry point of the app but while locating it another interesting class needs my attention MyApplication.

Figure 4: MyApplication Activity

Primary Function: Crash Handling and Persistence The main purpose of this class is to set up a custom UncaughtExceptionHandler. This is a mechanism that catches any crash or unhandled error that occurs anywhere in the application.

Remote Error Logging When the app crashes, the uncaughtException method is triggered. It gathers a lot of information:

  • The full error message and stack trace.
  • Device information: Manufacturer, Model, and Android Version.

It then checks a boolean flag: ljkavjgzxyxekzboggghzdnmgnwrikzcaafugbjxudfxiqqfko38.echo. the class extends Service, and the Boolean default is false.

If true (meaning a C2 connection is likely active), it immediately sends this crash report to the C2 server using the obfuscated method qmyydfbllhmhlfxhghgkveoykvkmngrzshtgbnclxyzfisljag52.

If false, it saves the crash report locally using MySettings.Write. It will likely try to upload this saved report the next time it connects to the C2.

Automatic Restart (Persistence) After logging the crash, it uses AlarmManager to schedule a restart of the MainActivity one second later. This is a powerful persistence technique. No matter why the app crashes, it will try to bring itself back online automatically.

Network Routine

Figure 5: qmyydfbllhmhlfxhghgkveoykvkmngrzshtgbnclxyzfisljag52 method

This is the core data transmission function. A step by step analysis shows that:

  • The code uses a ThreadPoolExecutor to run the network operations on a background thread. This is to prevent the app from freezing while sending data.
  • The code is not making a standard web request (like HTTP POST). Instead, it is writing directly to a network output stream (Service_Extended.outputnew). This stream belongs to a raw TCP socket (Service_Extended.reciver). This means the C2 communication is happening at a lower level than typical web traffic.
  • The byte array bArrUednoekajnvlmpjmkltaderreztowxjocwrpjejymruiisqojg42 is likely the C2 message so I suppose that uednoekajnvlmpjmkltaderreztowxjocwrpjejymruiisqojg42 method is just performing some formatting or better some encryption.

Figure 6: uednoekajnvlmpjmkltaderreztowxjocwrpjejymruiisqojg42 method

To fully understand the target “possible_crypto”, I need first to reverse the atbhwqtktfcdakyackyazdyvurjfhoenadhczohivybdmogdla47 method.

Figure 7: atbhwqtktfcdakyackyazdyvurjfhoenadhczohivybdmogdla47 method

This method is surprisingly simple. It does one thing: it compresses the data using the GZIP algorithm.

  • It creates a GZIP output stream.
  • It takes the input data (bArr) and writes it into the GZIP stream, which compresses it on the fly.
  • It retrieves the resulting compressed data.

This technique is widely used to reduce the message size.


Complete C2 Protocol - The Full Picture

Figure 9: Send_Data_to_C2 Deobfuscated

This function serves as the malware's C2 transport engine, responsible for sending all prepared data to the command and control server. It is a critical component that highlights the malware's sophisticated design.

  • It uses a thread pool to send data in the background. This prevents the app from freezing during transmission, making its activity less noticeable to the user.
  • By using a synchronized block, it ensures that data packets are sent one at a time without being corrupted. This is essential for the custom binary protocol it uses.
  • Instead of standard web traffic (HTTP), it communicates over raw TCP sockets. This is a common evasion technique to bypass firewalls and make network monitoring more difficult.
  • If the connection to the server fails during transmission, it has error handling that cleanly closes the connection, preventing the app from crashing and allowing it to try again later.

Figure 10: Send_Data_to_C2 Xref calls

The function has been called 71 different times so it must be info stealer as assumed previously.


Socket information

Now I need to find the socket information (IP/Port) so from this understanding of communication routine I think searching for “new Socket()” will give me a place to search.

Figure 11: Socket creation search

As search results show, there are three socket creations among the malware sample. To retrieve the C2 socket information I will simply search the three places.

The CameraHandler class is a specialized module with a single, powerful purpose: to secretly capture and stream live video from the device's camera.

  • Activation via Command: This CameraHandler service does not start on its own. It is activated when it receives a specific command (an Intent). This command contains a string array with all the necessary parameters, including an IP address and a port number.
  • Dynamic Connection: The key part of the code is in the CompletedApp method. It creates a new TCP socket, but it does not use a hardcoded IP address. Instead, it gets the host and port from the command it received.
  • Once the connection is established, the m17pr method runs in a loop. It continuously grabs frames from the camera preview, compresses them into JPEG images, and sends them through the socket using the same utilities.Packet_constructor we analyzed earlier.

The Service_Extended class has another socket creation routine.

Figure 13: Service_Extended socket creation routine

From the figure you find that IP/Port are passed through two string arrays defined previously.

Figure 14: Socket data variable initiation

From Figure 15 it is obvious that those two variables are initialized with arguments passed to the function.

Tracing function calls I simply found the hardcoded B64 IP/Port

Figure 15: IP/Port hardcoded

Decoding them using CyberChef I got simply “47.82.2.89 / 7772” also there is a variable called connection key containing another b64 value equal to “1234”.


MainActivity Analysis

Now it is time to see what the program does as a quick view of its capabilities.

The primary purpose of MainActivity is not to be the malware itself, but to act as a loader and setup agent. It has three main jobs:

  • It presents a seemingly harmless WebView (an in-app browser) loading a legitimate-looking charity website (sunlove.org.sg). This is a smokescreen to make the user believe the app is benign.
  • It uses social engineering to trick the user into granting highly dangerous permissions.
  • Most importantly, it ensures that the persistent background services (initializeService and Service_Extended), which handle the actual C2 communication and data theft, are started and running.

Work method

Figure 16: Work method definition

From Figure 16 I can say that this method does only three things:

  • Checks if the initializeService is running. If not, start it.
  • Checks if the main C2 service (Service_Extended) is running. If not, start it.
  • Checks if the device is running Android 8.0 (API level 26) or higher to determine how to start the service.

This means that as soon as MainActivity is created, it calls this method. This ensures that the two most important background services are launched. Service_Extended is the class we suspect contains the C2 IP/Port and manages the persistent connection. This Work() method is the trigger that kicks off the entire malicious operation in the background, completely hidden from the user who is looking at the WebView.

Next interesting part is Anti-Analysis and Evasion.


Anti-Analysis and Evasion

Figure 17: Anti-Emulation

The malware desperately wants to avoid being analyzed. It does this with the isEmu_DIV_ID_lator() method.

  return (Build.BRAND.startsWith(utilities.whrjmjiqnkguefdnveonzicbymsvunvznsfnnrkuhgqvfvduww53("genfxubzhcydkvtnlvsauqnsncixsitzjdmjzuenjvcrhaihiwxvoetlriukkclmiggbhnyesvednetygsrqhpsgjkfxprifvggwgeqstoetlxezczrnllsirpjuecdjyimwurzxwxgnnhgbbdokqwvgrnjtvekshgkavzrlpzgjfvwnfxwpvfuvfejqybjkcrpsjtztkoioyhzkgaaxzinejfhsrccfdhfatlolzhatgmiusitgtbuvhjfcmozbyvyleqfgwaafmsnlykqgmjkuolfnggssbgkzsitwforftdnfafjoobumgkadynqboiiddgjurizkfvxyelyzmeeqjaycmxtnojtyvrwghqgavirqyvpyakmhyitxlvowcflhlywkizvjusbongn55eric", "fxubzhcydkvtnlvsauqnsncixsitzjdmjzuenjvcrhaihiwxvoetlriukkclmiggbhnyesvednetygsrqhpsgjkfxprifvggwgeqstoetlxezczrnllsirpjuecdjyimwurzxwxgnnhgbbdokqwvgrnjtvekshgkavzrlpzgjfvwnfxwpvfuvfejqybjkcrpsjtztkoioyhzkgaaxzinejfhsrccfdhfatlolzhatgmiusitgtbuvhjfcmozbyvyleqfgwaafmsnlykqgmjkuolfnggssbgkzsitwforftdnfafjoobumgkadynqboiiddgjurizkfvxyelyzmeeqjaycmxtnojtyvrwghqgavirqyvpyakmhyitxlvowcflhlywkizvjusbongn55")) && Build.DEVICE.startsWith("generic")) || Build.FINGERPRINT.startsWith(utilities.whrjmjiqnkguefdnveonzicbymsvunvznsfnnrkuhgqvfvduww53("genfxubzhcydkvtnlvsauqnsncixsitzjdmjzuenjvcrhaihiwxvoetlriukkclmiggbhnyesvednetygsrqhpsgjkfxprifvggwgeqstoetlxezczrnllsirpjuecdjyimwurzxwxgnnhgbbdokqwvgrnjtvekshgkavzrlpzgjfvwnfxwpvfuvfejqybjkcrpsjtztkoioyhzkgaaxzinejfhsrccfdhfatlolzhatgmiusitgtbuvhjfcmozbyvyleqfgwaafmsnlykqgmjkuolfnggssbgkzsitwforftdnfafjoobumgkadynqboiiddgjurizkfvxyelyzmeeqjaycmxtnojtyvrwghqgavirqyvpyakmhyitxlvowcflhlywkizvjusbongn55eric", "fxubzhcydkvtnlvsauqnsncixsitzjdmjzuenjvcrhaihiwxvoetlriukkclmiggbhnyesvednetygsrqhpsgjkfxprifvggwgeqstoetlxezczrnllsirpjuecdjyimwurzxwxgnnhgbbdokqwvgrnjtvekshgkavzrlpzgjfvwnfxwpvfuvfejqybjkcrpsjtztkoioyhzkgaaxzinejfhsrccfdhfatlolzhatgmiusitgtbuvhjfcmozbyvyleqfgwaafmsnlykqgmjkuolfnggssbgkzsitwforftdnfafjoobumgkadynqboiiddgjurizkfvxyelyzmeeqjaycmxtnojtyvrwghqgavirqyvpyakmhyitxlvowcflhlywkizvjusbongn55")) || Build.FINGERPRINT.startsWith(EnvironmentCompat.MEDIA_UNKNOWN) || Build.HARDWARE.contains("goldfish") || Build.HARDWARE.contains("ranchu") || Build.MODEL.contains("google_sdk") || Build.MODEL.contains("Emulator") || Build.MODEL.contains(utilities.whrjmjiqnkguefdnveonzicbymsvunvznsfnnrkuhgqvfvduww53("Android SDK bfxubzhcydkvtnlvsauqnsncixsitzjdmjzuenjvcrhaihiwxvoetlriukkclmiggbhnyesvednetygsrqhpsgjkfxprifvggwgeqstoetlxezczrnllsirpjuecdjyimwurzxwxgnnhgbbdokqwvgrnjtvekshgkavzrlpzgjfvwnfxwpvfuvfejqybjkcrpsjtztkoioyhzkgaaxzinejfhsrccfdhfatlolzhatgmiusitgtbuvhjfcmozbyvyleqfgwaafmsnlykqgmjkuolfnggssbgkzsitwforftdnfafjoobumgkadynqboiiddgjurizkfvxyelyzmeeqjaycmxtnojtyvrwghqgavirqyvpyakmhyitxlvowcflhlywkizvjusbongn55uilt for x86", "fxubzhcydkvtnlvsauqnsncixsitzjdmjzuenjvcrhaihiwxvoetlriukkclmiggbhnyesvednetygsrqhpsgjkfxprifvggwgeqstoetlxezczrnllsirpjuecdjyimwurzxwxgnnhgbbdokqwvgrnjtvekshgkavzrlpzgjfvwnfxwpvfuvfejqybjkcrpsjtztkoioyhzkgaaxzinejfhsrccfdhfatlolzhatgmiusitgtbuvhjfcmozbyvyleqfgwaafmsnlykqgmjkuolfnggssbgkzsitwforftdnfafjoobumgkadynqboiiddgjurizkfvxyelyzmeeqjaycmxtnojtyvrwghqgavirqyvpyakmhyitxlvowcflhlywkizvjusbongn55")) || Build.MANUFACTURER.contains("Genymotion") || Build.PRODUCT.contains("sdk_google") || Build.PRODUCT.contains("google_sdk") || Build.PRODUCT.contains("sdk") || Build.PRODUCT.contains("sdk_x86") || Build.PRODUCT.contains(utilities.whrjmjiqnkguefdnveonzicbymsvunvznsfnnrkuhgqvfvduww53("sdk_gphone6fxubzhcydkvtnlvsauqnsncixsitzjdmjzuenjvcrhaihiwxvoetlriukkclmiggbhnyesvednetygsrqhpsgjkfxprifvggwgeqstoetlxezczrnllsirpjuecdjyimwurzxwxgnnhgbbdokqwvgrnjtvekshgkavzrlpzgjfvwnfxwpvfuvfejqybjkcrpsjtztkoioyhzkgaaxzinejfhsrccfdhfatlolzhatgmiusitgtbuvhjfcmozbyvyleqfgwaafmsnlykqgmjkuolfnggssbgkzsitwforftdnfafjoobumgkadynqboiiddgjurizkfvxyelyzmeeqjaycmxtnojtyvrwghqgavirqyvpyakmhyitxlvowcflhlywkizvjusbongn554_arm64", "fxubzhcydkvtnlvsauqnsncixsitzjdmjzuenjvcrhaihiwxvoetlriukkclmiggbhnyesvednetygsrqhpsgjkfxprifvggwgeqstoetlxezczrnllsirpjuecdjyimwurzxwxgnnhgbbdokqwvgrnjtvekshgkavzrlpzgjfvwnfxwpvfuvfejqybjkcrpsjtztkoioyhzkgaaxzinejfhsrccfdhfatlolzhatgmiusitgtbuvhjfcmozbyvyleqfgwaafmsnlykqgmjkuolfnggssbgkzsitwforftdnfafjoobumgkadynqboiiddgjurizkfvxyelyzmeeqjaycmxtnojtyvrwghqgavirqyvpyakmhyitxlvowcflhlywkizvjusbongn55")) || Build.PRODUCT.contains("vbox86p") || Build.PRODUCT.contains("emulator") || Build.PRODUCT.contains("simulator");
  • This method checks dozens of device properties (Build.BRAND, Build.MODEL, Build.HARDWARE, etc.) for keywords associated with emulators and sandboxes (like "Emulator", "sdk", "Genymotion", "vbox86p").
  • The keywords it searches for are themselves obfuscated using a utilities.whrjmjiqnkguefdnveonzicbymsvunvznsfnnrkuhgqvfvduww53 method to prevent simple string searches by analysts.
  • If it detects an emulator, it calls AsknoEmu(), which displays a fake "Emulator detected" error and immediately terminates the app with System.exit(0).

This is a deliberate and strong anti-analysis technique. It is designed to prevent dynamic analysis in a safe environment.


User tricking “Social Engineering”

Another amazing part is AskDraw() method.

It is designed to get the "Draw Over Apps" permission (MANAGE_OVERLAY_PERMISSION). This is one of the most dangerous permissions on Android. It allows an app to draw on top of any other app.

The Trick here is to convince the user, the app spoofs its identity. It tries to set its pop-up dialog's icon and title to that of the Google Play Store.

Figure 18: Identity Spoofing

With this permission, the malware can create fake login screens on top of legitimate banking, social media, or email apps to steal user credentials (a phishing attack known as tapjacking).


Tracking User Activity

The tracking mechanism is implemented in the onDestroy() and finish() methods of MainActivity. These methods are part of the Android Activity Lifecycle and are called automatically by the system whenever the main user interface of the app is about to be closed or destroyed.

Figure 19: Tracking User Activity

A user action, such as pressing the back button to exit the app or swiping it away from the recent apps list, triggers the onDestroy() or finish() method.

Before sending anything, the code checks this boolean flag. Service_Extended.echo is almost certainly a status variable that is set to true only after the malware has successfully established a connection and performed a handshake with the C2 server. This check prevents the app from trying to send data when it is offline, which would cause errors.

The code calls the data sending function with utilities.ActiveNow as the command string. This is not a random name. It is a clear, predefined command that the C2 server is programmed to understand. It essentially means "Activity Status Update."

The actual data being sent is just a single space character. In this case, the content of the payload is irrelevant. The entire message is conveyed by the command itself. The C2 server simply needs to see the ActiveNow command arrive to know what happened.

The command and the empty payload are then passed through the entire communication pipeline we have analyzed: they are compressed with GZIP, formatted into the custom binary packet, and sent over the raw TCP socket to the C2 server.

Why This is Done

  • This is not just random logging; it is a form of real-time intelligence gathering that provides significant strategic advantages to the attacker:
  • The C2 server now knows the precise state of the bot. It can differentiate between a bot that is running silently in the background and one where the user has just actively closed the foreground UI. This is crucial for command and control.
  • This signal can be used as a trigger. For example, the attacker might want to wait for the user to close the app before launching a more intrusive action, like popping up a fake notification or attempting to install another package. The "app closed" event is the perfect trigger for such a task, as the user is less likely to associate the new malicious activity with the app they just closed.
  • It acts as a "liveness" ping. It confirms to the attacker that the bot is not only online but also that the user is interacting with the device. This is more valuable than a simple periodic heartbeat because it is tied to a specific user action.
  • Over time, logging these open/close events allows the attacker to build a profile of the victim's usage habits. They can learn when the user typically uses their phone, for how long, and when they are inactive. This information is invaluable for scheduling data exfiltration or other resource-intensive tasks for times when the user is least likely to notice (e.g., in the middle of the night).

IOCs

File Hash (SHA-256) b35d06e5bd966766f3f6955af7d0e1ce061e103a6b2862ca969b7bc6aff8634b
File Hash (md5) fa54bdc24c3e37b7f322e02da4d388fc
Package Name nervous.missing.somerset
C2 Server IP 47.82.2.89
C2 Server Port 7772

Conclusion

  • This investigation concludes that the analyzed application is a highly sophisticated and dangerous Android Remote Access Trojan (RAT), confidently attributed to the SpyNote malware family. The malware initiates its attack under the guise of a legitimate application, deceiving the user with a harmless web interface while it launches its malicious services in the background.
  • Its capabilities are extensive, leveraging highly intrusive permissions to perform widespread data exfiltration. The abuse of the Accessibility Service to steal credentials from other applications is particularly notable, representing a critical threat to the user's financial and personal data. This is compounded by its ability to act as a keylogger and remotely activate the device's camera and microphone, turning the user's phone into a comprehensive spying tool.
  • Technically, the malware demonstrates a high level of sophistication. It employs strong anti-analysis features, such as emulator detection, to evade researchers. Its persistence is ensured through clever use of crash handlers and system alarms. Furthermore, its C2 communication protocol—a custom binary format over a raw TCP socket with GZIP compression—is designed for stealth and resilience, making it difficult to detect with conventional network security measures.
  • The combination of these features—deceptive social engineering, extensive surveillance capabilities, and advanced technical evasion—confirms that this SpyNote variant is a potent weapon for targeted espionage and cybercrime. It poses a severe and multifaceted risk to any compromised device.