[Guide] Reverse Engineering Android Apps - A push in the right direction

javabro

Executive VIP
Jr. VIP
Dec 2, 2015
1,934
7,049
I was contacted recently to reverse engineer the Spotify app by a client. The client had already tried it with other developers and failed. Once my initial steps were done (explained below) - he didn't want to move forward.

Spent a few hours on this (for which I didn't get paid). I thought I'd share it here. This is not a complete tutorial. It's more like a push in the right direction for anyone interested in this stuff. I am sure there are better devs here who know better than me. Please free to add your inputs to this thread.


Install an emulator
We are going to use Genymotion for this.
  • Go to https://www.genymotion.com/download/ and install (with VirtualBox).
  • Create an account here, you need the credentials to log into Genymotion (Personal use - gaming)
  • Create a virtual device - I'd advise you to go with an android less than Android version 7.0
  • I'm using both Nexus 6 (android 6.0) and Google Pixel XL (Android 7.1) for this example as I'm testing out some stuff - Reason
FPa1BAL




Run the virtual device and take note of the emulator IP
hr0EGsU


Make sure to enable debugging options on settings -> developer options
hmyTgPK




Download Platform Tools
Download platform-tools from the following link. We need this to talk with genymotion on several occasions.
https://developer.android.com/studio/releases/platform-tools

Unzip platform-tools. Open a PowerShell (or any terminal) and connect to your virtual device.
Code:
adb connect ip:5555
fjlZbuJ




Installing apps on your virtual device
From Genymotion website
Genymotion Desktop virtual devices architecture is x86 (32-bit). If your application uses ARMv7 code, you must install an ARM translation tool to make it work. The ARM translation tool must match your virtual device Android version.

You need to patch your virtual device to install many apps including Spotify/Chrome etc. This is how you do it.

8buHuWf


Now you can install apks on your device using the following command.
Code:
adb install <path-to-app.apk>
63w4MQ6




Install and setup burp to monitor network
Burp is a software you can set up to monitor network calls done via your browser, android apps etc.
Download and install the community edition: https://portswigger.net/burp/communitydownload
Once installed follow the step below and set up a proxy in your device.

  • Open blurp and create a temporary project.
  • Go to proxy -> options -> add and create a proxy to listen to all the interfaces
  • Make sure it is running (checkbox next to it)
mobilesetup_1.png
mobilesetup_2.png

mobilesetup_3.png

  • Go to Wifi settings on your virtual drive and set up the proxy. (Under advance options)
XferPZ0


Now we can monitor all the HTTP data proxy going through your virtual device.
J3fBjET


But If we try to visit an HTTPS site, we get the following warning:
ic5agvG



Installing a self-signed certificate to monitor HTTPS traffic
For this to work. We need to install a certificate in our virtual device.

Save your certificate as cert.cer from Burp as following
eV4PALA


tezHeEx


Push that certificate to your virtual device using adb
adb push cert.cer /sdcard/Download/cert.cer

Go to settings -> security -> Under credentials storage -> Install from SD card and select the .cer file you just uploaded. Sometime you will be asked to set a pin to your device.

I4nK4KC


Once the certificate is installed, you will be able to monitor https traffic without any problem.
If you used Nexus 6 (Android version 6) this is enough to view https data for most android apps.

Tumblr app login for example:
LzCZek9

Once you have the data for these API calls, all you have to do Is write some python scripts using request library to automate account creation, following, etc. The sky is the limit.

But if you tried it against an app like Spotify/Twitter/Facebook etc. This is not possible. This is because of
SSL Pinning.

48o7Ymk


SSL Pinning is a technique that we use in the client side to avoid man-in-the-middle attack by validating the server certificates again even after SSL handshaking

Basically when using SSL Pinning, just using a self-assigned certificate won't cut it. To bypass this, we need Frida.



Frida - SSL Pinning Bypass
Frida is a very powerful tool for reverse engineers. I'll only cover the steps to overcome this ssl-pinning issue. You should read more about it. If you wanna go on this path.

Code:
pip install Frida
pip install objection
pip install frida-tools
  • Save the following code in your plateform-tools directory as frida-inject.js
JavaScript:
/*
   Android SSL Re-pinning frida script v0.2 030417-pier

   $ adb push burpca-cert-der.crt /data/local/tmp/cert-der.crt
   $ frida -U -f it.app.mobile -l frida-android-repinning.js --no-pause

   https://techblog.mediaservice.net/2017/07/universal-android-ssl-pinning-bypass-with-frida/
  
   UPDATE 20191605: Fixed undeclared var. Thanks to @oleavr and @ehsanpc9999 !
*/

setTimeout(function(){
    Java.perform(function (){
        console.log("");
        console.log("[.] Cert Pinning Bypass/Re-Pinning");

        var CertificateFactory = Java.use("java.security.cert.CertificateFactory");
        var FileInputStream = Java.use("java.io.FileInputStream");
        var BufferedInputStream = Java.use("java.io.BufferedInputStream");
        var X509Certificate = Java.use("java.security.cert.X509Certificate");
        var KeyStore = Java.use("java.security.KeyStore");
        var TrustManagerFactory = Java.use("javax.net.ssl.TrustManagerFactory");
        var SSLContext = Java.use("javax.net.ssl.SSLContext");

        // Load CAs from an InputStream
        console.log("[+] Loading our CA...")
        var cf = CertificateFactory.getInstance("X.509");
        
        try {
            var fileInputStream = FileInputStream.$new("/data/local/tmp/cert-der.crt");
        }
        catch(err) {
            console.log("[o] " + err);
        }
        
        var bufferedInputStream = BufferedInputStream.$new(fileInputStream);
          var ca = cf.generateCertificate(bufferedInputStream);
        bufferedInputStream.close();

        var certInfo = Java.cast(ca, X509Certificate);
        console.log("[o] Our CA Info: " + certInfo.getSubjectDN());

        // Create a KeyStore containing our trusted CAs
        console.log("[+] Creating a KeyStore for our CA...");
        var keyStoreType = KeyStore.getDefaultType();
        var keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);
        
        // Create a TrustManager that trusts the CAs in our KeyStore
        console.log("[+] Creating a TrustManager that trusts the CA in our KeyStore...");
        var tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        var tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);
        console.log("[+] Our TrustManager is ready...");

        console.log("[+] Hijacking SSLContext methods now...")
        console.log("[-] Waiting for the app to invoke SSLContext.init()...")

           SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").implementation = function(a,b,c) {
               console.log("[o] App invoked javax.net.ssl.SSLContext.init...");
               SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").call(this, a, tmf.getTrustManagers(), c);
               console.log("[+] SSLContext initialized with our custom TrustManager!");
           }
    });
},0);

  • Download the Frida server from https://github.com/frida/frida/releases/, if you followed my steps you have to download the file ending with android-x86.xz (frida-server-version-android-x86.xz )
  • Move the file to the platform-tools directory and rename it to frida-server
  • Push the file to /data/local/tmp using adb push command
