An apparently benign app distribution scheme which has all it takes to turn (very) ugly
This articles discusses a recent Android sample from January 2021. It was first scanned on the 11th, but according to its certificate probably released on the 7th. Similar samples were seen in December 2020. sha256:f699f9e50e8401943321d757a9c1bab367473f102c0abfb57367e9252aae7fde
Packer
It is immediately clear the sample is packed. When the sample is launched, a class com.android.StubApplication
is called. This loads another DEX, which is decrypted from assets file qoh
.
The name of class StubApplication
reminds us of Tencent, Baidu or Qihoo packers, but not quite, because, in that case, the asset decryption is performed by a native library named libTmdsdk.so
.
Note you can get the unpacked JAR’s full path without pain with Dexcalibur or House. And then, do an adb pull
to retrieve the file.
The sample has only been compiled for ARMEABI-v7a. Consequently, to run or hook the sample, you’ll need to get an Android emulator for ARM.
Downloading plugins
The unpacked JAR consists of a manifest and a classes.dex
file. We find the main activity which was referenced in the packer.
The sample next queries a first URL to get the IP address for a “version” server. The sample posts to the version server details of the phone (IMSI, MAC address, IMEI, model…) and receives a customized list of apps to download. Finally, the sample downloads the apps and loads them silently.
{"code":"1",
"errmsg":"3050",
"host":{"versioncode":"0",
"url":"hXXp://tuiapk.b0.upaiyun.com/dwon/jjlibao130.apk",
"content":"..."},
"mod":{"versioncode":"0",
"url":"hXXp://nwapp.netwayapp.com/update/plugin_wxgjzq3050_1102a",
"md5":"edd7617265ca16e1770b4666fad35c2f",
"content":"..."}}
JSON answer from the version server. Slightly edited for readability.
An easy way to follow the queries is with a Frida hook on the URL
class. I also hooked loadApk
and getRealDex
which are part of the dynamically loaded DEX from x.jar
.
(frida-env) axelle@boostix $ frida -U -l ./dynhook.js -f com.lt7qmgb699f.mnf6viyhwlt
____
/ _ | Frida 14.2.8 - A world-class dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . More info at https://www.frida.re/docs/home/
Spawning `com.lt7qmgb699f.mnf6viyhwlt`...
[*] Hooking dynamic class / method
Spawned `com.lt7qmgb699f.mnf6viyhwlt`. Use %resume to let the main thread start executing!
[Android Emulator 5554::com.lt7qmgb699f.mnf6viyhwlt]-> %resume
[Android Emulator 5554::com.lt7qmgb699f.mnf6viyhwlt]-> [+] DexClassLoader constructor hook: dexpath=/data/user/0/com.lt7qmgb699f.mnf6viyhwlt/app_c/x/x.jar
[*] hooking go...
[*] hooking loadApk...
[*] hooking getRealDex...
URL: hXXp://nwapi.oss-cn-hangzhou.aliyuncs.com/api.txt?679480192
URL: hXXp://nwapi.oss-cn-hangzhou.aliyuncs.com/api.txt?679480192
URL: hXXp://118.190.122.47/netway/android/gamehack2/?act=checkver&referer=3050&v=235&gameid=quan&imei=null&imsi=310260000000000&model=sdk_phone_armv7&android_id=d83ee8a01efeda0f&mac=02:00:00:00:00:00&sysver=7.0&uid=null
URL: hXXp://118.190.122.47/netway/android/gamehack2/?act=checkver&referer=3050&v=235&gameid=quan&imei=null&imsi=310260000000000&model=sdk_phone_armv7&android_id=d83ee8a01efeda0f&mac=02:00:00:00:00:00&sysver=7.0&uid=null
[+] downloadFile: url=hXXp://nwapp.netwayapp.com/update/plugin_wxgjzq3050_1102a dir=/storage/emulated/0/Android/data/com.lt7qmgb699f.mnf6viyhwlt/files/nwplugin/ localname=
URL: hXXp://nwapp.netwayapp.com/update/plugin_wxgjzq3050_1102a
URL: hXXp://nwapp.netwayapp.com/update/plugin_wxgjzq3050_1102a
[+] getRealDex: srcdex=/storage/emulated/0/Android/data/com.lt7qmgb699f.mnf6viyhwlt/files/nwplugin/plugin_wxgjzq3050_1102a
[+] getRealDex returns dex=/data/user/0/com.lt7qmgb699f.mnf6viyhwlt/app_sex/win.apk
[+] loadApk: dex=/storage/emulated/0/Android/data/com.lt7qmgb699f.mnf6viyhwlt/files/nwplugin/plugin_wxgjzq3050_1102a
[+] getRealDex: srcdex=/storage/emulated/0/Android/data/com.lt7qmgb699f.mnf6viyhwlt/files/nwplugin/plugin_wxgjzq3050_1102a
[+] getRealDex returns dex=/data/user/0/com.lt7qmgb699f.mnf6viyhwlt/app_sex/win.apk
[+] DexClassLoader constructor hook: dexpath=/data/user/0/com.lt7qmgb699f.mnf6viyhwlt/app_sex/win.apk
This mechanism is particularly dangerous because, even if at a given moment the downloaded apps are not malicious, there is no way to ascertain the same channel won’t be used later to push malicious ones. Or the first server could be hacked or hijacked to return the IP address of a malicious version server. Additionally, the plugin we downloaded (plugin_wxgjzq3050_1102a
) is encrypted, and decrypted by getRealDex()
. We have all the components for a stealthy install of malware.
Malicious or not?
Despite a very dangerous download & install mechanism, I am not entirely convinced this sample is really malicious. This is because, so far, in the end, the distributed apps seemed at most scam or adware. Some AV detect the sample as a “Penguin” trojan dropper. It does indeed drop an APK. There is only little information what the Penguin family is, but it seems we should find code that puts a window on top of all others. I wasn’t able to locate such code in this sample, so probably bad naming. So, I named it Riskware/Tenpack!Android
. Until it grows up bad…
To summarize, plain malicious or not, Penguin or not, we need to keep an eye on such samples, because they can turn very bad one day. This is a sample you certainly don’t want on your smartphone 😏
— Cryptax
PS. Have you seen this packer? Or any other comment, please feel free to reply.