Quickstart
Prerequisites
- Python with
pipavailable - Target process already running (example uses macOS Twitter app)
- Platform: works on macOS, Linux, Windows, iOS, Android (this example targets macOS desktop)
Installation
1pip install frida-tools
This installs frida-trace, frida, frida-ps, frida-ls-devices, and related CLI tools.
Workflow: Trace Native Functions with frida-trace
Step 1 — Start tracing with glob patterns
1frida-trace -i "recv*" -i "read*" twitter
What happens:
- Frida injects into the
twitterprocess - Enumerates all loaded shared libraries
- Hooks every exported function whose name matches
recv*orread* - Auto-generates JavaScript handler stubs in the current working directory
- Prints timestamps and function names as calls occur
Example output:
recv: Auto-generated handler: …/recv.js
# (snip)
recvfrom: Auto-generated handler: …/recvfrom.js
Started tracing 21 functions. Press Ctrl+C to stop.
39 ms recv()
112 ms recvfrom()
128 ms recvfrom()
129 ms recvfrom()
Step 2 — Inspect the auto-generated handler
Each matched function gets a .js stub. Example for recvfrom:
1{
2 /**
3 * Called synchronously before recvfrom executes.
4 *
5 * @this {object} - Per-invocation state storage (use instead of
6 * outer state to share data between onEnter/onLeave)
7 * @param {function} log - Call log("string") to print output to the user
8 * @param {array} args - Function arguments as NativePointer objects.
9 * Read with args[N].readUtf8String(), args[N].toInt32(), etc.
10 * Modify by assigning a new NativePointer to args[N].
11 * @param {object} state - Shared state across all calls (not per-invocation)
12 */
13 onEnter(log, args, state) {
14 log("recvfrom()");
15 },
16
17 /**
18 * Called synchronously just before recvfrom returns.
19 *
20 * @this {object} - Per-invocation state set in onEnter
21 * @param {function} log - Same log function as onEnter
22 * @param {NativePointer} retval - Return value as NativePointer
23 * @param {object} state - Shared state across all calls
24 */
25 onLeave(log, retval, state) {
26 }
27}
Key behaviors:
- Scripts are hot-reloaded on save — no need to restart
frida-trace - Only one JS function executes at a time (no race conditions)
- Use
this(notstate) to pass data fromonEntertoonLeavefor the same call
Step 3 — Customize the handler to inspect arguments
Replace the log() line in onEnter with argument inspection:
1onEnter(log, args, state) {
2 log("recvfrom(socket=" + args[0].toInt32()
3 + ", buffer=" + args[1]
4 + ", length=" + args[2].toInt32()
5 + ", flags=" + args[3]
6 + ", address=" + args[4]
7 + ", address_len=" + args[5].readPointer().toInt32()
8 + ")");
9},
recvfrom signature reference:
args index | Parameter | Type | Read method |
|---|---|---|---|
| 0 | sockfd | int | args[0].toInt32() |
| 1 | buf | void * | args[1] (pointer) |
| 2 | len | size_t | args[2].toInt32() |
| 3 | flags | int | args[3] (pointer/int) |
| 4 | src_addr | struct sockaddr * | args[4] (pointer) |
| 5 | addrlen | socklen_t * | args[5].readPointer().toInt32() |
Save the file. frida-trace reloads it automatically.
Step 4 — Trigger activity and observe output
Perform a network action in the app. Example output:
8098 ms recvfrom(socket=70,
buffer=0x32cc018, length=65536,
flags=0x0,
address=0xb0420bd8, address_len=16)
NativePointer Read Methods (quick reference)
| Method | Returns |
|---|---|
.toInt32() | signed 32-bit integer |
.toUInt32() | unsigned 32-bit integer |
.readPointer() | NativePointer at this address |
.readUtf8String() | UTF-8 string at this address |
.readByteArray(n) | ArrayBuffer of n bytes |
Next Steps
- Build custom tools with the Frida Python API —
frida-traceitself is built on top of it - Source:
frida_tools/tracer.py - Full JavaScript API reference: https://frida.re/docs/javascript-api/