In this malware-everywhere context, the best way to stay safe is to install software only from trusted locations, like Google Play. Starting with 2011, Google managed to reduce the amount of malicious applications in its store by using an in-house automated antivirus system, called Google Bouncer.
However, since nowadays everything is continuously evolving and adapting, nothing is bulletproof and the bad guys found various ways (e.g. delayed backdoor trojan, dendroid malware) to trick the automated checker and upload malicious apps in the official store.
This is also the case for today’s case study – a trojan from the MKero family which was recently discovered in Google Play masked as normal gaming applications:
com.likegaming.gtascs (md5 14cdf116704af262174eb0678fd1b368), com.likegaming.rcdtwo (md5 39b84a45e82d547dc967d282d7a7cd1e), com.likegaming.ror (md5 69820ddcab4fe0c6ff6a77865abf30b9), com.likegaming.rprs (md5 8c496957d787861c0b11789a227a32c7), com.likestudio.offroadsimulatoreone (md5 c7478eff0c2eca8bcb5d0611bfec54d6).
This type of malware was discovered in 2014, but for the first time is now found in the official Google Store – which means that its developer(s) added special code to bypass Bouncer. Once installed on the device, the trojan’s logic is very simple: it secretly subscribes the victim to premium SMS services for which the user will be charged monthly with a minimum of $0.5 per message. In addition to bypassing Bouncer, the main peculiarity of this malware is its ability to automatically “resolve” the CAPTCHA image required in the subscription process, by sending it to an online image-to-text real-time service. Furthermore, this trojan is completely silent during the installation and, more importantly, during the infection time by hiding any incoming SMS sent by the premium subscription services.
How exactly is it doing its “thing”?
We know what this trojan does and how it passes the most complicated task (CAPTCHA decoding), so it will definitely be worth to dig further in its internals to find out how it works exactly.
For our analysis, we’ll use the com.likegaming.gtascs (md5 14cdf116704af262174eb0678fd1b368) apk from the above mentioned list of infected packages.
Let’s start by checking the internal APK structure – this can be done by extracting it (or just by listing the files) with any zip tool (e.g. unzip, 7-zip, winzip):
$ tree -L 2
│ └── bin
│ ├── armeabi-v7a
│ └── x86
│ ├── CERT.RSA
│ ├── CERT.SF
│ └── MANIFEST.MF
│ ├──[skipped res folders]
Nothing special so far, all the usual files (manifest, classes, resources) and folders (res, lib, assets) are there and they seem to contain usual APK data.
Since the AndroidManifest.xml file is the entry point of any apk, we’ll continue the analysis here. In order to convert the binary XML into the human readable format, we need android-apktool which will also do some extra decoding required later:
$ apktool if com.likegaming.gtascs.apk
I: Framework installed to: $HOME/apktool/framework/127.apk
$ apktool d com.likegaming.gtascs.apk
I: Using Apktool 2.0.1 on com.likegaming.gtascs.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: $HOME/apktool/framework/1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...
From the decoded XML file, one can usually check various tags/elements like: package name (com.likegaming.gtascs, in our case), needed permissions, activities, services, receivers.
When taking a look at the permissions, some of them seem very suspicious (check the highlighted lines) for an application which is supposed to be a normal gaming app:
Thus, the required permissions are the first suspicious thing about this app and, if the user is properly cross-checking them with regard to app’s scope/description, the installation should be aborted at this point. But, we all know that this wont happen too often and, usually, the required permissions will be simply ignored and accepted by the regular user.
Next, let’s check the main activity declaration – nothing special from the name, so we’ll have to dig in its code later on:
There are also various other activities in the manifest, but we’ll first focus on the declared services which, by definition, are background tasks that are run even when the user is not interacting with the application. There’s not much information though, just some suspect names for the services starting with Mk:
Things are getting more interesting for the receivers part – there are 2 of them having a priority of 1000 in the intent-filter element:
From the information extracted from the manifest file we’ve found the following: suspect permissions, the name of the main activity, the services which can be started by the app and 2 high-priority receivers (one for the SMS_RECEIVED intent and the other one for the BOOT_COMPLETED intent).
It’s now time to start looking into the code after every important activity/service/receiver found above. For this, the file classes.dex, which is in Dalvik VM format, must be decompiled into a human-readable format; we already decompiled it to smali/baksmali with the manifest file conversion, but it’s also possible to convert the dex to jar and then open the jar file with a java decompiler, like jd-gui, in order to view the java code.
Analyzing the main activity, com.unity3d.player.UnityPlayerActivity, appears to be a dead-end because it’s basically calling code from the legit game engine framework, com.unity3d. Therefore, nothing malicious is happening when the user is actually opening and playing the game. That being said, it means that the malicious code is activated by other means, like broadcast receivers. So let’s continue by checking the code of the 2 high-priority broadcast receivers found in the manifest – com.mk.lib.receivers.MkStart and com.mk.lib.receivers.MkSms.
The first receiver, com.mk.lib.receivers.MkStart, which is called whenever the phone is (re)started, is creating an intent which repeatedly starts (using 1h delay) a new service, com.mk.lib.MkProcess:
Looking at the onStartCommand method of com.mk.lib.MkProcess service, it appears that this one is starting a new background thread that executes the com.mk.lib.MkProcess$Commands.doInBackground method which is doing the whole magic (communicates with the C&C servers to get the URL(s) of the SMS premium servers and then starts the registration process):
Now let’s try to find the C&C domains which seem to be returned by the com.mk.lib.heplers.Functions$getDomains (notice the spelling error – heplers instead of helpers) method. Unfortunately, my version of jd-gui tool is unable to decompile the com.mk.lib.heplers.Functions file (probably because of the obfuscation), thus we’ll look into the smali code instead – smali/com/mk/lib/heplers/Functions.smali file. From its smali, the method is calling another private method, com.mk.lib.heplers.Functions$appDomains, which seem to directly return the name of the used domains:
Unfortunately, as it is the case with the whole application, the strings are heavily obfuscated (see highlighted areas), so they do not make much sense in this form. Luckily, the domains seem to be in-place decoded with the com.mk.lib.heplers.Data.Http.V method. Looking at the decoding method, one can see that it’s doing a lot of heavy stuff (multiple loops with various bitwise operators) and can’t be easily reversed, so we need another way to obtain the original strings.
Since the method is implemented in the decompiled jar, we can create a simple java program which simply calls the decoding method with the obfuscated string as input. While trying to do so, you’ll get a java compilation error because the decode function is defined as static and is not accessible from the exterior of the package. Fortunately, this can be bypassed using java reflexion – I have implemented a simple java program which loads the method, makes it accessible, then calls it with the provided input and, in the end, prints the result on standard output:
Finally, running the above java program with our strings, we get the following results:
$ java -cp .:classes-dex2jar.jar MethodCaller 'com.mk.lib.heplers.Data$Http' V "obfuscated_string_1" "obfuscated_string_2"
Thus, the malware tries to communicate with the first responsive C&C server from the above lists and, once it gets a response, it will start the SMS subscription process.
Another interesting service is com.mk.lib.MkPages which handles the CAPTCHA: after extracting the image from the subscription page, it’s sending it to https://antigate.com and then is waiting maximum 2.5 minutes to receive the text. Check the following highlighted text from the com.mk.lib.MkPages$doInBackground method, after deobfuscating the strings:
Let’s move now to the 2nd receiver, com.mk.lib.receivers.MkSms, which will be called before any other broadcast-receiver (due to its high-priority, 1000) whenever the device is receiving a SMS message. After decoding the strings from its onReceive method, one can see that this service is responsible with the SMS code and activation link extraction needed in the subscription process and, also, with blocking of further SMS messages coming from the subscription server:
This is pretty much all about the internals of this trojan and, coming back to the Bouncer bypassing, we can see now that the malware passed undetected due to the delayed infection (i.e. is waiting 1h in order to start the subscription process).
In conclusion, no matter how smart the (automated) application checkers are, the bad guys will always find new and sophisticated methods to infiltrate malicious code even in official stores. In this circumstances, Avira is helping you to fight against potential malware – so don’t wait to be infected and install our free Android product today.