Home Security Tools Frida – Dynamic Instrumentation Toolkit for Developers, Reverse-Engineers, and Security Researchers

Frida – Dynamic Instrumentation Toolkit for Developers, Reverse-Engineers, and Security Researchers

by ethhack
Frida - Dynamic Instrumentation Toolkit for Developers, Reverse-Engineers, and Security Researchers

Frida is a dynamic instrumentation toolkit for developers, reverse-engineers, and security researchers.


It is

  • Scriptable: It lets you inject your own scripts into black box processes. Hook any function, spy on crypto APIs or trace private application code, no source code needed. Edit, hit save, and instantly see the results. All without compilation steps or program restarts. 
  • Portable: Works on Windows, macOS, GNU/Linux, iOS, Android, and QNX. Install the Node.js bindings from npm, grab a Python package from PyPI, or use Frida through its Swift bindings, .NET bindings, Qt/Qml bindings, or C API. 
  • Free: Frida is a free software.
  • Battle-tested: It is very popular among security researchers and pentesters.

Frida also provides you some simple tools built on top of the Frida API. These can be used as-is, tweaked to your needs, or serve as examples of how to use the API.

Why You Need Frida In Your Arsenal (Here are some use-cases):

  • There’s this new hot app everybody’s so excited about, but it’s only available for iOS and you’d love to interop with it. You realize it’s relying on encrypted network protocols and tools like Wireshark just won’t cut it. You pick up Frida and use it for API tracing.
  • You’re building a desktop app which has been deployed at a customer’s site. There’s a problem but the built-in logging code just isn’t enough. You need to send your customer a custom build with lots of expensive logging code. Then you realize you could just use Frida and build an application- specific tool that will add all the diagnostics you need, and in just a few lines of Python. No need to send the customer a new custom build – you just send the tool which will work on many versions of your app.
  • You’d like to build a Wireshark on steroids with support for sniffing encrypted protocols. It could even manipulate function calls to fake network conditions that would otherwise require you to set up a test lab.
  • Your in-house app could use some black-box tests without polluting your production code with logic only required for exotic testing.

Tools:

  • Frida CLI: Frida CLI is a REPL interface that aims to emulate a lot of the nice features of IPython (or Cycript), which tries to get you closer to your code for rapid prototyping and easy debugging.
# Connect Frida to an iPad over USB and start debugging Safari
$ frida -U Safari
    _____
   (_____)
    |   |    Frida 4.0.0 - A world-class dynamic
    |   |                  instrumentation framework
    |`-'|
    |   |    Commands:
    |   |        help      -> Displays the help system
    |   |        object?   -> Display information about 'object'
    |   |        exit/quit -> Exit
    |   |
    |   |    More info at http://www.frida.re/docs/home/
    `._.'

[USB::iPad 4::Safari]->

An example session:

# Connect Frida to a locally-running Calculator.app
$ frida Calculator
    _____
   (_____)
    |   |    Frida 4.0.0 - A world-class dynamic
    |   |                  instrumentation framework
    |`-'|
    |   |    Commands:
    |   |        help      -> Displays the help system
    |   |        object?   -> Display information about 'object'
    |   |        exit/quit -> Exit
    |   |
    |   |    More info at http://www.frida.re/docs/home/
    `._.'

# Look at the local variables/context
[Local::ProcName::Calculator]-> 
Backtracer           Process
CpuContext           Proxy
Dalvik               Socket
DebugSymbol          Stalker
File                 Thread
Frida                WeakRef
Instruction          clearInterval
Interceptor          clearTimeout
Memory               console
MemoryAccessMonitor  gc
Module               ptr
NULL                 recv
NativeCallback       send
NativeFunction       setInterval
NativePointer        setTimeout
ObjC
# Look at things exposed through the ObjC interface
[Local::ProcName::Calculator]-> ObjC.
Object            implement         selector
available         mainQueue         selectorAsString
classes           schedule
# List the first 10 classes (there are a lot of them!)
[Local::...::Calculator]-> Object.keys(ObjC.classes).slice(0, 10)
[
    "NSDrawer",
    "GEOPDETAFilter",
    "NSDeserializer",
    "CBMutableCharacteristic",
    "NSOrthographyCheckingResult",
    "DDVariable",
    "GEOVoltaireLocationShiftProvider",
    "LSDocumentProxy",
    "NSPreferencesModule",
    "CIQRCodeGenerator"
]



Loading a script:

# Connect Frida to a locally-running Calculator.app and load calc.js
$ frida Calculator -l calc.js
    _____
   (_____)
    |   |    Frida 4.0.0 - A world-class dynamic
    |   |                  instrumentation framework
    |`-'|
    |   |    Commands:
    |   |        help      -> Displays the help system
    |   |        object?   -> Display information about 'object'
    |   |        exit/quit -> Exit
    |   |
    |   |    More info at http://www.frida.re/docs/home/
    `._.'

# The code in calc.js has now been loaded and executed
[Local::ProcName::Calculator]->
# Reload it from file at any time
[Local::ProcName::Calculator]-> %reload
[Local::ProcName::Calculator]->

Enable the Node.js compatible debugger:

# Connect Frida to a locally-running Calculator.app
# and load calc.js with the debugger enabled
$ frida Calculator -l calc.js --debug
    _____
   (_____)
    |   |    Frida 4.0.0 - A world-class dynamic
    |   |                  instrumentation framework
    |`-'|
    |   |    Commands:
    |   |        help      -> Displays the help system
    |   |        object?   -> Display information about 'object'
    |   |        exit/quit -> Exit
    |   |
    |   |    More info at http://www.frida.re/docs/home/
    `._.'

Debugger listening on port 5858
# We can now run node-inspector and start debugging calc.js
[Local::ProcName::Calculator]->

  • frida-ps: This is a command-line tool for listing processes, which is very useful when interacting with a remote system. (You can acquire device id from frida-ls-devices tool)
# Connect Frida to an iPad over USB and list running processes
$ frida-ps -U

# List running applications
$ frida-ps -Ua

# List installed applications
$ frida-ps -Uai

# Connect Frida to the specific device
$ frida-ps -D 0216027d1d6d3a03

  • frida-trace: frida-trace is a tool for dynamically tracing function calls.
# Trace recv* and send* APIs in Safari, insert library names
# in logging
$ frida-trace --decorate -i "recv*" -i "send*" Safari

# Trace ObjC method calls in Safari
$ frida-trace -m "-[NSView drawRect:]" Safari

# Launch SnapChat on your iPhone and trace crypto API calls
$ frida-trace -U -f com.toyopagroup.picaboo -I "libcommonCrypto*"

# Trace all JNI functions in Samsung FaceService app on Android
$ frida-trace -U -i "Java_*" com.samsung.faceservice

# Trace a Windows process's calls to "mem*" functions in msvcrt.dll
$ frida-trace -p 1372 -i "msvcrt.dll!*mem*"

# Trace all functions matching "*open*" in the process except
# in msvcrt.dll
$ frida-trace -p 1372 -i "*open*" -x "msvcrt.dll!*open*"

# Trace an unexported function in libjpeg.so
$ frida-trace -p 1372 -a "libjpeg.so!0x4793c"

Full List of Options:
--version             show program's version number and exit
-h, --help            show this help message and exit
-D ID, --device=ID    connect to device with the given ID
-U, --usb             connect to USB device
-R, --remote          connect to remote frida-server
-H HOST, --host=HOST  connect to remote frida-server on HOST
-f FILE, --file=FILE  spawn FILE
-F, --attach-frontmost
                      attach to frontmost application
-n NAME, --attach-name=NAME
                      attach to NAME
-p PID, --attach-pid=PID
                      attach to PID
--stdio=inherit|pipe  stdio behavior when spawning (defaults to "inherit")
--runtime=duk|v8      script runtime to use (defaults to "duk")
--debug               enable the Node.js compatible script debugger
-I MODULE, --include-module=MODULE
                      include MODULE
-X MODULE, --exclude-module=MODULE
                      exclude MODULE
-i FUNCTION, --include=FUNCTION
                      include FUNCTION
-x FUNCTION, --exclude=FUNCTION
                      exclude FUNCTION
-a MODULE!OFFSET, --add=MODULE!OFFSET
                      add MODULE!OFFSET
-T, --include-imports
                      include program's imports
-t MODULE, --include-module-imports=MODULE
                      include MODULE imports
-m OBJC_METHOD, --include-objc-method=OBJC_METHOD
                      include OBJC_METHOD
-M OBJC_METHOD, --exclude-objc-method=OBJC_METHOD
                      exclude OBJC_METHOD
-s DEBUG_SYMBOL, --include-debug-symbol=DEBUG_SYMBOL
                      include DEBUG_SYMBOL
-q, --quiet           do not format output messages
-d, --decorate        Add module name to generated onEnter log statement
-o OUTPUT, --output=OUTPUT
                      dump messages to file

-U, –usb: connect to USB device:
This option tells frida-trace to perform tracing on a remote device connected via the host machine’s USB connection. Example: You want to trace an application running on an Android device from your host Windows machine. If you specify -U / –usb, frida-trace will perform the necessary work to transfer all data to and from the remote device and trace accordingly.

Note: When tracing a remote device, remember to copy the platform-appropriate frida-server binary to the remote device. Once copied, be sure to run the frida-server binary before beginning the tracing session. For example, to trace a remote Android application, you would copy the ‘frida-server-12.8.0-android-arm’ binary to the Android’s /data/local/tmp folder. Using adb shell, you would run the server in the background (e.g. frida-server-12.8.0-android-arm &).

