The White Ops Threat Intelligence team recently identified 100+ malicious apps, with more than 4.6 million downloads, performing ad fraud. All of the apps use a common code package White Ops has dubbed “Soraka” (com.android.sorakalibrary.*):
In addition to the Soraka code package, we also discovered, in some of the apps, a variant with similar functionality which we dubbed “Sogo” (com.android.sogolibrary.*):
Best Fortune Explorer App
One example of the Soraka package was the “Best Fortune Explorer” app by the publisher JavierGentry80. This app was released on September 9, 2019 and is the only app published by JavierGentry80. Best Fortune Explorer is, as of this writing, available on the Google Play Store and has no Anti-Virus (AV) detections on VirusTotal. This app has more than 170,000 downloads.
Fraud Activity Filters
The apps are using a framework called AppsFlyer for mobile attribution and marketing analytics. The app displays fraudulent ads only if AppsFlyers determines the installation is NOT organic, meaning the install was attributed to a promotional effort by the fraudsters. There are several filters the code checks before a fraudulent ad is shown to the user:
- Screen On
- Interval since installation
- Trigger on/off switches
- Ad Network daily count limit
- Trigger time interval (to space out the ad rendering for each trigger)
The filtering is likely a mechanism to avoid detection from automated analysis and other services that would install the app ad-hoc and then, most likely, be considered as organic by AppsFlyer.
This mechanism also allows fine-grain control of who (or what) receives the ad fraud, using the controls of ad serving platforms. The apps render out-of-context ads when the filter conditions are appropriate.
The Soraka package can be found in com.android.sorakalibrary, and utilizes several triggers to make the determination of what to run. As an example, int[ ] b( ) returns an integer array of filters this trigger (pressing the Home button) needs to check before running. The method public String c( ) in HomeTask returns the name of the trigger. All of the trigger classes implement this method, each returning its name. To further obfuscate the code and make analysis more difficult, HomeTask creates a class named with the Cyrillic character Ӝ, which is part of the Udmurt language. The class Ӝ goes to a Mopub method ah where the onAdloaded function is called to start the ad rendering process.
White Ops Threat Intelligence identified the following ways the app rendered ad fraud:
- Upon unlocking the device, the app code removes the background notification service that halts all fraud activity while the phone screen is off.
- The first Out-of-Context (OOC) ad (shown below) is rendered a couple seconds after the device is unlocked.
- A second OOC ad (not shown) is observed after the first OOC ad is minimized by clicking the hardware’s home button.
- After a few more actions, a third OOC ad (not shown) is rendered.
There is also code initiating fraud activity only while the device screen is ON and the host app is NOT on top.
The Best Fortune Explorer app code dynamically registers broadcast listeners for several actions, which is important to detect things like screen state, user presence, and when the home button is pressed.
The app manifest lists the broadcast receivers class as com.flurry.android.ads.common.component.a.c.a. where we can see the onReceive function in the figure below.
An additional set of broadcast receivers are located in com.mopub.common.c.a.c. As shown below, these receivers will run when the actions, noted in the code comments, occur.
The main Java based persistence mechanisms are initiated by the Java class in com.mopub.common.c.a.c.b, and use imports to start a service. The types of persistences vary. The most common ones are:
- Operating System (OS) syncable account
- Job Service (Persisted when possible)
- Services (Foreground where available)
Method b will set the alarm mechanism, the intent will start com.flurry.android.ads.common.component.a.d.a which is a service:
The method c( ) starts a Job that will periodically run com.flurry.android.ads.common.component.a.d.d. If the SDK version is greater than 24, then the Job is set as “Persisted”, which will make it run even after the device restarts.
Method d( ) has the ability to create an account in the OS, set it to be “Syncable” and to be automatically synced. The method determines the period for the syncing to 100 seconds as seen below:
The new account created was seen in the device Settings>Accounts.
Besides Java based persistence, this threat also uses Native libraries:
The native function dp (Lollipop library) and dk (KitKat library) enter an infinite loop in which every 10 seconds a set of files are checked for locking. A callback Java function is called, if needed, so the files checked are:
If the app is force closed, then the library detects it and brings it back via the java_callback function.
The White Ops Threat Intelligence team continues to monitor these packages and will identify any emerging packages. We recommend removal of any apps listed in the Indicators of Compromise section below.
Indicators of Compromise (IoC)
App Packages Using Soraka and/or Related SDKs: