Operation NoVoice: Rootkit Tells No Tales

Authored By: Ahmad Zubair ZahidÂ
McAfeeâs mobile research team identified and investigated an Android rootkit campaign tracked as Operation Novoice. The malware described in this blog relies on vulnerabilities Android made patches available for in 2016 â 2021. All Android devices with a security patch level of 2021-05-01 or higher are not susceptible to the exploits that we were able to obtain from the command-and-control server. However patched devices that downloaded these apps could have been exposed to unknown potential payloads outside of what we discovered. The attack begins with apps that were previously available on Google Play that appear to be simple tools such as cleaners, games, or gallery utilities. When a user downloaded and opened one of these apps, it appeared to behave as advertised, giving no obvious signs of malicious activity. Â
In the background, however, the app contacts a remote server, profiles the device, and downloads root exploits tailored to that deviceâs specific hardware and software. If the exploits succeed, the malware gains full control of the device. From that moment onward, every app that the user opens are injected with attackerâcontrolled code. Â
This allows the operators to access any app data and exfiltrate it to their servers. One of the targeted apps is WhatsApp. We recovered a payload designed to execute when WhatsApp launches, gather all necessary data to clone the session, and send it to the attackerâs infrastructure.  Â
On older, unsupported devices (Android 7 and lower) that no longer receive Android security updates as of September 2021, this rootkit is highly persistent; a standard factory reset will not remove it, and only reflashing the device with a clean firmware will fully restore the device.  Â
In total, we identified more than 50 of these malicious apps on Google Play, with at least 2.3 million downloads. Â
McAfee identified the malicious apps, conducted the technical analysis, and reported its findings to Google through responsible disclosure channels. Following McAfeeâs report, Google removed the identified apps from Google Play and banned the associated developer accounts. McAfee is a member of the App Defense Alliance, which supports collaboration across the mobile ecosystem to improve user protection. McAfee Mobile Security detects this malware as a High-Risk Threat. For more information, and to get fully protected, visit McAfee Mobile Security. Â
Background And Key Findings
Android malware has been moving toward modular frameworks that update themselves remotely and adapt to each device. Campaigns like Triada and Keenadu have shown that replacing system libraries gives attackers persistence to survive factory resets. BADBOX has shown that backdoors pre-installed through the supply chain can reach millions of devices. Recent research has confirmed links between several of these families, suggesting shared tooling rather than isolated efforts.Â
NoVoice fits both trends but does not rely on supply chain access. It reaches devices through Google Play and achieves the same level of persistence through exploitation. McAfeeâs investigation revealed the following key findings:Â
- All carrier apps were distributed through Google Play. No sideloading required, no user interaction beyond opening the app.Â
- C2 infrastructure remains active at the time of publication.Â
- The C2 server profiles each device and delivers root exploits matched to its hardware and software version.Â
- The rootkit overwrites a core system library, causing every app on the device to run attacker code at launch.Â
- The infection survives factory reset and can only be removed by reflashing the firmware.Â
- The chain is fully plugin-based. Operators can push any payload to any app on the device at runtime.Â
- The only task we recovered clones WhatsApp sessions, but the framework is designed to accept any objective.
Naming Â
The name comes from R.raw.novioce, a silent audio resource embedded in one of the later-stage payloads. It plays at zero volume to keep a foreground service alive, abusing Androidâs media playback exemption. We believe it is a deliberate misspelling of âno voice.âÂ
Distribution MethodÂ
All carrier apps were distributed through Google Play and request no unusual permissions. Their manifests include the same SDKs any legitimate app would (Firebase, Google Analytics, Facebook SDK, AndroidX). The malicious components are registered under tampered com.facebook.utils, blending in with the real Facebook SDK classes the apps already include. Â

The initial payload is embedded in the appâs asset directory as a polyglot image. This means the file displays and renders a normal image, but a deeper inspection reveals that the encrypted malicious payload is appended after the PNG IEND marker. Since that marker signals to image viewers that the image data ends there, the appended payload remains hidden during normal viewing.
Geographical PrevalenceÂ
The geographical prevalence map shows the highest infection rates in Nigeria, Ethiopia, Algeria, India, and Kenya, regions where budget devices and older Android versions that no longer receive security updates are common.Â

Malware Analysis
The following breakdown walks through each stage of the chain in order, from the moment a user opens the app to the moment stolen data leaves the device. No single file contains the full chain. Each stage decrypts and loads the next, most are delivered from the server at runtime.Â

