消息传递
本页为社区译文;如有疑义,请以英文原文为准。
英文原文
本教程介绍如何向目标进程发送消息,以及如何从目标进程接收消息。
设置实验环境
创建文件 hello.c:
#include <stdio.h>
#include <unistd.h>
void
f (int n)
{
printf ("Number: %d\n", n);
}
int
main (int argc,
char * argv[])
{
int i = 0;
printf ("f() is at %p\n", f);
while (1)
{
f (i++);
sleep (1);
}
}使用以下命令编译:
$ gcc -Wall hello.c -o hello启动程序,并记下 f() 的地址(以下示例中为 0x400544):
f() is at 0x400544
Number: 0
Number: 1
Number: 2
…从目标进程发送消息
以下脚本演示如何将消息发回 Python 进程。可以发送任何能够序列化为 JSON 的 JavaScript 值。
创建文件 send.py,内容如下:
import frida
import sys
session = frida.attach("hello")
script = session.create_script("send(1337);")
def on_message(message, data):
print(message)
script.on('message', on_message)
script.load()
sys.stdin.read()运行此脚本时:
$ python send.py它应打印以下消息:
{'type': 'send', 'payload': 1337}这表示 JavaScript 代码 send(1337) 已在 hello 进程内部执行。按 Ctrl-D 终止脚本。
处理 JavaScript 运行时错误
如果 JavaScript 脚本抛出未捕获的异常,该异常会从目标进程传播到 Python 脚本。如果将 send(1337) 替换为 send(a)(一个未定义变量),Python 将收到以下消息:
{'type': 'error', 'description': 'ReferenceError: a is not defined', 'lineNumber': 1}请注意 type 字段(error 与 send)。
在目标进程中接收消息
可以从 Python 脚本向 JavaScript 脚本发送消息。创建文件 pingpong.py:
import frida
import sys
session = frida.attach("hello")
script = session.create_script("""
recv('poke', function onMessage(pokeMessage) { send('pokeBack'); });
""")
def on_message(message, data):
print(message)
script.on('message', on_message)
script.load()
script.post({"type": "poke"})
sys.stdin.read()运行脚本:
$ python pingpong.py会产生以下输出:
{'type': 'send', 'payload': 'pokeBack'}recv() 的工作机制
recv() 方法本身是异步(非阻塞)的。注册的回调(onMessage)只会接收一条消息。要接收下一条消息,必须使用 recv() 重新注册回调。
在目标进程中阻塞接收
可以在 JavaScript 脚本内部等待消息到达(阻塞接收)。创建脚本 rpc.py:
import frida
import sys
session = frida.attach("hello")
script = session.create_script("""
Interceptor.attach(ptr("%s"), {
onEnter(args) {
send(args[0].toString());
const op = recv('input', value => {
args[0] = ptr(value.payload);
});
op.wait();
}
});
""" % int(sys.argv[1], 16))
def on_message(message, data):
print(message)
val = int(message['payload'], 16)
script.post({'type': 'input', 'payload': str(val * 2)})
script.on('message', on_message)
script.load()
sys.stdin.read()程序 hello 应处于运行状态,并且应记下它启动时打印的地址(例如 0x400544)。运行:
$ python rpc.py 0x400544然后观察运行 hello 的终端中发生的变化:
Number: 3
Number: 8
Number: 10
Number: 12
Number: 14
Number: 16
Number: 18
Number: 20
Number: 22
Number: 24
Number: 26
Number: 14hello 程序应开始输出“加倍”后的值,直到停止 Python 脚本(Ctrl-D)。