12-11-19 Blog Image

Year after year, developers bang their heads against the obstacles posed by complex frameworks when trying to test their applications offline. In order to bypass this, SDKs started offering “alternative” code paths for offline testing work. However, what do you do when this is not available out-of-the-box? You start hacking and monkey patch it, of course!

Monkey patching is a technique allowing a developer to alter the behavior of a piece of code at runtime, without changing the underlying code. For example, using this technique, a fraudster could make a back button in the app do something different when the program is run than what the original app developer intended. Monkey patching can be used on code libraries, methods, or even variables. While useful for developers to debug code, this technique can also be used to commit fraud.

In the code snippet below, Rafsan Jany (Monkey Patching in Python blog) shows how extremely easy this is to do in languages like Python, where you just need to assign a method its replacement.

Screen Shot 2019-12-09 at 10.58.49 AM

Monkey patch in python
Source: Rafsan Jany - Monkey Patching in Python

This gets more and more complicated as we dive into “deeper” programming languages, as shown by this piece of Java code:

Screen Shot 2019-12-09 at 11.00.03 AM

Method patched to always return false
Source: White Ops Threat Intelligence

The above code is a snippet from the latest finding of the White Ops Threat Intelligence team. It allows app developers to modify any SDK’s internals, in this case an advertising SDK, in order to twist its behaviour to their whim. More on that later, though.

Primal Needs

While investigating a batch of Android apps with high levels of user complaints for displaying ads on top of other apps and hiding the app’s icon, White Ops Threat Intelligence discovered a collection of classes and code which exhibited the monkey patching technique to perform ad fraud.

We dubbed this collection “DefPackage,” as the classes don’t have a specific package name, but are inserted into the defpackage package when first added to the code. The identified apps display out-of-context ads which stick around longer on your screen (thanks to the above mentioned technique) and have been installed over 2.6 million times. White Ops Threat Intelligence shared their findings with Google and all of the offending apps were removed from the Google Play Store as of October 2019.

The main app we analyzed to demonstrate the monkey patching technique was “Cut Paste Photo Editor S” (package name: com.hammergod.picture.photo) which had 100,000 downloads on the Google Play Store before being removed in mid-September 2019. It was marketed as a photo editor, but the app did not live up to the task, according to the comments.

App Name Cut Paste Photo Editor S
Package Name com.hammergod.picture.photo
SHA256 73ef822a22aba4011998741a7ce8c9d2b3a7cfedd58909
bc92bf645a090de22a

Summary of the app information
Source: White Ops Threat Intelligence

Screen Shot 2019-12-09 at 11.02.35 AM

Screenshot of the app information
Source: Google Play Store

A scan of many of the apps identified as having the DefPackage SDK found a plethora of negative reviews as shown below. Many of these apps did not function as advertised and continually generated ads, which may have contributed to their poor scores.

Screen Shot 2019-12-09 at 11.03.45 AM

Screenshot of malicious apps and negative reviews
Source: Google Play Store

The Cut Paste Photo Editor S app included many negative reviews with complaints regarding the app’s monetization practices as shown below.

 

Screen Shot 2019-12-09 at 12.13.58 PM

Comments from Cut Paste Photo Editor S Google’s Play Store entry
Source: Google Play Store

Monkeying Around

The app exhibited an interesting behavior with the use of the getDeclaredField method. Through the use of monkey patching, the author(s) of the DefPackage SDK removed certain checks, including timing for the back button functionality, from the associated advertising SDK. In our tests, the monkey patching changed the time when the back button became available to use, forcing the ads to stay on the screen for longer than we might otherwise expect.

Upon opening the AndroidManifest.xml, two entries stood out:

Screen Shot 2019-12-09 at 12.22.43 PM

Suspicious service inside AndroidManifest.xml
Source: White Ops Threat Intelligence

The PixelService (used for residency) seemed to be present across all the apps (although sometimes renamed). The service had verbose output in logcat (default system log tracer in Android OS) and was visible in the process list.

Screen Shot 2019-12-09 at 12.22.57 PM

Logcat log confirming the service’s activity
Source: White Ops Threat Intelligence

The service tried to restart itself every 5-15 minutes in case it was shut down (through Android’s job scheduler) after which it registered a broadcast receiver in order to hook any user activity (ie. unlocking the phone).

 

Screen Shot 2019-12-09 at 12.23.16 PM

Persistence code inside the malicious service
Source: White Ops Threat Intelligence

Screen Shot 2019-12-09 at 12.23.42 PM

Intents being caught by an obfuscated class inside the app
Source: White Ops Threat Intelligence

The obfuscated strings inside the receiver above were able to be decrypted and identified as:

  • UNLOCK_AD_CLOSE_ACTION
  • UNLOCK_DELAY_AD_CLOSE_ACTION
  • CLEAN_ALL_TASK_ACTION

The authors of the DefPackage SDK used the same encryption techniques as in other parts of the code. With that knowledge and the help of the CyberChef tool, White Ops Threat Intelligence decrypted the obfuscated strings.

The (obfuscated) broadcast receiver listens for the screen on/off events in addition to other internal ad-related events. This gives the DefPackage SDK an entry point for pushing ads right after a user unlocks their phone.

The next step is a helper function called from the broadcast listener to check if all of the following conditions are met before the ad is launched:

  • Computed random number between 1 and 100 is lower than 30
  • Device is connected to the Internet
  • Device screen is on
  • Device is unlocked
  • 8 to 24 hours have passed since the app was installed.

