I'm experimenting with Frida, and some of the simplest examples I've found do not work as expected on macOS. Here is an example.
Consider this C code:
#include <stdio.h>
#include <unistd.h>
void print_hello(int n, char a, float f) {
printf("hello %d %c %f\n", n, a, f);
}
int main(int argc, char *argv[]) {
while (1) {
print_hello(10, 'a', 3.141f);
sleep(1);
}
return 0;
}
Obvious what it does.
Now here's a Frida python launcher:
#!/usr/bin/env python3
import frida
def on_message(message, data):
print(message)
pid = frida.spawn('./a.out')
session = frida.attach(pid)
script = session.create_script("""
Interceptor.attach(Module.findExportByName(null, 'print_hello'), {
onEnter(args) {
send('enter')
},
onLeave(retval) {
send('leave')
}
})
""")
script.on('message', on_message)
script.load()
frida.resume(pid)
One would expect this to print enter/leave every second. Instead, here are some of the results I get:
% ./trace.py
hello 10 a 3.141000
{'type': 'send', 'payload': 'enter'}
hello 10 a 3.141000
hello 10 a 3.141000
hello 10 a 3.141000
hello 10 a 3.141000
hello 10 a 3.141000
hello 10 a 3.141000
hello 10 a 3.141000
hello 10 a 3.141000
hello 10 a 3.141000
^C
% ./trace.py
hello 10 a 3.141000
{'type': 'send', 'payload': 'enter'}
hello 10 a 3.141000
hello 10 a 3.141000
hello 10 a 3.141000
^C
% ./trace.py
hello 10 a 3.141000
{'type': 'send', 'payload': 'enter'}
hello 10 a 3.141000
^C
% ./trace.py
hello 10 a 3.141000
{'type': 'send', 'payload': 'enter'}
{'type': 'send', 'payload': 'leave'}
% ./trace.py
hello 10 a 3.141000
{'type': 'send', 'payload': 'enter'}
hello 10 a 3.141000
hello 10 a 3.141000
^C
% ./trace.py
hello 10 a 3.141000
{'type': 'send', 'payload': 'enter'}
hello 10 a 3.141000
hello 10 a 3.141000
hello 10 a 3.141000
^C
On that third invocation it exited w/o ^C.
There's nothing keeping trace.py
alive, so the instrumentation is reverted once it reaches the end of the script – as part of the Python interpreter shutting down. You could add a call to sys.stdin.read()
at the end of the script to avoid this.