Stage 1: The Delivery
The moment the app opens, code injected into the legitimate Facebook SDK initialization path runs automatically. No user interaction is needed. It first checks whether the device has already been processed and, in most samples, whether it is running Android 12L or below. A subset of the carrier apps skips the version check entirely. If either check fails, it stops and logs a message disguised as a Facebook SDK error: âFacebookSdk: Failed in initStore.âÂ
If the device was already processed, the code cleans up files assumed to be left behind by previous runs, including paths that do not belong to any standard Android component. None of these are visible to the user.Â
If the checks pass, the app reads a polyglot image from its own assetsâ directory, extracts the encrypted payload (enc.apk) hidden after the image data, decrypts it to produce h.apk, and loads it into memory. It then deletes all intermediate files, temporary directories.Â


Stage 2:Â The GatekeeperÂ
The decrypted payload (h.apk) loads a native library (libkwc.so) that controls the rest of this stage. It first verifies it is running inside the intended carrier app by checking the package name and signing certificate against hardcoded values. It also checks whether the app is running in a debug environment.Â
libkwc.so contains two encrypted embedded payloads. The first (sec.jar) is a gate designed to detect analysis environments. It runs 15 checks, including emulator detection, root indicators, debuggers, VPN and proxy connections, Xposed hooks, and GPS geofencing. If any check fails, the chain stops silently. The geofence compares the deviceâs location against bounding boxes for Beijing and Shenzhen hardcoded in the native library and excludes devices confirmed to be inside them. If the app does not have location permission, it cannot determine the deviceâs position and defaults to letting the chain continue. Two brands get special treatment: on Gionee devices, all checks except the geofence are skipped; on Meizu devices, the chain follows a separate code path entirely. Gionee devices have a documented history of shipping with pre-installed malware through supply chain compromise.Â
Only if all checks in sec.jar pass does libkwc.so decrypt and load the second payload (hex.jar), which begins contacting the C2 server. If the gate fails, it deletes the working directory and stops.Â

Stage 3:Â The PluginÂ
Once the gate passes, hex.jar sets up a plugin framework built on an internal codebase the authors refer to as âkuwoâ in their package names. It checks in with a C2 server every 60 seconds. Updates are delivered the same way as the initial payload: as image files with encrypted data hidden after the image content. The server returns download URLs in a response field named warningIcon, disguising plugin downloads as icon fetches. A log-deletion routine runs alongside the framework to remove forensic traces from the device.Â
The first plugin delivered (rt) acts as an orchestrator. It manages sub-plugins and handles C2 communication. It checks in with the server, sending over 30 device identifiers including hardware model, kernel version, installed packages, and whether the device has already been rooted. The campaignâs name comes from this plugin: it embeds a silent audio resource named R.raw. novioce.Â
The checkin tells the server two things: who this device is and whether it has already been rooted. If it has not, rt_plugin downloads security.jar, moving the chain into root exploitation.Â

Stage 4:Â The ExploitÂ
security.jar first checks whether the device is already rooted. If it has been, it stops. For unrooted devices, it sends the deviceâs chipset, kernel version, security patch date, and other identifiers to the C2. The server responds with a list of exploit binaries matched to that specific device.Â
Before running any exploit, the rootkit installer (CsKaitno.d) is decrypted from an embedded resource and written to disk. The rootkit is already in place before any exploit runs.Â
The exploits are downloaded one at a time from the C2âs CDN, each encrypted and verified before execution. We recovered 22 exploits in total. Our deep analysis of one revealed a three-stage kernel attack: an IPv6 use-after-free for kernel read, a Mali GPU driver vulnerability for kernel read/write, and finally credential patching and SELinux disablement.Â
The expected end result is the same across all exploits: a root shell with SELinux disabled. From that shell, the exploit loads CsKaitno.d. This is where exploitation ends and persistence begins.Â

Stage 5: The RootkitÂ
CsKaitno.d carries four encrypted payloads: library hooks for ARM32 and ARM64 (asbymol and bdlomsd), a bytecode patcher (jkpatch), and a persistence daemon (watch_dog). It first removes files associated with possible competing rootkits, then decrypts and writes its own payloads to disk.Â
The installer backs up the original libandroid_runtime.so and replaces it with a hook binary matched to the deviceâs architecture. It also replaces libmedia_jni.so. The replacements are not copies of the original libraries. They are wrappers that intercept the systemâs own functions. When any hooked function runs, it redirects to attacker code.Â