Screen Shot 2019-12-09 at 12.28.18 PM

Checks put in place for randomly displaying an ad inside PixelActivity
Source: White Ops Threat Intelligence

If all the conditions are met, the ad activity is launched through an intent . The popup ad displays in full screen upon triggering the activity.

 

null

 

Cut Paste Photo Editor S app generating out-of-context ad
Source: White Ops Threat Intelligence

The activity is empty initially (just an overlay) and the content is spawned based on some internal logic that’s heavily obfuscated:

 

Screen Shot 2019-12-09 at 12.31.20 PM

Activity shell inside the DefPackage SDK
Source: White Ops Threat Intelligence

Going Bananas

The DefPackage SDK tampers with various variables such as the value returned by the method zzhk which relays information about when the ad is finished and the user can press the back button.

Screen Shot 2019-12-09 at 12.33.05 PM

Method patched to always return false
Source: White Ops Threat Intelligence

Method zzhk always returns false after being patched, which leads to incorrect processing of the back button press so the user cannot exit the ad display.

null

 

Ad SDK code that processes the patched method
Source: White Ops Threat Intelligence

White Ops Threat Intelligence detected the same behaviour on other SDKs as well.

Monkeys in Action

The following screenshots are an example of an ad displayed after unlocking the screen on our test phones during analysis.

animation

DefPackage SDK generating ad after device unlock
Source: White Ops Threat Intelligence

Natural Selection


In order to combat attacks like these, more rigorous framework integrity checks are needed. One way to achieve this is to monitor for class name changes. This is possible in one of the above mentioned cases because the patched member belongs to a Dynamic Proxy. Dynamic proxies are JAVA’s syntactic sugar for performing advanced reflection which hooks every method call done to the object they’re proxying.

To demonstrate this, White Ops Threat Intelligence set up a simple proof-of-concept of a monkey patch scenario. The project is available here. We have a class that sets up a private value which can only be read. The value is used inside a simple toast notification.

Screen Shot 2019-12-09 at 12.41.50 PM

Container for private variable
Source: White Ops Threat Intelligence

Screen Shot 2019-12-09 at 12.42.07 PM

Tampering the “getter” using the same technique
Source: White Ops Threat Intelligence

In order to detect any tampering, we’ll implement a simple SDK to detect any changes in the class name of an object. This is done via locking the class name of a member of any publicly accessible parent object from the residing point in the SDK.

Screen Shot 2019-12-09 at 12.42.32 PM

Locking down the class names
Source: White Ops Threat Intelligence

To detect tampering, we have to check our locked objects’ type against their original types. To do this, we just have to repeat the above procedure for each member and parent pair. If we detect a mismatch, we instantly break the loop and report the tampering.

Screen Shot 2019-12-09 at 12.47.23 PM

Checking class names against the locked types
Source: White Ops Threat Intelligence

As seen in the below screenshot, before initiating the monkey patch, our initial Secret class matched the initially stored value.

Screen Shot 2019-12-09 at 12.49.02 PM

Before tampering
Source: White Ops Threat Intelligence

After the tampering, we can see the change in the class name to that of the proxy object:

Screen Shot 2019-12-09 at 12.49.52 PM

After tampering
Source: White Ops Threat Intelligence

One obvious flaw of a mechanism like this would the classic “who watches the watcher” scenario, as the anti-tamper-proof SDK can also be tampered with by a threat actor with enough time on their hands. This is why SDKs need to be heavily obfuscated and the “locks” hidden well inside the code, in order to prevent an adversary from easily modifying this anti-tamper layer.

While not a perfect solution, remember: You don't need unbreakable code, just a way to delay the bad guys until your next release cycle.

Indicators of Compromise (IOCs)

Below is a list of identified app packages using the DefPackage SDK and corresponding installation numbers, as of early September 2019. All of the apps have been removed from the Google Play Store.

Package Name Installs
com.acaleph.octopus 500,000
com.butterfly.picture.photo 50,000
com.chile.eritrea.sky.camera 50,000
com.cyprus.ghana.blur.image.plus 100,000
com.estonia.brunei.fashion.hairstyles.pic.editor2019 100,000
com.flatfish.soldiercrab.autoblur.photo 100,000
com.gailun.effect 100,000
com.game.panzerkiller 100,000
com.game.rotarypaint 100,000
com.hammergod.picture.photo 100,000
com.hnnmsl.picture.fashion 100,000
com.jordan.iraq.blur.image.pro 100,000
com.kiribati.zowbat.image.blur.editor.free 100,000
com.maxwell.photocutpro 100,000
com.missing.collage.picture 100,000
com.oman.mayotte.hairstyles.photo.editorplus 50,000
com.palau.guam.fashion.hairstyles.pic.editor 100,000
com.pop.color 10,000
com.positive.photo.collage 100,000
com.pottwal.bowhead 100,000
com.qingjiao.collage.photo 100,000
com.risemeup.protectball 1,000
com.rwanda.seychelles.latest.hairstyles.free 100,000
com.seisikou.photobackground 1,000
com.sgame.cannonbricks 1,000
com.sgame.connectionpipe 10,000
com.sgame.drivesafely 5,000
com.sweets.caincamera 50,000
com.yasuo.art 100,000
com.yongdegree.face.feature 100,000

Table 1 - Apps using DefPackage SDK
Source: Google Play Store

Tagged: SecurityResearch & Detection