code

Thursday, September 20, 2018

Hacking android apps to remove annoying ads



No one likes ads. They're annoying and pop up in the worst times possible, just before we need to view this item, read an article or finish that boss in your favorite game.
So, on this post, I'll see what I can do to get rid of most (if not all of them) in an Android app.

As always, warning first:
I don't take any responsibility to bad things that might happen to your phone/apps, do things responsibly and always backup. Also , hacking to proprietary apps is probably illegal anywhere in the world, and I did those researches for academic reasons only!
If you want to support the app developers, buy a premium license for the app, without ads (if that's an option), or just learn to live with them :)

Now that we got this away, let's start with the tools of the trade, in order to decompile and investigate an Android app:

- apktool 
- dex2jar
- jd-gui or any other java decompiler (I also used Luyten)



The ads I'm going to talk about and see if we can remove, that from what I've seen are also the most popular ones, are: banner ads, native ads (the ones that are implemented inside of your activity, like where you're reading some article, and somewhere between the text blocks, you see an ad) and splash ads (aka pop-ups. The most annoying if you ask me)

First let's unpack the app. Get the apk of the app you want to investigate (pull it from your phone if it's installed or download it from the internet).
Unpack it with: apktool d [your apk file]
You'll get a directory with the app reverse domain name, inside you'll have some directories and files. The ones we care about are: AndroidManifest.xml , the smali directory and res directory.



The res directory is anything related to the app's resources. It will include all of the layouts, strings (in different languages) , sometimes data like sounds,videos and more.

The easiest thing we can do, is just try to remove all the layout that are related to the ads and how they are shown on the screen (but be careful with that, make sure you're removing only layouts you know for sure what they are for).
So on the app I investigated, after searching a bit on the app itself and its strings.xml and then crossing it with words I searched like 'ad' , 'ads, 'splash' etc , I found a layout for the bottom banner of the app. I also searched it via the java decompiled from dex code ( I'll explain in a bit)  to make sure it's on the activity that it should be in.
Then what I did was just removing the 'android:layout_width' and 'android:layout_height'.
I guess you could also just give it a 0 value or manipulate it in another way.
With some researching, you could do the same thing for the native and splash ads. 
The problem with the splash ad though, is that unlike the others, it's usually inflated above an activity and have some kind of timeout , after the timeout ends (or if the user click the 'x' button) it'll deflate and return back to the activity behind it. So if we just remove the layout properties for it, we'll probably won't see anything for a few seconds (or maybe a spinning wheel) and then return to the actual content, which is not less annoying than seeing the actual ad.

So what can be done?

So, on the app I investigated (some popular news app), there was an option to buy a premium account from within the app, and get an ads-free version of the app.
I started examining the code, to see if I can find any reference for this option, maybe if this check is done on the client side, we can manipulate and patch the app, so we'll have this ads-free version for ourselves.
In order to view a source code of the app, we need to do a couple of things:
1. First we need to extract the .dex code (Dalvik Executable - where all the the app code, assembled in a package.class format, is stored). To do that all you have to do is open the .apk file with your favorite archive manger, like 7zip or Winrar and extract the classes.dex file.
2. Use dex2jar , to convert the .dex file to a .jar, so our java decompiler can read it. This one is easy - just launch from your terminal:  'd2j-dex2jar classes.dex'
3. The output of the former will be a 'classes.jar' file. You can then start jd-gui and open this .jar file
On jd-gui , you'll hopefully get something similar to:


Since most apps will have at least the default obfuscation used when compiling an apk (ProGuard), the app's classes, functions and variables will have random letters instead of their actual names.
Most of the code we're looking for will be under com.*appname* package
In order to start searching, you can check your manifest file to see your activities' names, then search things like their layouts. Then, on the excellent  jd-gui search , you can cross tour findings and see if they are found within the app's code.
I searched for things like 'payment', 'premium', 'ads free'...You get the point :) 
You could also search for a string that shows when trying to buy the premium option (like a dialog that says something like 'click here to buy the app'), and then follow the code flow from there or search for 'Log.*' functions.
A lot of the time , app developers will log their functions when developing and debugging the app, and write critical things there (like what happens when returning from some function with x value or y value). For some reason, those log functions will not always be removed from production releases. Luckily for us, we can use that for our advantage to get some hints :)
I, eventually, found a function the loads the splash ad on the screen if it's the free version of the app.
Cool, now all we need to do is comment out or remove this code, and we'll have an ads free version finally!
Since the decompilation dex2jar provides us is only partial, we cannot just change the code in java and recompile to dex.

Enter: Smali

"smali/baksmali is an assembler/disassembler for the dex format used by dalvik, Android's Java VM implementation" (from their github project)

So Smali provides us some kind of assembly to the .dex format. As always, before changing anything, make sure you know what you're doing, cause any little wrong change can crash the app.

In order to modify any code, check the class name of the function or if statement you wish to change. Then, go to the smali directory I mentioned before, and search for the same path you found on jd-gui, for the part you wish to change.
Open it with your favorite text editor and edit whatever you need. You can remove the function completely, or maybe change a value before a jump, or change what will happen after some condition is met:
Here's an example taken from xda-developers.com:
Java code:

if (flagx == 1)
 flagx = 2
else
 flagx = 3

Smali code (flagx variable is referenced as v0) :

const/4 v1, 0x1
if-ne v0, v1, :cond_0
const/4 v2, 0x2
move v0,v2
goto :goto_0
:cond_0
const/4 v2, 0x3
move v0,v2
:goto_0

If you wish to do more advanced stuff, you can search online for smali/backsmali guides, and find how to write more advanced smali code.
After we finish editing and saving, we need to pack the code back to dex with:
'apktool b [apk dir name] [apk_file.apk]'
One last thing left to do, since the original android app was signed with their google play key, when we'll try to install the apk we'll have an error. In order to bypass that we can sign the apk with debug keys, as done when debugging an ongoing app. If there are no internal checks, like checking the android:debuggable flag is always false, you'll be good to go and install your modified apk on your device. Just make sure, on your android settings, that you enable installing apps from 'Unknown Sources'  .
I used a program called signapk.jar to sign my apk , but you can maybe use something easier like 'https://github.com/appium/sign'.

That's it for now, go break stuff :)
Cheers

Mastering Problem-Solving and Cultivating a Research Mindset in the ChatGPT Era (and why you still need to RTFM)

  In this post I'll present a technical problem (some will say it's probably a bug more than it is a feature) I had with a VR app, h...