After replacing the libraries, jkpatch modifies pre-compiled framework bytecode on disk. This is a second layer of persistence: even if someone restores the original library, the frameworkâs own compiled code still contains the injected redirections
Stage 6:Â The WatchdogÂ
To survive reboots, the installer replaces the system crash handler with a rootkit launcher, installs recovery scripts, and stores a fallback copy of the exploitation stage on the system partition. If any component is removed, the rootkit can reinstall itself.Â
It then deploys a watchdog daemon (watch_dog) that checks the installation every 60 seconds. If anything is missing, it reinstalls it. If that fails repeatedly, it forces a reboot, bringing the device back up with the rootkit intact.Â
After cleaning up all staging files, the installer marks the device as compromised. On the next boot, the systemâs process launcher (zygote) loads the replaced library, and every app it starts inherits the attackerâs code.Â

Stage 7:Â The InjectionÂ
On the next boot, every app on the device loads the replaced system library. The injected code decides what to do based on which app it is running inside. Two payloads activate depending on the app. The malware authors named them BufferA and BufferB in their own code. Both are embedded as fragments inside the replaced libandroid_runtime.so from Stage 5, assembled in memory at runtime, and deleted from disk immediately after loading, leaving no files behind. BufferA runs inside the systemâs package installer and can silently install or uninstall apps. BufferB runs inside any app with internet access.Â
BufferB is the campaignâs primary post-exploitation tool. It operates two independent C2 channels with separate encryption keys and beacon intervals. Both channels send device fingerprints to the C2 and receive task instructions in return.Â
If all primary domains fail and three or more days pass without contact, a fallback routine activates between 1 and 4 AM, reaching out to api[.]googlserves[.]com for a fresh domain list. Because BufferB runs inside any app with internet access, it can be active in dozens of apps simultaneously on a single device.Â

Stage 8:Â The TheftÂ
The only task payload we recovered is PtfLibc, delivered to BufferB from Alibaba Cloud OSS. Its target is WhatsApp.Â
PtfLibc copies WhatsAppâs encryption database, extracts the deviceâs Signal protocol identity keys and registration ID, and pulls the most recent signed prekey. It also reads 12 keys from WhatsAppâs local storage, including the phone number, push name, country code, and Google Drive backup account. For the client keypair, it tries multiple decryption methods depending on how the device stores the key.Â
It sends the stolen data to api[.]googlserves[.]com through multiple layers of encryption and deletes the temporary database copy when done.Â
With these keys and session data, an attacker can clone the victimâs WhatsApp session onto another device.Â

