diff --git a/src/Makefile.am b/src/Makefile.am index eafed83..d2966dd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,6 +8,10 @@ do_substitution = sed -e 's,[@]pythondir[@],$(pythondir),g' \ -e 's,[@]PACKAGE[@],$(PACKAGE),g' \ -e 's,[@]VERSION[@],$(VERSION),g' +frida-discover: frida-discover.in Makefile + $(do_substitution) < $(srcdir)/frida-discover.in > $@ + chmod +x $@ + frida-trace: frida-trace.in Makefile $(do_substitution) < $(srcdir)/frida-trace.in > $@ chmod +x $@ diff --git a/src/frida-discover.in b/src/frida-discover.in new file mode 100644 index 0000000..648e71a --- /dev/null +++ b/src/frida-discover.in @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +import sys +sys.path.insert(1, '@pythondir@') + +import frida +import frida.discoverer + +if __name__ == '__main__': + frida.discoverer.main() diff --git a/src/frida/discoverer.py b/src/frida/discoverer.py new file mode 100644 index 0000000..0d66b34 --- /dev/null +++ b/src/frida/discoverer.py @@ -0,0 +1,95 @@ +class Discoverer(object): + def __init__(self): + self._script = None + + def start(self, process): + def on_message(message, data): + print message, data + source = self._create_discover_script() + self._script = process._session.create_script(source) + self._script.on("message", on_message) + self._script.load() + + def stop(self): + if self._script is not None: + try: + self._script.unload() + except: + pass + self._script = None + + def _create_discover_script(self): + return """ +var pending = []; +var active = []; +Process.enumerateThreads({ + onMatch: function (thread) { + pending.push(thread); + }, + onComplete: function () { + var currentThreadId = Process.getCurrentThreadId(); + pending = pending.filter(function (thread) { + return thread.id !== currentThreadId; + }); + var processNext = function processNext() { + if (pending.length === 0) { + return; + } + active.forEach(function (thread) { + send("unfollow(" + thread.id + ")"); + Stalker.unfollow(thread.id); + }); + active = pending.splice(0, 4); + active.forEach(function (thread) { + send("follow(" + thread.id + ")"); + Stalker.follow(thread.id, { + events: { call: true }, + onCallSummary: function (summary) { + send("summary from " + thread.id); + } + }); + }); + setTimeout(processNext, 2000); + }; + setTimeout(processNext, 0); + } +}); +""" + + +def main(): + import frida + from optparse import OptionParser + import sys + + usage = "usage: %prog [options] process-name-or-id" + parser = OptionParser(usage=usage) + (options, args) = parser.parse_args() + if len(args) != 1: + parser.error("process name or id must be specified") + + try: + target = int(args[0]) + except: + target = args[0] + try: + process = frida.attach(target) + except Exception, e: + print >> sys.stderr, "Failed to attach: %s" % e + sys.exit(1) + + d = Discoverer() + d.start(process) + print "Discovery started" + print "Press ENTER to stop" + raw_input() + print "Stopping..." + d.stop() + process.detach() + frida.shutdown() + + sys.exit(0) + + +if __name__ == '__main__': + main() diff --git a/src/setup.py b/src/setup.py index a587699..60543ba 100755 --- a/src/setup.py +++ b/src/setup.py @@ -33,6 +33,7 @@ setup( author_email="ole.andre.ravnas@tillitech.com", entry_points={ 'console_scripts': [ + 'frida-discover = frida.discoverer:main', 'frida-trace = frida.tracer:main' ] },