From 39e525c2d58e80c7af604aaffdc932084a16b995 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Mon, 8 Feb 2016 18:51:06 -0600 Subject: [PATCH] Simplify the REPL by using the RPC feature Fixes #66 --- src/frida/repl.py | 123 +++++++++++----------------------------------- 1 file changed, 30 insertions(+), 93 deletions(-) diff --git a/src/frida/repl.py b/src/frida/repl.py index 73846ce..c539b48 100644 --- a/src/frida/repl.py +++ b/src/frida/repl.py @@ -23,10 +23,6 @@ def main(): self._script = None self._seqno = 0 self._ready = threading.Event() - self._next_request_id = 1 - self._response_cond = threading.Condition() - self._response_queue = [] - self._completor_locals = [] self._history = FileHistory(os.path.join(os.path.expanduser('~'), '.frida_history')) self._completer = FridaCompleter(self) self._cli = None @@ -312,52 +308,19 @@ def main(): return prompt_string def _evaluate(self, text): - request_id = -1 - with self._response_cond: - request_id = self._next_request_id - self._next_request_id += 1 - - self._reactor.schedule(lambda: self._script.post_message({ - 'id': request_id, - 'name': '.evaluate', - 'payload': { - 'expression': text - } - })) - - response = None - with self._response_cond: - while True: - for r in self._response_queue: - if r[0]['id'] == request_id: - response = r - break - if response is not None: - self._response_queue.remove(response) - break - if not self._reactor.is_running(): - raise frida.InvalidOperationError("Invalid operation while stopping") - self._response_cond.wait(0.5) - - stanza, data = response - if data is not None: - return ('binary', data) - elif stanza['name'] == '+result': - payload = stanza['payload'] - return (payload['type'], payload.get('value', None)) + result = self._script.exports.evaluate(text) + if is_byte_array(result): + return ('binary', result) + elif isinstance(result, dict): + return ('binary', bytes()) + elif result[0] == 'error': + raise JavaScriptError(result[1]) else: - assert stanza['name'] == '+error' - raise JavaScriptError(stanza['payload']) + return result def _process_message(self, message, data): message_type = message['type'] - if message_type == 'send': - stanza = message['payload'] - response = (stanza, data) - with self._response_cond: - self._response_queue.append(response) - self._response_cond.notify_all() - elif message_type == 'error': + if message_type == 'error': text = message.get('stack', message['description']) self._log('error', text) else: @@ -372,55 +335,23 @@ def main(): return user_script + """\ -(function () { - "use strict"; - - function onEvaluate(requestId, expression) { - try { - var result = (1, eval)(expression); - - if (result instanceof ArrayBuffer) { - send({ - id: requestId, - name: '+result', - payload: { - type: 'binary' - } - }, result); - } else { - var type = (result === null) ? 'null' : typeof result; - send({ - id: requestId, - name: '+result', - payload: { - type: type, - value: result - } - }); - } - } catch (e) { - send({ - id: requestId, - name: '+error', - payload: { - name: e.name, - message: e.message - } - }); +rpc.exports.evaluate = function (expression) { + try { + var result = (1, eval)(expression); + if (result instanceof ArrayBuffer) { + return result; + } else { + var type = (result === null) ? 'null' : typeof result; + return [type, result]; } + } catch (e) { + return ['error', { + name: e.name, + message: e.message, + stack: e.stack + }]; } - - var onStanza = function (stanza) { - switch (stanza.name) { - case '.evaluate': - onEvaluate.call(this, stanza.id, stanza.payload.expression); - break; - } - - recv(onStanza); - }.bind(this); - recv(onStanza); -}).call(this); +}; """ class FridaCompleter(Completer): @@ -527,6 +458,12 @@ def main(): lines.append("%04x %-*s %s\n" % (c, length * 3, hex, printable)) return "".join(lines) + def is_byte_array(value): + if sys.version_info[0] >= 3: + return isinstance(value, bytes) + else: + return isinstance(value, str) + if sys.version_info[0] >= 3: iterbytes = lambda x: iter(x) else: