Frida for all! Pt. 3

This is going to be another worked example - nothing new, this has been done by others before. I hope to demonstrate a fully worked example from the ground up as a record of how to go from knowing nothing about an android app to being able to disclose some interesting artefacts about it.

What? Why instagram?

Instagram’s API has some interesting properties. Every request is HMAC’d with a SHA256 standard HMAC - nothing custom, but requires the provision of a key in order to successfully sign each message.

This is a tactic becoming more and more common, and many infosec researchers consider it ‘out of reach’ to tinker with. That said, it is included in Facebook’s whitehat bug bounty programme [NB - the only thing that is out of scope is blog.instagram.com, so bear that in mind].

So, what’s the skinny?

Well, it’s relatively straightforward to perform all these actions, and only takes a minimal level of familiarity with the tools in play in order to get very good results. What seems to be a bit of a mystery for those trying to get into reverse engineering is the perception of a skills gap (this is the same with hardware hacking - it’s all a matter of perception).

Getting started

Things you’ll need:

  • Patience
  • dex2jar
  • Some extra patience
  • A valid idea of what you want to achieve by hooking the app
  • jd but I use jd-cli
  • Decent coffee machine with freshly ground coffee

First principles

Get it all working. Here are some helpful hints, but a full walkthrough of ‘how to install a thing’ is beyond this kind of walkthrough, so I’ll just leave with these comments:

  • Check your libraries and make sure that they are installed.
  • Make full use of github issue tracking and google searching - chances are, most people have had the same problem before.
  • Understand that most file types are essentially zipped/compressed data; case in point, both .apk and .ipa files are just zips with a specific structure.

First steps recipe

Now here’s how we find and instrument the instagram functions of interest.

  1. download and unzip the .apk file
  2. There will be a .dex file. Run this through dex2jar with the following command line: /home/user/tools/dex2jar/d2j-dex2jar.sh -o ./apk.jar app-file.dex
  3. This works because .dex files are just reconstructed .jar files. Now we have made the conversion, we can decompile the .jar into java code we can analyse.
  4. Decompile the .jar using a command like this: java -jar /home/userone/Tools/jd-cmd/jd-cli.jar ./apk.jar -od ./apk_out/

Now we have the raw code, and associated libraries at the ready for some analysis.

Ok, now what…

Well, doing a quick grep -R '.*[Ss]ignature.*' to find associated signature functions yields the following code snippet:

package com.instagram.strings;

import com.facebook.e.a.a;
import com.facebook.soloader.y;

public class StringBridge
{
  private static boolean a = false;

  static
  {
    try
    {
      y.a("scrambler");
      y.a("strings");
      return;
    }
    catch (Throwable localThrowable)
    {
      a.b(StringBridge.class, "Failed to load native string libraries", localThrowable);
      a = true;
    }
  }

  public static boolean a()
  {
    return a;
  }

  public static native String getInstagramString(String paramString);

  public static native String getSignatureString(byte[] paramArrayOfByte);
}

NB - If you’re not familiar with java and it’s syntax, I suggest you quickly become so before doing this kind of work. You don’t need to be a ninja, but you do need to be able to read code as a significant advantage.

Ok, so what’s interesting here? For me it’s the public static native String getSignatureString() method. The static native bit means it’s calling out to a natively compiled library file (these are written in C/C++ and compiled to run on Android as native code, not inside the Dalvik VM).

Which library files are these? Well, this is given by the loader code just above. We’re looking for the scrambler and strings files. Doing a quick find ./ -name *scramber*' yields a file called libscrambler.so`.

Loading this into IDA Pro (screenie to follow) we find that there is a number of methods. Running this into frida-trace we get a full list (to do this, run something like frida-trace -U -i '*scrambler*' com.instagram.android).

Looking down this list, we see one function that is called occasionally, and looks like our candidate. Yes, you could use IDA/Immunity/GDB/other tools in combination to work out exactly which one, but you could also guess. Both are fine, just that the former methods are faster.

Instrumenting instagram

In case you’ve been lazy (naughty) and not tried this yourself the funcion you want is _ZN9Scrambler9getStringESs - yeah that one.

So you can now instrument with frida as we’ve done previously:

import frida
import sys

session = frida.get_usb_device(1000).attach("com.instagram.android")
script = session.create_script("""
point2me = Module.findExportByName(null, "_ZN9Scrambler9getStringESs");
Interceptor.attach(ptr(point2me), {
   onLeave: function (retval) {
   send("key: " + Memory.readCString(retval));
}
});
""")

def on_message(message, data):
    if message['type'] == 'error':
        print("[!] " + message['stack'])
    elif message['type'] == 'send':
        print("[i] " + message['payload'])
    else:
        print(message)
script.on('message', on_message)
script.load()
sys.stdin.read()

Really?

yeah, really.

It’s that simple?

Yeah.

By my mate went mental trying to do this…

yeaahhh…