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.

Prerequisites

Message Types

Messages received by the Python on_message callback have a type field:

typeWhen generatedAdditional fields
sendJavaScript calls send(value)payload: the JSON-serializable value passed to send
errorUncaught JavaScript exceptiondescription: error message string, lineNumber: int

JavaScript API

send(value)

Sends a message from the target process to the Python controller.

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.

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)

script.post(message)

Sends a message from the Python controller to the JavaScript script.

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