3
\$\begingroup\$

I'm using Frida to run a script on a process, and I want to wait for it to send the result back to me, as a callback.

My current code looks like this:

def check(target):
    global msg

    script_to_run = '''
    (omitted for brevity)
    '''
    
    # callback to handle the output of the script
    def on_message(message, data):
        global msg
        if message['type'] == 'send':
            msg = message['payload']

    session = device.attach(target.pid)
    
    script = session.create_script(script_to_run)
    script.on('message', on_message)
    script.load()
    
    # Wait for the script to send us a message
    while msg == None:
        pass

    return msg == 'true'

The while loop in particular looks a bit unoptimized, and I'm also worried about how I used that global variable... it will pollute the global scope.

EDIT: As it turns out, I was approaching this in the wrong direction. See my answer below for details.

\$\endgroup\$
3
  • \$\begingroup\$ At the very least, I found I should change the pass for a sleep(0): stackoverflow.com/a/790246/12735366 \$\endgroup\$
    – JJTech
    Sep 4, 2022 at 19:41
  • \$\begingroup\$ This feels too vague to really answer. How is check(target) used? You're transforming an asynchronous function into a synchronous one, which defeats the entire point. \$\endgroup\$
    – Teepeemm
    Sep 4, 2022 at 21:46
  • \$\begingroup\$ Yes, sorry, I realize now that messages aren’t the proper way to go about it, I should use the RPC api. I’ll elaborate both question and answer when I get home \$\endgroup\$
    – JJTech
    Sep 4, 2022 at 21:47

2 Answers 2

4
\$\begingroup\$

So, as it turns out, I was approaching this problem in the wrong direction.

Instead of trying to wait on an asynchronous message, I discovered that Frida has an RPC API.

Here's how I re-wrote my code:

import frida

# --snip--

def check(target):
    session = frida.attach(target.pid)

    script = session.create_script('''
        rpc.exports = {
            check: function () {
                // --snip--
                return true;
            }
        };
    ''')
    script.load()

    return script.exports.check()

Much more succinct, doesn't use globals, and doesn't use a while loop to block.

\$\endgroup\$
1
\$\begingroup\$

I am not familiar with Frida, but looking at the examples found at https://frida.re/docs/messages/ I think you should do your processing in the callback "on_message", instead of passing it to the main thread.

The Frida examples end with sys.stdin.read() which acts like a wait-forever loop. The callback is probably executing in a different thread.

So change your last lines to

# Wait for the script to send us a message
sys.stdin.read()

And change the callback to

def on_message(message, data):
    if message['type'] == 'send':
        print(message['payload'] == 'true')

Don't worry about poluting the global namespace. You are the only one using it :-)

\$\endgroup\$
1
  • \$\begingroup\$ Well, see the problem is that this function is going to be part of a larger program. So, I need to get the result back in the main thread, and block until then. \$\endgroup\$
    – JJTech
    Sep 4, 2022 at 19:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.