Code:
./adb.exe push frida-server /data/local/tmp
  • Give permission to it using
Code:
./adb.exe shell chmod 777 /data/local/tmp/frida-server
  • Push the certificate we used previously with the name cert-der.crt
Code:
./adb.exe push cert.cer /data/local/tmp/cert-der.crt
  • Push frida.js file we created using the following command
Code:
 .\adb.exe push .\frida.js /data/local/tmp
  • Run the frida-server
Code:
./adb.exe shell /data/local/tmp/frida-server &
F8MCqtF


  • Run the following command in a new terminal (keep Frida server running) and copy the package name you are trying to bypass ssl-pinning
Code:
frida-ps -U
dw7ylwz

  • Hook the frida-inject.js file to the target application using the following command.
Code:
frida -U -f com.twitter.android -l frida-inject.js --no-paus

pfNnXtn


YAY YAY YAY That's it. We have successfully bypassed SSL Pinning. You should be able to view requests from twitter. (Or the app you were trying to bypass)
18wg1WG


Notes:
The above script.js is taken from https://codeshare.frida.re/@pcipolloni/universal-android-ssl-pinning-bypass-with-frida/ and may not work for the app you are working with.

What you can do is decompile the app using https://github.com/skylot/jadx and look for "TrustManager", "Pinning" keywords.

Again, reverse engineering is a big topic. This thread is just a starting point for new developers to push them in the right direction.

Thank you for reading.
thank-you.jpg

 
Nice! I'm on my phone but will do my best:

Any reason for Burp vs Fiddler?
Is there a need for Frida? I've never had any issue with emulating SSL handshakes thus I'm asking.

Great job with the guide nonetheless!
 
Nice! I'm on my phone but will do my best:

Any reason for Burp vs Fiddler?
Is there a need for Frida? I've never had any issue with emulating SSL handshakes thus I'm asking.

