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” (*):

Figure 1 Soraka Package

In addition to the Soraka code package, we also discovered, in some of the apps, a variant with similar functionality which we dubbed “Sogo” (*):

Figure 2 Sogo Package

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.

Table 1 Best Fortune App Details


Figure 3 Best Fortune Google Play

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
  • TopActivity
  • 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.

Figure 4 Soraka HomeTask Trigger

The Soraka package can be found in, 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.

Figure 5 Soraka Ad Loading Function

Ad Fraud

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.
Figure 7 Best Fortune Screen On Chk

There is also code initiating fraud activity only while the device screen is ON and the host app is NOT on top.

Figure 8 Best Fortune App on Top Chk

Broadcast Receivers

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.

Figure 9 Best Fortune App Manifest

The app manifest lists the broadcast receivers class as where we can see the onReceive function in the figure below.

Figure 10 Best Fortune onReceive Function

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.

Figure 11 Adtl Best Fortune Listeners


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:

  • Alarms
  • 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 which is a service:

Figure 12 Alarm Persistence Mech

The method c( ) starts a Job that will periodically run 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.

Figure 13 Persistence Set

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:

Figure 14 OS sync Persistence

The new account created was seen in the device Settings>Accounts.

Besides Java based persistence, this threat also uses Native libraries:

Figure 15 Native Lib

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:

Figure 16 Java Function Call

If the app is force closed, then the library detects it and brings it back via the java_callback function.

Wrap Up

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:

Package Name:

TAGGED: Bot Fraud