InfrastructureÂ
The campaign spreads its C2 communication across multiple domains, each serving a different function.Â
fcm[.]androidlogs[.]com handles initial device enrollment. Once the plugin framework activates, stat[.]upload-logs[.]com takes over as the primary C2 for plugin delivery, device checkin, exploit distribution, and result reporting. config[.]updatesdk[.]com serves as its fallback. Exploit binaries are hosted separately on download[.]androidlogs[.]com, with an S3-accelerated endpoint (logserves[.]s3-accelerate[.]amazonaws[.]com) as the primary CDN. This endpoint returned 403 errors during our analysis.Â
Task payloads for BufferB are hosted on Alibaba Cloud OSS (prod-log-oss-01[.]oss-ap-southeast-1[.]aliyuncs[.]com). PtfLibc beacons to api[.]googlserves[.]com, a domain designed to look like Google service traffic at a glance.Â
The domain separation is deliberate. Taking down one domain does not affect the others. The C2 can update BufferBâs domain lists at runtime, and a fallback routine fetches fresh domains from hardcoded backup endpoints if all configured domains go silent for three or more days.Â
RecommendationsÂ
Because the rootkit writes to the system partition, a factory reset does not remove it. A reset wipes user data but leaves system files intact. Compromised devices require a full firmware reflash to return to a clean state. Blocking the C2 domains and beacon patterns listed in this report at the network level can disrupt the chain at multiple stages.Â
Attribution Â
Several indicators link NoVoice to the Android.Triada family. The property (os.config.ppgl.status) NoVoice sets to mark a device as compromised is a known indicator of compromise for Android.Triada.231, a variant that uses the same property to track installation state. Both NoVoice and Triada.231 persist by replacing libandroid_runtime.so and hooking system functions so that every app runs attacker code at launch. Whether NoVoice is a direct evolution of Triada.231, a fork of its codebase, or a separate group reusing proven techniques, the shared approach suggests access to a common toolchain.Â
ConclusionÂ
What makes NoVoice dangerous is not any single technique. It is the engineering effort behind the full chain: a self-healing pipeline that goes from a Play Store install to code execution inside every app on the device, survives factory reset, and monitors its own installation. The operators built a delivery system, an infrastructure.Â
We recovered one task. The framework is designed to accept any number of them, for any app, at any time. The C2 infrastructure remains active. We do not know what other objectives have been deployed before, during, or after our analysis. The WhatsApp session theft we observed may be the least of it.Â
The rootkitâs persistence model, overwriting a system library inherited by every process, patching pre-compiled framework bytecode, and monitoring its own installation with a watchdog, makes remediation difficult.Â
This research underscores McAfeeâs ongoing role in identifying advanced mobile threats and working with platform partners to protect users before largeâscale harm occurs.Â
ReferencesÂ
https://www.kaspersky.com/blog/triada-trojan/11481/Â
Indicators of CompromiseÂ
Command and Control ServersÂ
api.googlserves[.]comÂ
api.uplogconfig[.]comÂ
avatar.ttaeae[.]comÂ
awslog.oss-accelerate.aliyuncs[.]comÂ
check.updateconfig[.]comÂ
config.googleslb[.]comÂ
config.updatesdk[.]comÂ
dnskn.googlesapi[.]comÂ
download.androidlogs[.]comÂ
fcm.androidlogs[.]comÂ
log.logupload[.]comÂ
logserves.s3-accelerate.amazonaws[.]comÂ
prod-log-oss-01.oss-ap-southeast-1.aliyuncs[.]comÂ
sao.ttbebe[.]comÂ
stat.upload-logs[.]comÂ
upload.crash-report[.]comÂ
nzxsxn.98kk89[.]comÂ
98kk89[.]comÂ
Carrier App SamplesÂ
03e62ac5080496c67676c0ef5f0bc50fc42fc31cf953538eda7d6ec6951979d8,com.filnishww.fluttbuber.storagecleaner,Â
066a096a3716e02a6a40f0d7e6c1063baecbebc9cbcc91e7f55b2f82c0dad413,com.wififinder.wificonnect,Â
0751decd391fa76d02329b0726c308206e58fc867f50283aa688d9fe0c70e835,com.wuniversal.lassistant,Â
07a9d41c1c775def78a017cf1f6e65266382e76de0f05400b3296e2230979664,com.dynamicpuzzle.cvbfhf,Â
0f28c49b24070a36dec09dd9d4b768e1ef6583b4891eca2e935a304ce704fcce,com.wgoddessg.sgallery,Â
106edd06b6961c3d38edfefd2869ee05285f11b68befe145b124794d0e79e766,com.crazycodes.blendphoto,Â
183e9174e51786be77d1341bcf7f05514f581823532028119c5844a8a5111848,com.colorbrickelim.inationl,Â
1e0376330ff9e97f798870da8433c81e39f3591c82497ca1f6b5f00878d0221a,com.crazycodes.photomotion,Â
1e7fe0ae7546162f23ff4f6e570f51b38562bf4f0ffd9305533b43d19574be38,com.swiftc.tcleans,Â
1e8b048c8d32662f340787893d9ca824b039c14fb91bcc16e185a8bb872e0b80,com.mybatice.googcomlayou.phonecleaner,Â
224e2395d3df96cf19e0b7be9731452da5b568026d81bd0981e48893f6a66859,com.glamorousg.sgoddesslys,Â
2c2c965f3d091693bc6906fc2ed8d03ffccb84e0665841f2d073c2f0a09261bc,com.myapps.gooble.mobile1.maxclean,Â
30504104f232a990f8226ff746b1718aafb727ce111d5a538962cc5e06c4259a,com.mybatice.smartersleep.junkfiles,Â
3937b0bec287662fd82fca4693c8b3619b8c61eca7fe6efa7540c1ae291f8759,com.crazycodes.beautycam,Â
4830a985f064974e6b5d19ae95d645d01fb57edd975a4fce5a1453c2ada70d4e,com.khanbro.gamestation,Â
4f7825647bab001298f768302d0eeb6e0d639d401dc8b5bf60a4b9841a93c980,com.wBoothCash_18748294,Â
4fbf1906fe02745cbf0350563440e9a05d19cd4a27c4fb6b67436392a18a0cd4,com.steppay.yrewards,Â
54224288aa9fa3d4281fb91ad7b202fbc3e5708b173e319b6b450ad15bcdab43,com.scleanm.nmastery,Â
594521e642fee75d474d8d0be839ebe9341f30196b19555882499145bf00746b,com.qwalkingr.grewards,Â
721d92d30fbb90fe643507055baa4cce937c8659f1520be1bbce7f9669af6f84,com.modes2048.gamepro,Â
7d90ee0be5eb63fbaa6839efdd6217b482576b1bab553731cac0b55f2fa1e6fa,com.jkesogeop.classicsudo,Â
7f00991e63154a79ea220b713fcfb2ef8b8db923a75366a61e9bc30d9c355274,com.glamorousg.sgoddesslys,Â
8cd77df7cf2242105b12297071ad1d11e91264f9de311d1b082666da19134476,com.wtoolboxp.xpro,Â
974a5d005d3cfe4c63bd7a46ca72c6716c6c6de397d2e3e19b1730def31f7825,com.systmapp.mobile1.cleanmanager,Â
98819230a6c3f5092517ada9652e9156e338acc27d29e4647b3cb69cddb668cb,com.crazycodes.airvpn,Â
98db4904c3299b8ac383dd177c3cde87af25c088df1988f484427aab3b5c4e0d,com.wlifetoolp.lpro,Â
9b9f55c4a68385e4a739c7d11159c9b4ab006660142331e8bdc477b5eba62aad,com.ulifea.eassistants,Â
a02694b5de7a8a6ef3024d53e54a54a676f992bfa1e070f07827ab9b5dd1365c,com.priceper.km,Â
a1e77c148f190b6bfdd40ce657722e902a31cedecab669dd6f78f38b6b18ddf7,crazycodes.notes.app,Â
a430123efe9611f322fbc3c459fc5ec13abbb0def88ba3ec56a05a361a51a9ac,com.gbversion.gbplus.gblatestversion,Â
ab6365bf7e6c7fba6867b44a80e8bf653c7b66ff91204ee3e2981b6532fea7ee,com.snowfindthesame.samethesnowswe,Â
b4438ac1694e3a08a994750a7ac76399c48d5d3446e90ebebbea1f8694bf3dd5,com.guidely.earningapp,Â
b8087e3535d395210b80637be35da6ae8e10450b6fb87de62a284d5d7397cd17,com.shcoob.groobe.timebuke,Â
bf47dc1577c8b862c4e849a7ce52e143239f2f7274421befa902baf4bd1c4a19,com.wlifet.etoolbox,Â
c332166f720e4d2f6f9b59993559df05281e7d2fbd56f90a7f2399a0ac620295,com.ebitans.tenstarbd,Â
c509a98d0823add0c1440a7b043586eb5a8069fbb776ca36252f5b7653c92cb7,com.whabitn.tnotes,Â
c517b26dfc8ffd5de7f49966ff3391475f80299ebc6ad9988bf166029cf76c91,com.filnishww.fluttbuber.storagecleaner,Â
cf945c433aa80120be10566b9f1ae88e043f96872996f599b75bb57c74248e56,com.mfunt.ttetris,Â
d72d96c6f299fe961dd98655e0468e45ed3ac03df0cfa499e27d4c399e304500,com.wififinder.wificonnect,Â
db1168f2cb3b25ef65e06eb4e788ddda237a428fbce0725de1e9d70b36e96833,com.whomea.eassistan,Â
ddc4da4c63c8bc7df53c3c7fe350b56ad31f313c7d95b472dc45a9fcf85273f0,com.mi2048nig.game,Â
df00753933359d7369668eddeb0dc2565f075c78e4b46f3cabd2e8ff31eda42e,com.sportscash.xyz,Â
e32c8a869585c107ccd1586b5edebc1d8eaa18017c2dd39b6267eec4db7f7410,com.biopops.mathly,Â
e5b8d25ef612f0240ce28fbffd550fd4e0b9abdbf325e3ff85718e8312b70c2b,com.wdailyn.anova,Â
e5f3aa5ef6b5b5fa94a921b55f52aa2c1011486b7370f1585deb6d571325ebcb,com.khan.pregnancyexercise,Â
ec79443aa53864e4d322b8fa8fd4aad0ef878221f01e7d32512694ba24992aee,com.merge2048joy.joy,Â
f654c5f926ebfcded4c0d07590972536280454e2501dc8a525390402fa945ff1,com.kgoddessv.svibe,Â
f7c664ea66c43a82801ed7da23369af1e285857c1a4bf200147b716715f09d3f,com.chall2048enge.game,Â
fc3b06c36feb38ed62f3034e428e814d6e1ac06ec1569ea22428374b8d15d848,com.jekunotesimple.notesimple,Â
fd62c2bfa2277eff8787926f9976aa4a11235a18a9a543ced71a509c6ebf2bf2,com.game.ludoplay,Â
The post Operation NoVoice: Rootkit Tells No Tales appeared first on McAfee Blog.









