Great job with the guide nonetheless!
Burp is just a personal preference.

Well yes, many enterprise like apps (twitter, snapchat, tiktok, ....) enables ssl-pinning/certificate validation (validate the certificate after handshaking).
Since we are using a self-signed certificate, we won't be able to see these requests. Frida can inject code in runtime and (try to) bypass this validation.

The shared script doesn't work for all the checks. If the app uses okhttp3 for example, we may need to use something like the following.
https://codeshare.frida.re/@owen800q/okhttp3-interceptor/
Of course, the best way to do this is to decompile the app and look at the code.

Also, using an older version of an app may come in handy in some cases :D
 
Nice!! Bookmarking this for when I have some free time. Once went in this direction..did most of what you wrote here but got stuck when I hit ssl pinning..and that’s when I gave up...worth trying again because I really need to get Instagram api for some projects I have in mind. ...Spotify too..
 
Bookmarked! Will try this in my free time, thanks for your effort
 
Push to right direction? You pretty much opened it all lol. Thanks a bunch for this. I collected some very valuable info that I might need very soon. ;)
 
Good stuff! I'm usually more of a "look at the code" guy, but I can see this network monitoring approach being quicker and more insightful in many cases :)
 
Nice!! Bookmarking this for when I have some free time. Once went in this direction..did most of what you wrote here but got stuck when I hit ssl pinning..and that’s when I gave up...worth trying again because I really need to get Instagram api for some projects I have in mind. ...Spotify too..

Yep, SSL pinning is tough to bypass, but if we look hard enough, you can sure get it.
Spotify Fake listens = Money :D

Push to right direction? You pretty much opened it all lol. Thanks a bunch for this. I collected some very valuable info that I might need very soon. ;)
Hahah, happy to be help man :D let me know when you try it :)

Good stuff! I'm usually more of a "look at the code" guy, but I can see this network monitoring approach being quicker and more insightful in many cases :)
Looking into the code definitely works. Combining the two will yield amazing results ;)
 
Right now I am building one app and something really got me thinking about how my competitors manage it this guide is pure gold for me.
Thanks
 
Great post! I really liked the ssl pinning bypass part.

One question - What are some of the ways we can go through the code considering most of the big apps obfuscate the code so just decompiling doesn't cut it.

I was trying to reverse engineer snapchat and learned most of the things in this thread but it was not enough and I had to decompile the app but the code was obfuscated and didn't make any sense. Plus, there were thousands of files so it was too hard to go through each one of them and find the code where a particular header is generated. I want to know your take on the code reading part and how one can reverse engineer secure apps.

Thanks for the guide, man! Really helpful!
 
I'm not a tech guy at all. But I like the way you deacribe this unique method and the effort you put here.
First I was thinking I'm gonna try this and lately I realized this is not so simple. Anyway thanks for the contribution and good luck.
 
This is what happened when you had too much caffeine dude! :DI feel like I'm reading something out of this world. You're an alien! Thanks for sharing!
 
Great post! I really liked the ssl pinning bypass part.

One question - What are some of the ways we can go through the code considering most of the big apps obfuscate the code so just decompiling doesn't cut it.

I was trying to reverse engineer snapchat and learned most of the things in this thread but it was not enough and I had to decompile the app but the code was obfuscated and didn't make any sense. Plus, there were thousands of files so it was too hard to go through each one of them and find the code where a particular header is generated. I want to know your take on the code reading part and how one can reverse engineer secure apps.

Thanks for the guide, man! Really helpful!
It is case by case really. I've done this for few apps including musically - now tiktok (which was the hardest). They always obfuscate stuff. But if you look hard enough - you can definitely find it. There is no straightforward answer unfortunately for every app. With experience, you will know where to look for. The best way to get to this is keep trying it with different apps and especially be active on other places where developers/reverse engineers hang out.

This is what happened when you had too much caffeine dude! :DI feel like I'm reading something out of this world. You're an alien! Thanks for sharing!
Ha ha :D Well i recently started doing the keto diet, and i have all this energy man. It is going to come out one way or another. :D
 
Back
Top
AdBlock Detected

We get it, advertisements are annoying!

Sure, ad-blocking software does a great job at blocking ads, but it also blocks useful features and essential functions on BlackHatWorld and other forums. These functions are unrelated to ads, such as internal links and images. For the best site experience please disable your AdBlocker.

I've Disabled AdBlock