Frida as an Alternative to Network Tracing

With network tracing getting harder, Frida is becoming a better way to break into black boxes.

Picture: pixta.jp (used under license)

Recently, a client asked if I could document the network behavior of a suite of mobile applications running on both Android and iOS. I thought at first that this would be straightforward.

The bad news? It was anything but. The good news? I discovered Frida, which let me tackle the problem in a whole other light.

The Black Boxes Are Getting More Opaque

In the good ol’ days of the Web, it was pretty easy to proxy a Web browser through a web debugging proxy like Fiddler or Burp Suite and capture its traffic. And that still works for many situations. However, there are many cases where this either falls short or is impossible.

A major issue is tracing mobile application behavior. To decrypt a mobile app’s encrypted web traffic over HTTPS, you have to get the app you want to trace to sign requests using a security certificate generated by your debugging proxy. On modern devices, this usually means (for Android) rooting your device with something like Magisk or (for iPhone) jailbreaking with an app such as unc0ver.

Even then, however, you still may not be able to get a specific app to use your user certificate. Many apps use a technique known as certificate pinning. As explained by Ray Wenderlich, pinning associates a host with its certificate or public key, which is bundled with the app at compile time. If an app is using pinning, it’ll reject any attempts at using a user certificate.

And that’s not the end of your woes. What if the app you want to trace isn’t even using HTTP/2.0 for all of its communications? More and more apps are adapting HTTP/3, which doesn’t even use TCP as its transport layer — all messages are sent via the UDP-based protocol QUIC. And some apps use other protocols for specialized tasks; for example, Instagram leverages MQTT for real-time notifications.

What is Frida?

Enter Frida. Frida is, in the words of its developer, “GreaseMonkey for native applications.” It provides a framework for hooking native application function and object method calls on a large variety of platforms — including Android and iOS.

This is incredibly powerful. It means (with the right JavaScript code) that you can examine network data in an unencrypted state. If you can find where the data is handled in the app before it’s encrypted for the request and after it’s decrypted from the response, you don’t have to bother with man-in-the-middle SSL tricks at all. You can examine data sent over multiple protocols as well as internal program data.

And that’s not all. You can even alter return results and change a program’s behavior! As a matter of fact, there’s Frida code that can even bypass SSL pinning for most Android apps.

Frida works its magic using several components. The Frida core implements an instrumentation engine, GumJS, that lets you write JavaScript code that hooks a native function or method call. Frida core injects Google’s V8 JavaScript engine into an application’s memory. Using GumJS, Frida provides an API for finding and hooking the entry and exit of any running routine in the app.

To hook calls on mobile applications on Android and iOS, you run a Frida server on the device — a lightweight server that implements Frida core and accepts injection commands over a TCP port.

Finally, the Frida tools, written in Python, let you send injection commands to the Frida server. You can use either the Python command-line utilities shipped with Frida or use the Frida library for Python to write your own injection script. (I’ll talk about why you’d want to do that in a subsequent article.)

Getting Set Up for Frida

Getting started with Frida on a mobile device can take some time due to the need to have a rooted or jailbroken device. Rooting and jailbreaking are themselves immense topics that I won’t cover here. For Android, I recommend obtaining a Google Pixel 3 and following the GadgetHacks.com guide to rooting your Android device with Magisk.

Once you have your device rooted, you can use the Magisk program to download and run a number of utilities that require superuser access to run. One of those is the program MagiskFrida, which runs Frida server on the device whenever it boots. MagiskFrida is also synced with the Frida artifact repository and automatically keeps your Frida server at the latest version.

On iPhone, it’s just as easy: After jailbreaking with unc0ver, you can use the “jailbroken app store” app Cydia to install Frida server.

Verifying Your Frida Setup

Once Frida is running, download the Frida tools to your desktop or laptop and plug in your device. You’ll know everything is working if the following command succeeds:

frida-ps -U

frida-ps will list all processes and their processed IDs running on the device:

The -U signals to frida-ps to connect to Frida server over USB. if you don’t specify it, frida-ps will list the processes on your local computer instead. (Yes, you can trace those too!)

Running Your First Trace Script

Developing JavaScript files for Frida is a whole separate subject that I plan to tackle in a series of articles. For now, let’s keep it simple and run an existing script.

There are a number of great GitHub repositories containing example Frida JavaScript files that are ready to run. There’s also Frida CodeShare, a large library of Frida scripts that can be downloaded and run instantly.

To give you a taste of what’s possible, let’s run the file Android TCP Trace, which will give us a printout of every TCP socket connection that an app makes. To run this script directly from CodeShare, run:

frida -U --codeshare mame82/android-tcp-trace -f com.android.chrome --no-pause

Note that, compared to what’s on Frida CodeShare, I added a couple of arguments here. The -U argument, again, tells Frida to send commands to Frida server over a USB connection. The --no-pause argument doesn’t stop script processing after Frida’s attached and injected itself into the process.

Once you trust the project, you should start to see a printout of all socket connections, their unique IDs, they type, the port they’re using, and the host to which they’re connected.

The One Issue with Frida for Tracing

From here, you can use other scripts on the Internet to trace a large number of standard Java library and Objective-C calls — including network calls. (Check out dweinstein’s awesome-frida for a significant compilation of such resources.)

However, not everything you want to trace may be using standard API library functions and classes. Many larger app makers, for example, roll their own network stacks for better control and performance. I’ll talk in subsequent articles about how you can use the utility frida-trace to figure out which calls you want to trace and how to build a JavaScript program to extract data out of them.

The one downside with this approach is that it can sometimes be pretty time-consuming to build your JavaScript tracer out. It can take a little detective work and a lot of patience, for example, to re-assemble an HTTP request/response pair — a transaction that often takes place across dozens or hundreds of method calls and multiple threads of execution.

That aside, Frida is a powerful tool that changes the game when it comes to application activity and network tracing. In my next article, I’ll dive into how to find relevant functions and method calls and generate your first Frida script.

Teaching technology is my passion. If you need a technical trainer or a technical writer for API docs, white papers, or case studies, contact me!

Owner, kotobits.com. Technical Writer and Trainer specializing in Cloud and DevOps. Tech, programming, technical writing, gadget reviews, and geek humor.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store