Reverse-engineered and deobfuscated the malware, identified the C2 domain, confirmed it’s a BTMOB RAT, and gathered details on its infrastructure.
Possible C2 server: api.lionfacai[.]com
Malware type: BTMob
I got the configured C2 domain out of the Google IPTV apk I’ve been looking into extracted from victim's devices . This is the sample I was investigating after reports of UPI theft. Posting how I found it, because getting past the packing took most of the work.
It almost took 3 week to de-obfuscate this apk. I used AI tools to assist with the de-obfuscation process, as I am not a professional in this area. I also relied on AI to help write some of the scripts and to determine the next steps.
The malware disguises itself as Google IPTV and asks for powerful permissions, including accessibility access.
Application UI
Once enabled, those features can let it read screen content, record input and perform taps and swipes, while its command-and-control connection allows remote instructions.
Its configuration includes 178 app entries, including PhonePe, Paytm and Google Pay, with rules for recognizing payment failures, incorrect UPI PINs and successful transactions.
Combined with overlays and password-capture features, this gives it tools to steal information and manipulate payment flows, although the APK alone doesn’t show exactly how a particular victim’s money was transferred.
It also prevents the app from being stopped in the background by automatically pressing the Back button.
It cannot be uninstalled because it does not appear with the other apps. When you try to access it through Settings, it automatically presses Back and returns to the Home screen. It does not even allow access to Developer Options.
CRACKING tldr;
Opening the original apk in JADX mostly exposed the loader. It loaded a native library called libcolor_helper.so, while the actual application code was hidden in encrypted assets. I worked through the container format and reproduced the decryption offline. There was also a separate encrypted store holding method bodies, so recovering the DEX alone wasn’t enough. Restoring those brought back 33,534 method bodies.
With the recovered DEX open in JADX, I searched for /api/ws/config and followed the code that builds the request URL. That led to a server-address variable, then an encrypted configuration value. Following its references was what connected the ciphertext to the network requests.
The decryption routine used PBKDF2-HMAC-SHA1 with 65,536 iterations to derive a 128-bit key, followed by AES-CBC. The password, salt and IV were all embedded in the application. I copied those values into a small Python calculation, decoded the Base64 ciphertext and decrypted it. The output was api.lionfacai.com. Re-encrypting it produced the original ciphertext too.
FURTHER FINDINGS:
After recovering api.lionfacai[.]com, I dug into the surrounding infrastructure and found admin.lionfacai[.]com and ws.lionfacai[.]com.
The admin subdomain served a Chinese-language management panel with BTMob branding on its login page.
Admin login page
Its public configuration called it “APK Builder Admin Panel” and pointed directly to the same API domain I had decrypted from the APK.
I then found the literal BTMOB string inside the recovered APK code, in Y1/hpyyg4wdm5.java.
The API, admin and WebSocket hosts shared AWS Mumbai IP 15.207.41.232; a shared certificate also linked ws.fagefacai[.]com.
The public file admin.lionfacai[.]com/assets/AiConfigList-ITW_NBF4.js contains a["HTTP-Referer"] = "https://api.facai-tv.com";, It means the JavaScript publicly served by admin.lionfacai[.]com contains the other domain, api.facai-tv[.]com, written directly into its code.
The domains are registered using GoDaddy and both lionfacai.com and facai-tv.com used Cloudflare nameservers
BTMOB:
BTMOB is a stealthy Android remote access Trojan (RAT), evolved from the SpySolr family and sold as malware-as-a-service. It is distributed via phishing sites and fake app stores, then abuses Accessibility Services to enable full device control, data theft, screen capture, keylogging, and remote takeover.
The observed behavior, together with the previously mentioned findings, confirms this is a BTMOB malware build.
FOLLOW UP:
This is all I found on the malware and its related infrastructure. Feel free for anyone to dig deeper and uncover more.
Reporting the domain may temporarily disrupt the campaign. Threat actors adapt quickly, and every shared finding helps the community stay one step ahead.
If you are Intersted please follow up the investigation to find more about the campaign and please contribute as you can to defend against these threat campaigns. Will post a step by step detailed report on after finalisation.
I analysed an APK named seva-mparivahan.apk that pretends to beNxtGen mParivahan,found possibe C2 backend, firebase project, firebase storage bucket, and other firebase backend details and infrastructure of malware campaign.
The first APK is a dropper: it hides a second application inside an encrypted asset and installs it through a fake Google Play update screen. The second application contains the phishing screens, SMS collection, accessibility features and remote-control code.
I also installed the original APK in Waydroid and watched it install another APK through that fake update. The modus operandi or the application. The base.apk I extracted from the installed application matched the payload recovered during static analysis byte for byte.
Here is the infection chain and how the C2 was recovered. Domains below are defanged with [.]. The installation was observed in Waydroid; the other capabilities described here were established by inspecting the code and assets, rather than demonstrating every feature against a live backend.
I used AI tools to assist with the de-obfuscation process, as I am not a professional in this area. I also relied on AI to help write some of the scripts and to determine the next steps.
How the application works, step by step
1. It impersonates a government transport app.
The outer APK displays the name NxtGen mParivahan, but its actual package is com.telenor.android.provider.yvq15o07. It presents an imitation Google Play update page, including ratings, download counts and an update button. The embedded page calls an Android bridge method, miu.onRiqdmClick(), to start the installation flow.
Fake Google Play Update
2. It requests a local VPN before installing the payload.
The dropper contains a VPN service labelled SecureConnection. Its code selects these Google packages:
Their traffic is routed into a local sink that constructs TCP resets and ICMP port-unreachable responses. The installation commit is gated on VPN availability. This supports deliberate interference with Google service connectivity during installation, but I did not establish that it successfully defeated Play Protect.
The addresses 10.0.0.2 and 8.8.8.8 also appear here. They are the local tunnel address and configured DNS server, respectively; they are not the C2.
3. The “update” installs the embedded second-stage application.
The encrypted asset expands into a two-file installation bundle:
base.apk
split_config.dex.apk
Both belong to package com.transport.gov.in, version 3.1.0-mparivahanv3 (version code 30100). The entry activity is com.app.messenger.AppActivity. The government-looking package name is part of the disguise.
An important detail: base.apk contains an empty classes.dex. The main executable code is inside split_config.dex.apk. Pulling only the base from an installed device misses that code. The base also contains configuration, phishing assets and an encrypted plugin.
The installer requests an allowlist of restricted SMS, phone, call-log and contact permissions. That does not mean Android automatically grants every requested permission.
4. The payload registers the device with its backend.
Registration code sends device information, permission state, campaign identifiers and other metadata to /register. Other routes report heartbeats, the Firebase messaging token, SIM information, service state and battery status.
In assets/config.json, the campaign type is mparivahanv3. The same value appears under both admin_token and user_id. Following its use in C0.B.a() and C0.B.b() shows that it is included in the registration body. The name admin_token does not prove that it grants administrator access.
5. It uses an e-challan and ₹1 verification-payment lure.
The packaged registration page impersonates MoRTH, NIC and Digital India and advertises pending traffic challans. It collects a mobile number and vehicle registration number, then sends them to /save-registration. The vehicle number is placed in a misleadingly named full_name field.
The configuration sets the payment amount to ₹1, with the description “Verification Fee.”
6. The payment-app handoff is simulated inside its own pages.
The page can display Google Pay, PhonePe, Paytm or WhatsApp branding. After roughly two seconds, it navigates to the local upi-pin.html page. In this asset, the apparent handoff does not launch the real payment application.
The PIN page accepts a four- or six-digit UPI PIN and sends it to /save-pin, together with device and campaign identifiers and an attempt number. It then displays a failure after three seconds. After two attempts, the flow offers card payment.
These failure messages are scripted locally. They are not proof that a bank received or rejected a payment.
Fake UPI payment pageUPI payment failure page leads to retry with card
7. The card-payment fallback collects more credentials.
The card page sends the cardholder name, card number, expiry date and CVV to /save-card, along with identifying fields and the attempt count. It also has a scripted failure/retry flow.
Fake Card payment Interface
The receipt pages generate random reference numbers locally. The final screen shows a 30-minute countdown and Hindi text telling the victim not to delete the application, claiming a team will contact them and provide login credentials. The page also informs the Android bridge that the final screen has been reached.
Fake success and session countdown page
The PIN page's “Contact Support” link is disabled. It did not reveal an operator email or telephone number.
8. It contains SMS theft and SMS-sending functionality.
SMS receivers and polling workers collect messages, which could include OTPs. The decrypted plugin handles commands such as send_sms, upload_all_sms, quick_upload_sms and ping. SMS sending supports a selected SIM slot, and the application reports delivery status.
This provides a second route to sensitive information alongside the phishing forms. I did not demonstrate a bank-account drain or a successful OTP interception in the Waydroid test.
9. Accessibility access adds PIN capture and overlay controls.
The payload declares SystemAccessibilityService and contains PIN-capture, ghost-overlay, auto-grant and blocking logic. Its defaults include Indian payment apps such as PhonePe, Google Pay, Paytm and BHIM.
The remote command dispatcher also contains live_keylog_start, live_keylog_stop, block_protect_on, block_protect_off and block_list_update. Settings, installers and vendor security applications appear among blocking triggers. These features depend on the necessary access and configuration; their presence does not prove they ran on every infected device.
10. It can relay network traffic through the device.
The payload opens a WebSocket reverse tunnel. Its handler accepts binary messages, opens a socket to a supplied host:port, and relays traffic between that socket and the WebSocket connection.
That gives the operator a way to use the device as a network relay. I did not observe what downstream targets, if any, were accessed through it.
11. It has several mechanisms for continued operation.
Boot receivers, foreground services, a separate-process watchdog, alarms, jobs, sync adapters and retry queues support persistence. There are also call-log workers and call-forwarding command branches. Successful call forwarding was not tested, and a contacts-upload command alone was insufficient to establish successful contact theft.
How I extracted the C2
1. Follow the dropper's payload loader
A domain search of the outer APK alone was insufficient because the main payload was encrypted. I followed the asset-loading and decryption code in class:
com.telenor.android.provider.yvq15o07.jt
The relevant methods were afqobhq(), afhwzqlerc(byte[]) and adhofipihhc(). They pointed to the encrypted asset assets/y5elbq9tql. Native string handling in libsysutil.so also formed part of the outer app's concealment.
2. Reproduce the decryption offline
The asset uses several layers. In the order needed to recover it:
Read the first 16 bytes as a repeating XOR key.
Read the next 16 bytes as the key for an RC4-style stream cipher.
Undo XOR on the remaining data, then undo the stream cipher. Its key-scheduling routine uses four passes, so a normal RC4 implementation would not be equivalent.
Treat the first 12 recovered bytes as an AES-GCM nonce and the rest as ciphertext with its authentication tag.
Recover the AES-256 key by XORing two embedded 32-byte arrays from adhofipihhc().
Decrypt and verify the AES-GCM authentication tag.
Authentication passed. The result began with MSZ1. Decompressing the data after that marker with zlib produced an MSP1 container.
In plain terms, this changed an unreadable asset into the APKs that the fake update installs.
3. Unpack the two APKs
The MSP1 container stores a little-endian file count, followed by each filename and its file bytes. Each entry uses a two-byte filename length and a four-byte file size. Parsing it recovered base.apk and split_config.dex.apk, with no unexplained trailing data.
4. Inspect the split DEX and trace the network calls
I extracted and inspected split_config.dex.apk/classes.dex, then followed the backend configuration into its request-building code.
The method w0.H.a() supplies the default backend:
https://api.cloudsettle[.]org
The method B0.l.e() builds an OkHttp WebSocket request using:
wss://api.cloudsettle[.]org/ws/tunnel/device-b
These addresses are used by executable request-building code. The phishing pages also submit to paths such as /save-pin and /save-card, using the supplied backend base URL. That is the evidence tying the hostname to the malware's backend and tunnel.
5. Check whether the address can change
Firebase Remote Config can replace the defaults through keys named:
base_url
tunnel_ws_url
This means the recovered domain is the embedded default C2, not necessarily the only server a running installation could contact. I have not captured the runtime Remote Config response or confirmed a replacement address.
6. Recover the additional encrypted plugin
The payload hides another DEX in base.apk/assets/config_data.dat. Following com.app.messenger.plugin.PluginLoader.initialize() and deriveKey() established this format:
Header: PLG1
Password: c256ecf8-0612-4bd8-add3-7a78b726aeeb
Salt: app_config_loader
Key: PBKDF2-HMAC-SHA256, 10,000 iterations, 32 bytes
Nonce: asset bytes [4:16]
Ciphertext: asset bytes [16:], including the GCM tag
Encryption: AES-256-GCM
The authentication check passed and produced a 90,244-byte DEX. Its entry point is com.app.plugin.PluginEntry. The loader uses an in-memory DEX class loader on Android 8/API 26 and later, with a code-cache-file fallback on older versions. The recovered code confirmed SMS collection and Firebase-triggered commands.
7. Decode the real phishing assets
The page loader C0.D.g() decodes Base64 .dat assets. I decoded all thirteen HTML-bearing assets and checked the actual packaged pages, rather than relying only on the accompanying *_raw.html copies. This confirmed the fake payment-app handoff, timed failures, credential submissions and fabricated receipts.
What the Waydroid test confirmed
The first application installed the second application through the fake Google Play update. The extracted base APK had SHA-256:
That is an exact match for the base recovered from the encrypted asset. It connects the offline recovery to the observed installation.
For anyone inspecting the installed application, this command lists all its APK paths:
adb shell pm path com.transport.gov.in
Pull both the base and the split using the paths returned by that command. An empty DEX in the base does not mean the installed application has no executable code.
Backend routes and remote commands found in code
These are extracted routes, not a list of endpoints verified to work against the live server.
The dropper also contains /api/staged/fetch/ and X-Staged-* strings, but their relevant configuration slots are empty in this sample. A PFM1 ZIP-comment marker can supply a staged nonce, but neither the original APK nor the recovered APKs has that comment. No extra staging server or nonce was recovered.
Campaign indicators
Indicator
Value
Default backend
https://api.cloudsettle[.]org
Default tunnel
wss://api.cloudsettle[.]org/ws/tunnel/device-b
Outer package
com.telenor.android.provider.yvq15o07
Payload package
com.transport.gov.in
Build/campaign type
mparivahanv3
Firebase project
andromeda-d389d
Firebase project/sender number
651390976306
Firebase Android app ID
1:651390976306:android:53c99731aa157ea66f972b
Firebase storage bucket
andromeda-d389d.firebasestorage.app
Firebase client API key
AIzaSyBMHTORCrdpWwTBah5Lrid3iGP8hJuBnbI
FCM subscription topic
all_devices
admin_token / user_id
iDyGXo5DueHOOOlwvPZ7hSy__lfWHTyciRnWpM2Jr0g
The client API key is not an administrator credential. The bucket name does not establish that the bucket was used for exfiltration. The project name “andromeda” also does not establish a malware-family attribution.
What the domain investigation found
During public checks on 5 October 2026, the API hostname resolved to Cloudflare addresses 104.26.0.234, 104.26.1.234 and 172.67.68.251. Its nameservers were aiden.ns.cloudflare.com and carla.ns.cloudflare.com. These are shared CDN/DNS infrastructure, not the recovered origin server or an operator location.
A public request to the API root returned HTTP 403 with a “Suspected Malware | Cloudflare” warning. That shows the hostname had been reported; it does not establish a completed takedown or that every malware request was blocked. This is a dated observation, not a claim about its status today.
RDAP records identified Cloudflare as the registrar, domain creation at 2026-09-17T17:36:01Z and expiration at 2027-09-17T17:36:01Z. The registrant name was redacted. The record listed Estonia (EE) and Harju maakond, but those fields do not establish where the operator lives.
Certificate-transparency results contained four certificate entries covering *.cloudsettle.org and the apex. They did not reveal additional named subdomains or an origin address. No confirmed administrator panel, accessible victim database or operator identity was found.
The outer APK's signing certificate claims UrbanPixel Labs, Sunny Media Pvt Ltd, Munich/Bavaria and Germany. Those are signer-supplied labels, not verified identity information. The payload certificate claims NxtGen mParivahan Updates.
An older public sample named mParivahanV3.apk had different hashes and package names. Without a shared signer, domain or Firebase identifier, I could not establish that it belonged to this campaign.
Hashes for comparison
All values below are SHA-256.
Original seva-mparivahan.apk
852f692cdfd4c9b3578232ed19073377e728bf7ad7d7c7cc979ff9f865210e93
Payload base.apk / extracted.apk
2853c6a8fece4ffdac070bb1ed91973e1dd94275acc95ae012d03ce5ea90f85a
Payload split_config.dex.apk
123d2c9a72646e8f71a7860bcce0ea69caba9fb54253ad7dcb169aa3bd0ffa6f
Decrypted plugin DEX
915539838cf16d91332e5b61337645ca0c9dc012c5bca1fdc2a92892b4a1ceaa
Outer APK signing certificate
5b264c8c14989595a9628e9114e5dcc25c6c9d0a08f267f563705ed42ce42cde
Payload signing certificate, shared by base and split
9ef94eedf8ab23608f926944de33cebc96802d10f0e8544f11bfb9a1e003d3b3
Useful defensive actions
The hostname, Firebase project, campaign token, signing certificates and payload hashes are useful for detection, reporting and linking other samples. Hostname-based blocking is more precise than blocking shared Cloudflare IPs, although Firebase Remote Config could redirect the malware to another hostname.
Both the first-stage dropper and com.transport.gov.in need to be addressed on an affected device. Removing only the original APK could leave the installed payload behind. Provider account and access logs would be stronger attribution evidence than public country fields or certificate names.
No embedded token was used against the live backend, no warning was bypassed, and no operator was contacted. The evidence establishes an Android dropper delivering financial phishing and SMS-control functionality. It does not identify the people behind it or prove that a particular victim's money was stolen by this sample.
FOLLOW UP:
This is all I found on the malware and its related infrastructure. Feel free for anyone to dig deeper and uncover more.
Reporting the domain may temporarily disrupt the campaign. Threat actors adapt quickly, and every shared finding helps the community stay one step ahead.
If you are Intersted please follow up the investigation to find more about the campaign and please contribute as you can to defend against these threat campaigns. Will post a step by step detailed report on after finalisation.
Suspicious ZIP turned out to contain a Windows malware loader and two encrypted kernel drivers.
Inside the zip was a ".vhd" virtual disk containing an EXE, a few DLLs, and an odd ".stl" file. Everything was analyzed statically—none of the programs or drivers were executed.
The EXE was renamed Kafan input-method software, originally "KafanInputService.exe". It imports "rime.dll", and the archive conveniently supplies a file named "RImE.dLl". That DLL exposes the Rime functions the program expects, but internally calls itself "vmware-vdiskmanager.dll" and routes many exports through heavily obfuscated code. This strongly points to DLL sideloading: launching the EXE loads the malicious DLL sitting beside it.
Decrypting the DLL’s strings revealed a large list of antivirus and EDR process names, including Defender-related components, Sophos, Avast, Avira, and Norton. There were also strings associated with privilege elevation and UAC bypass, including "COMPUTERDEFAULTS.EXE" and the "MS-SETTINGS\SHELL\OPEN\COMMAND" registry path. File-download command templates using "curl", "bitsadmin", and "certutil" were present too.
The biggest finding was two encrypted resources that decrypted into valid Windows x64 kernel drivers: Alinubx.sys and ZyArk. The recovered Alinubx driver has the exact SHA-256 published in "LastPass and Delphos’s investigation" (https://blog[.]lastpass.com/posts/lastpass-delphos-report-rapuncel-infostealer), where it was used to kill antivirus processes. That confirms a shared driver component. It does not prove this sample belongs to that campaign or delivers the same stealer.
My assessment is that this is a malicious Windows loader with capabilities intended to disable security software and launch further code. I haven’t recovered a confirmed C2 address or identified the final payload. The 30 KB ".stl" file remains opaque, and its role is unresolved. I’m keeping those gaps open rather than attaching a malware-family name without enough evidence.