Messages
Overview
Frida provides a message-passing channel between the JavaScript script running inside the target process and the Python controller on the host. Communication is JSON-based and bidirectional.
- Target → Host:
send()in JavaScript; received viaon('message', callback)in Python - Host → Target:
script.post()in Python; received viarecv()in JavaScript
Prerequisites
- Frida installed (
pip install frida-tools) - A running target process to attach to
- Familiarity with
frida.attach()/session.create_script()
Message Types
Messages received by the Python on_message callback have a type field:
type | When generated | Additional fields |
|---|---|---|
send | JavaScript calls send(value) | payload: the JSON-serializable value passed to send |
error | Uncaught JavaScript exception | description: error message string, lineNumber: int |
JavaScript API
send(value)
Sends a message from the target process to the Python controller.
valuemust be JSON-serializable (object, array, number, string, bool, null).- Calling
send()is non-blocking; execution continues immediately.
1send(1337);
2send({ event: "hit", address: ptr("0x400544").toString() });
recv(type, callback)
Registers a one-shot listener for a message of the given type posted by the Python controller.
type(string): matches thetypefield of the object passed toscript.post().callback(message): invoked with the full message object when a matching message arrives.- One-shot: the callback fires exactly once. To keep receiving, call
recv()again inside the callback. - Returns an operation object with a
.wait()method.
1recv('poke', function onMessage(pokeMessage) {
2 send('pokeBack');
3});
recv(type, callback).wait()
Blocks the current thread inside the target process until the host posts a matching message. Useful for synchronous RPC-style interception patterns.
1const op = recv('input', value => {
2 args[0] = ptr(value.payload);
3});
4op.wait(); // blocks until script.post({'type': 'input', ...}) is called
Python API
script.on('message', callback)
Registers a handler for all messages arriving from the target.
1def on_message(message, data):
2 print(message) # {'type': 'send', 'payload': ...} or {'type': 'error', ...}
3
4script.on('message', on_message)
message: dict with at minimum atypekey.data: raw bytes accompanying the message (usuallyNone).
script.post(message)
Sends a message from the Python controller to the JavaScript script.
message: a dict that must include atypekey matching whatrecv()listens for.
1script.post({"type": "poke"})
2script.post({"type": "input", "payload": "42"})
Examples
1 — Simple send (target → host)
send.py
1import frida, sys
2
3session = frida.attach("hello")
4script = session.create_script("send(1337);")
5
6def on_message(message, data):
7 print(message)
8
9script.on('message', on_message)
10script.load()
11sys.stdin.read()
Output:
1{'type': 'send', 'payload': 1337}
2 — Ping-pong (bidirectional)
pingpong.py
1import frida, sys
2
3session = frida.attach("hello")
4script = session.create_script("""
5 recv('poke', function onMessage(pokeMessage) {
6 send('pokeBack');
7 });
8""")
9
10def on_message(message, data):
11 print(message)
12
13script.on('message', on_message)
14script.load()
15script.post({"type": "poke"})
16sys.stdin.read()
Output:
1{'type': 'send', 'payload': 'pokeBack'}
3 — Blocking recv for synchronous argument modification (RPC pattern)
Intercepts function f at a given address, sends the argument value to Python,
waits for Python to reply with a modified value, then resumes execution with the
new value.
rpc.py (pass the target function’s address as the first CLI argument)
1import frida, sys
2
3session = frida.attach("hello")
4script = session.create_script("""
5Interceptor.attach(ptr("%s"), {
6 onEnter(args) {
7 send(args[0].toString());
8 const op = recv('input', value => {
9 args[0] = ptr(value.payload);
10 });
11 op.wait();
12 }
13});
14""" % int(sys.argv[1], 16))
15
16def on_message(message, data):
17 print(message)
18 val = int(message['payload'], 16)
19 script.post({'type': 'input', 'payload': str(val * 2)})
20
21script.on('message', on_message)
22script.load()
23sys.stdin.read()
1python rpc.py 0x400544
The target process will print doubled values until the Python script exits.
4 — Error message example
If the JavaScript throws an uncaught exception:
1send(a); // 'a' is undefined
Python receives:
1{'type': 'error', 'description': 'ReferenceError: a is not defined', 'lineNumber': 1}
Key Constraints
recv()is one-shot: re-register inside the callback to receive subsequent messages.recv().wait()blocks the target thread — use only inside hooks where stalling is acceptable.- Messages are serialized as JSON; binary data should be passed as hex strings or base64.
send()with non-JSON-serializable values will throw an error in the target script.