Skip to content

Optimizing our Frida setup

When instrumenting applications it is not only important to optimize our instrumentation code for edge cases, but also optimizing the library that we are injecting in our target application.

Frida provides in its config.mk file certain features that might not be needed in our agent, and this would help reduce the memory footprint of the injected agent. Among the features that can be disabled are:

  • V8 Runtime
  • Frida connectivity (TLS and ICE, OpenSSL)
  • Frida Objective-C bridge
  • Swift Bridge
  • Java Bridge

To understand what percentege represents each of the components the following graph illustrates it:

Size of components in frida-agent.so Note: The representation of each component is done as of 03/10/2022 and might change in future releases, use this graph as a rough estimate only.

After seeing what can be easily disabled, it is time to decide what functionality is needed or not in our application. For example, when instrumenting Android applications the Swift and Objective-C runtime are not needed at all. If we have no use for V8 functionality, it is better to simply strip it from our agent and get a lighter version. On the other hand, when instrumenting applications in iOS the Java bridge is likely not needed.

For desktop applications outside of MacOS where the Obj-C brige is useful, all the functionality can be removed unless you want to instrument binaries using the V8 runtime. These optimizations vary on a per-case basis and should be considered in the later stages of instrumentation development.

As a result of these optimizations, when compiling an agent with no V8 runtime and no bridges the result are as follows:

optimized: 9.5M frida-agent.so non-optimized: 24M frida-agent.so

9.5M vs 24M, this is roughly a 61% decrease in the size of the agent (and that's not counting other libraries such as frida-gadget). The biggest decrease of size in the agent is due to disabling the V8 runtime whereas the other features do not have such a big impact (but every byte counts).

The following table shows suggested settings for different target Operative Systems:

Feature Windows Linux MacOS Android iOS
V8 Runtime disabled* *disabled *disabled *disabled *disabled
ObjC bridge disabled disabled enabled disabled enabled
Java Bridge disabled disabled disabled enabled disabled
Swift bridge disabled disabled enabled disabled enabled
Database disabled* disabled* disabled* disabled* disabled*

* in disabled means that you should enable if your use case requires it.

For a more detailed overview of Frida's memory footprint I recommend readying through frida.re/docs/footprint/.

Building an optimized Frida agent

In case that you are interested in building a custom agent by yourself, you can do so by cloning the Frida repository:

git clone --recurse-submodules https://github.com/frida/frida

Once you clone this repository, you will find a file named config.mk inside with the following settings (among others):

FRIDA_V8 ?= enabled
FRIDA_CONNECTIVITY ?= enabled
FRIDA_DATABASE ?= enabled
FRIDA_JAVA_BRIDGE ?= auto
FRIDA_OBJC_BRIDGE ?= auto
FRIDA_SWIFT_BRIDGE ?= auto

These are the default settings. It is possible to disable specific features by setting the enabled flag to disabled. For example, this would disable the Frida V8 Runtime:

FRIDA_V8 ?= disabled
FRIDA_CONNECTIVITY ?= enabled
FRIDA_DATABASE ?= enabled
FRIDA_JAVA_BRIDGE ?= auto
FRIDA_OBJC_BRIDGE ?= auto
FRIDA_SWIFT_BRIDGE ?= auto
And once this change has been made, the agent can be compiled:

make python-linux-x86_64