-I, -X: include/exclude module:
These options allow you to include or exclude all functions in a particular module (e.g., *.so, *.dll) in one, single option. The option expects a filename glob for matching one or more modules. Any module that matches the glob pattern will be either included or excluded in its entirety.

frida-trace will generate a JavaScript handler file for each function matched by the -I option.

To exclude specific functions after including an entire module, see the -i option.

-i, -x: include/exclude function (glob-based):
These options enable you to include or exclude matching functions according to your needs. This is a flexible option, allowing a granularity ranging from all functions in all modules down to a single function in a specific module.

frida-trace will generate a JavaScript handler file for each function matched by the -i option.

The -i / -x options differ syntactically from their uppercase counterparts in that they accept any of the following forms (MODULE and FUNCTION are both glob patterns):

– MODULE!FUNCTION
– FUNCTION
– !FUNCTION
– MODULE!

Here are some examples and their descriptions:

-i "msvcrt.dll!*cpy*"	Matches all functions with 'cpy' in its name, ONLY in msvcrt.dll
-i "*free*"	        Matches all functions with 'free' in its name in ALL modules
-i "!*free*"	        Identical to -i "*free*"
-i "gdi32.dll!"	        Trace all functions in gdi32.dll

frida-trace has an internal concept of a “working set”, i.e., a set of “module:function” pairs whose handlers will be traced at runtime. The contents of the working set can be changed by an include / exclude command line option (-I / -X / -i / -x).

It is important to understand that the order of the include / exclude options is important. Each such option works on the current state of the working set, and different orderings of options can lead to different results. In other words, the include/exclude options are procedural (i.e., order counts) rather than simply declarative.

For example, suppose we want to trace all “str*” and “mem*” functions in all modules in a running process. In our example, these functions are found in three modules: ucrtbase.dll, ntdll.dll, and msvcrt.dll. To reduce the noise, however, we do not want to trace any functions found in the msvcrt.dll module.

We will describe three different option orders on the command line and show that they produce different results.

  • -i “str*” -i “mem*” -X “msvcrt.dll”
    • ‘-i “str*”‘ matches 80 functions in 3 modules, working set has 80 entries
    • ‘-i “mem*”‘ matches 18 functions in 3 modules, working set has 98 entries
    • ‘-X “msvcrt.dll”‘ removes the 28 “str” and 6 “mem” functions originating in msvcrt.dll, final working set has 64 entries.
  • -i “str*” -X “msvcrt.dll” -i “mem*”
    • ‘-i “str*”‘ matches 80 functions in 3 modules, working set has 80 entries
    • ‘-X “msvcrt.dll”‘ removes the 28 “str” functions originating in msvcrt.dll, working set has 52 entries.
    • ‘-i “mem*”‘ matches 18 functions in 3 modules including msvcrt.dll, final working set has 70 entries
  • -X “msvcrt.dll” -i “str*” -i “mem*”
    • ‘-X “msvcrt.dll”‘ tries to remove the 28 “str” and 6 “mem” functions originating in msvcrt.dll. Since the working set is empty, there is nothing to remove, working set has 0 entries.
    • ‘-i “str*”‘ matches 80 functions in 3 modules, working set has 80 entries
    • ‘-i “mem*”‘ matches 18 functions in 3 modules, final working set has 98 entries

-a: include function (offset-based):

This option enables tracing functions whose names are not exported by their modules (e.g., a static C/C++ function). This should not prevent you from tracing such functions, so long as you know that absolute offset of the function’s entry point.

Example: -a “libjpeg.so!0x4793c”

The option value provides both the full name of the module and the hex offset of the function entry point within the module.

frida-trace will generate a JavaScript handler file for each function matched by the -a option.

-d, –decorate: add module name to log tracing:

The –decorate option is relevant when frida-trace auto-generates JavaScript handler scripts. By default, a handler’s onEnter function looks like this:

onEnter: function (log, args, state) {
  log('memcpy()');
},

The drawback is that, if the same function name exists in multiple modules, it will be difficult to differentiate between function traces. The –decorate function instructs frida-trace to insert the module name in the default onEnter trace instruction:

onEnter: function (log, args, state) {
  log('memcpy() [msvcrt.dll]');
},

  • frida-discover: frida-discover is a tool for discovering internal functions in a program, which can then be traced by using frida-trace.
  • frida-ls-devices: This is a command-line tool for listing attached devices, which is very useful when interacting with multiple devices.
# Connect Frida to an iPad over USB and list running processes
$ frida-ls-devices

# example output

Id                                        Type    Name            
----------------------------------------  ------  ----------------
local                                     local   Local System    
0216027d1d6d3a03                          tether  Samsung SM-G920F
1d07b5f6a7a72552aca8ab0e6b706f3f3958f63e  tether  iOS Device      
tcp                                       remote  Local TCP  
  • frida-kill: This is a command-line tool for killing processes. You can acquire PIDs from frida-ps tool.
$ frida-kill -D 
# List active applications
$ frida-ps -D 1d07b5f6a7a72552aca8ab0e6b706f3f3958f63e  -a

PID  Name                Identifier                                           
----  ------------------  -----------------------------------------------------
4433  Camera              com.apple.camera                                     
4001  Cydia               com.saurik.Cydia                                     
4997  Filza               com.tigisoftware.Filza                               
4130  IPA Installer       com.slugrail.ipainstaller                            
3992  Mail                com.apple.mobilemail                                 
4888  Maps                com.apple.Maps                                       
6494  Messages            com.apple.MobileSMS                                                          
5029 Safari              com.apple.mobilesafari                               
4121  Settings            com.apple.Preferences  

# Connect Frida to the device and kill running process
$ frida-kill -D 1d07b5f6a7a72552aca8ab0e6b706f3f3958f63e 5029

# Check if process has been killed
$ frida-ps -D 1d07b5f6a7a72552aca8ab0e6b706f3f3958f63e  -a

PID  Name                Identifier                                           
----  ------------------  -----------------------------------------------------
4433  Camera              com.apple.camera                                     
4001  Cydia               com.saurik.Cydia                                     
4997  Filza               com.tigisoftware.Filza                               
4130  IPA Installer       com.slugrail.ipainstaller                            
3992  Mail                com.apple.mobilemail                                 
4888  Maps                com.apple.Maps                                       
6494  Messages            com.apple.MobileSMS                                                          
4121  Settings            com.apple.Preferences

How To Install Frida

Requirements for Frida’s CLI tools:
  • Python – latest 3.x is highly recommended
  • Windows, macOS, or GNU/Linux

Install with pip:

The best way to install Frida’s CLI tools is via PyPI:

$ pip install frida-tools

Install manually:
Download binaries and install it.

Testing Your Installation

Start a process we can inject into:

$ cat

Just let it sit and wait for input. On Windows you might want to use notepad.exe.

Note that this example won’t work on macOS El Capitan and later, as it rejects such attempts for system binaries. However, if you copy the cat binary to e.g., /tmp/cat then run that instead the example should work:

$ cp /bin/cat /tmp/cat
$ /tmp/cat
In another terminal, make a file example.py with the following contents:
import frida

def on_message(message, data):
    print("[on_message] message:", message, "data:", data)

session = frida.attach("cat")

script = session.create_script("""
rpc.exports.enumerateModules = function () {
  return Process.enumerateModules();
};
""")
script.on("message", on_message)
script.load()

print([m["name"] for m in script.exports.enumerate_modules()])

If you are on GNU/Linux, issue:

$ sudo sysctl kernel.yama.ptrace_scope=0

to enable ptracing non-child processes.

At this point, we are ready to take Frida for a spin! Run the example.py script and watch the magic:

$ python example.py

The output should be something similar to this (depending on your platform and library versions):

[u'cat', …, u'ld-2.15.so']

Modes of Operation

Frida provides dynamic instrumentation through its powerful instrumentation core Gum, which is written in C. Because such instrumentation logic is prone to change, you usually want to write it in a scripting language so you get a short feedback loop while developing and maintaining it. This is where GumJS comes into play. With just a few lines of C you can run a piece of JavaScript inside a runtime that has full access to Gum’s APIs, allowing you to hook functions, enumerate loaded libraries, their imported and exported functions, read and write memory, scan memory for patterns, etc.

Most of the time, however, you want to spawn an existing program, attach to a running program, or hijack one as it’s being spawned, and then run your instrumentation logic inside of it. As this is such a common way to use Frida, it is what most of our documentation focuses on. This functionality is provided by frida-core, which acts as a logistics layer that packages up GumJS into a shared library that it injects into existing software, and provides a two-way communication channel for talking to your scripts, if needed, and later unload them. Beside this core functionality, frida-core also lets you enumerate installed apps, running processes, and connected devices. The connected devices are typically iOS and Android devices where frida-server is running. That component is essentially just a daemon that exposes frida-core over TCP, listening on localhost:27042 by default.

It is sometimes not possible to use Frida in Injected mode, for example on jailed iOS and Android systems. For such cases we provide you with frida-gadget, a shared library that you’re supposed to embed inside the program that you want to instrument. By simply loading the library it will allow you to interact with it remotely, using existing Frida-based tools like frida-trace. It also supports a fully autonomous approach where it can run scripts off the filesystem without any outside communication.



Source link

Related Articles

Leave a Comment