mirror of
https://github.com/frida/frida-python
synced 2026-06-08 14:16:17 +00:00
Add spawn support to ConsoleApplication
This commit is contained in:
+70
-13
@@ -2,6 +2,7 @@
|
||||
|
||||
import collections
|
||||
from optparse import OptionParser
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
@@ -27,6 +28,17 @@ class ConsoleApplication(object):
|
||||
action='store_const', const='tether', dest="device_type", default='local')
|
||||
parser.add_option("-R", "--remote", help="connect to remote device",
|
||||
action='store_const', const='remote', dest="device_type", default='local')
|
||||
if self._needs_target():
|
||||
def store_target(option, opt_str, target_value, parser, target_type, *args, **kwargs):
|
||||
if target_type == 'file':
|
||||
target_value = [target_value]
|
||||
setattr(parser.values, 'target', (target_type, target_value))
|
||||
parser.add_option("-f", "--file", help="spawn FILE", metavar="FILE",
|
||||
type='string', action='callback', callback=store_target, callback_args=('file',))
|
||||
parser.add_option("-n", "--attach-name", help="attach to NAME", metavar="NAME",
|
||||
type='string', action='callback', callback=store_target, callback_args=('name',))
|
||||
parser.add_option("-p", "--attach-pid", help="attach to PID", metavar="PID",
|
||||
type='int', action='callback', callback=store_target, callback_args=('pid',))
|
||||
self._add_options(parser)
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
@@ -34,25 +46,35 @@ class ConsoleApplication(object):
|
||||
self._device_type = options.device_type
|
||||
self._device = None
|
||||
self._schedule_on_device_lost = lambda: self._reactor.schedule(self._on_device_lost)
|
||||
self._target = None
|
||||
self._spawned_pid = None
|
||||
self._process = None
|
||||
self._schedule_on_process_detached = lambda: self._reactor.schedule(self._on_process_detached)
|
||||
self._started = False
|
||||
self._resumed = False
|
||||
self._reactor = Reactor(run_until_return)
|
||||
self._exit_status = None
|
||||
self._status_updated = False
|
||||
|
||||
self._initialize(parser, options, args)
|
||||
|
||||
target_specifier = self._target_specifier(parser, options, args)
|
||||
if target_specifier is not None:
|
||||
try:
|
||||
self._target = int(target_specifier)
|
||||
except:
|
||||
self._target = target_specifier
|
||||
if self._needs_target():
|
||||
target = getattr(options, 'target', None)
|
||||
if target is None:
|
||||
if len(args) < 1:
|
||||
parser.error("target file, process name or pid must be specified")
|
||||
target = infer_target(args[0])
|
||||
args.pop(0)
|
||||
target = expand_target(target)
|
||||
if target[0] == 'file':
|
||||
argv = target[1]
|
||||
if not os.path.isfile(argv[0]):
|
||||
parser.error("%s: file not found" % argv[0])
|
||||
argv.extend(args)
|
||||
args = []
|
||||
self._target = target
|
||||
else:
|
||||
self._target = None
|
||||
|
||||
self._initialize(parser, options, args)
|
||||
|
||||
def run(self):
|
||||
mgr = frida.get_device_manager()
|
||||
on_devices_changed = lambda: self._reactor.schedule(self._try_start)
|
||||
@@ -66,6 +88,8 @@ class ConsoleApplication(object):
|
||||
self._process.off('detached', self._schedule_on_process_detached)
|
||||
self._process.detach()
|
||||
self._process = None
|
||||
if self._spawned_pid is not None:
|
||||
self._device.kill(self._spawned_pid)
|
||||
if self._device is not None:
|
||||
self._device.off('lost', self._schedule_on_device_lost)
|
||||
mgr.off('changed', on_devices_changed)
|
||||
@@ -78,8 +102,8 @@ class ConsoleApplication(object):
|
||||
def _initialize(self, parser, options, args):
|
||||
pass
|
||||
|
||||
def _target_specifier(self, parser, options, args):
|
||||
return None
|
||||
def _needs_target(self):
|
||||
return False
|
||||
|
||||
def _start(self):
|
||||
pass
|
||||
@@ -87,6 +111,13 @@ class ConsoleApplication(object):
|
||||
def _stop(self):
|
||||
pass
|
||||
|
||||
def _resume(self):
|
||||
if self._resumed:
|
||||
return
|
||||
if self._spawned_pid is not None:
|
||||
self._device.resume(self._spawned_pid)
|
||||
self._resumed = True
|
||||
|
||||
def _exit(self, exit_status):
|
||||
self._exit_status = exit_status
|
||||
self._reactor.stop()
|
||||
@@ -100,8 +131,16 @@ class ConsoleApplication(object):
|
||||
self._device.on('lost', self._schedule_on_device_lost)
|
||||
if self._target is not None:
|
||||
try:
|
||||
self._update_status("Attaching...")
|
||||
self._process = self._device.attach(self._target)
|
||||
target_type, target_value = self._target
|
||||
if target_type == 'file':
|
||||
argv = target_value
|
||||
self._update_status("Spawning: %s" % " ".join(argv))
|
||||
self._spawned_pid = self._device.spawn(argv)
|
||||
attach_target = self._spawned_pid
|
||||
else:
|
||||
attach_target = target_value
|
||||
self._update_status("Attaching...")
|
||||
self._process = self._device.attach(attach_target)
|
||||
self._process.on('detached', self._schedule_on_process_detached)
|
||||
except Exception as e:
|
||||
self._update_status("Failed to attach: %s" % e)
|
||||
@@ -138,6 +177,24 @@ def find_device(type):
|
||||
return device
|
||||
return None
|
||||
|
||||
def infer_target(target_value):
|
||||
if target_value.startswith('.') or target_value.startswith(os.path.sep):
|
||||
target_type = 'file'
|
||||
target_value = [target_value]
|
||||
else:
|
||||
try:
|
||||
target_value = int(target_value)
|
||||
target_type = 'pid'
|
||||
except:
|
||||
target_type = 'name'
|
||||
return (target_type, target_value)
|
||||
|
||||
def expand_target(target):
|
||||
target_type, target_value = target
|
||||
if target_type == 'file':
|
||||
target_value = [os.path.abspath(target_value[0])]
|
||||
return (target_type, target_value)
|
||||
|
||||
|
||||
class Reactor(object):
|
||||
def __init__(self, run_until_return):
|
||||
|
||||
@@ -153,15 +153,13 @@ def main():
|
||||
|
||||
class DiscovererApplication(ConsoleApplication, UI):
|
||||
def _usage(self):
|
||||
return "usage: %prog [options] process-name-or-id"
|
||||
return "usage: %prog [options] target"
|
||||
|
||||
def _initialize(self, parser, options, args):
|
||||
self._discoverer = None
|
||||
|
||||
def _target_specifier(self, parser, options, args):
|
||||
if len(args) != 1:
|
||||
parser.error("process name or id must be specified")
|
||||
return args[0]
|
||||
def _needs_target(self):
|
||||
return True
|
||||
|
||||
def _start(self):
|
||||
self._update_status("Injecting script...")
|
||||
|
||||
+3
-5
@@ -17,12 +17,10 @@ def main():
|
||||
super(REPLApplication, self).__init__(self._process_input)
|
||||
|
||||
def _usage(self):
|
||||
return "usage: %prog [options]"
|
||||
return "usage: %prog [options] target"
|
||||
|
||||
def _target_specifier(self, parser, options, args):
|
||||
if len(args) != 1:
|
||||
parser.error("process name or id must be specified")
|
||||
return args[0]
|
||||
def _needs_target(self):
|
||||
return True
|
||||
|
||||
def _start(self):
|
||||
def on_message(message, data):
|
||||
|
||||
+3
-5
@@ -449,16 +449,14 @@ def main():
|
||||
self._profile_builder = pb
|
||||
|
||||
def _usage(self):
|
||||
return "usage: %prog [options] process-name-or-id"
|
||||
return "usage: %prog [options] target"
|
||||
|
||||
def _initialize(self, parser, options, args):
|
||||
self._tracer = None
|
||||
self._profile = self._profile_builder.build()
|
||||
|
||||
def _target_specifier(self, parser, options, args):
|
||||
if len(args) != 1:
|
||||
parser.error("process name or id must be specified")
|
||||
return args[0]
|
||||
def _needs_target(self):
|
||||
return True
|
||||
|
||||
def _start(self):
|
||||
self._tracer = Tracer(self._reactor, FileRepository(), self._profile)
|
||||
|
||||
Reference in New Issue
Block a user