def reboot_bootloader(): """Reboots the device to the bootloader. """ log.info('Rebooting %s to bootloader' % context.device) with Client() as c: c.reboot_bootloader()
def read(path, target=None, callback=None): """Download a file from the device, and extract its contents. Arguments: path(str): Path to the file on the device. target(str): Optional, location to store the file. Uses a temporary file by default. callback(callable): See the documentation for ``adb.protocol.Client.read``. Examples: >>> print adb.read('/proc/version') # doctest: +ELLIPSIS Linux version ... >>> adb.read('/does/not/exist') Traceback (most recent call last): ... PwnlibException: Could not stat '/does/not/exist' """ with Client() as c: stat = c.stat(path) if not stat: log.error('Could not stat %r' % path) data = c.read(path, stat['size'], callback=callback) if target: misc.write(target, data) return data
def wait_for_device(kick=False): """Waits for a device to be connected. By default, waits for the currently-selected device (via ``context.device``). To wait for a specific device, set ``context.device``. To wait for *any* device, clear ``context.device``. Return: An ``AdbDevice`` instance for the device. Examples: >>> device = adb.wait_for_device() """ with log.waitfor("Waiting for device to come online") as w: with Client() as c: if kick: try: c.reconnect() except Exception: pass serial = '' if context.device: serial = str(context.device) with Client() as c: c.wait_for_device(serial) for device in devices(): if context.device == device: return device if not serial: break else: log.error("Could not find any devices") with context.local(device=device): # There may be multiple devices, so context.device is # insufficient. Pick the first device reported. w.success('%s (%s %s %s)' % (device, product(), build(), _build_date())) return context.device
def unlock_bootloader(): """Unlocks the bootloader of the device. Note: This requires physical interaction with the device. """ Client().reboot_bootloader() fastboot(['oem', 'unlock']) fastboot(['continue'])
def reboot(wait=True): """Reboots the device. """ log.info('Rebooting device %s' % context.device) with Client() as c: c.reboot() if wait: wait_for_device()
def remount(): """Remounts the filesystem as writable.""" with log.waitfor("Remounting filesystem on %s" % context.device) as w: disable_verity() root() with Client() as c: reply = c.remount() if 'remount succeeded' not in reply: log.error("Could not remount filesystem:\n%s" % reply)
def walk(top, topdown=True): join = os.path.join isdir = lambda x: stat.S_ISDIR(x['mode']) client = Client() names = client.list(top) dirs, nondirs = [], [] for name, metadata in names.items(): if isdir(metadata): dirs.append(name) else: nondirs.append(name) if topdown: yield top, dirs, nondirs for name in dirs: new_path = join(top, name) for x in walk(new_path, topdown): yield x if not topdown: yield top, dirs, nondirs
def listdir(directory='/'): """Returns a list containing the entries in the provided directory. Note: This uses the SYNC LIST functionality, which runs in the adbd SELinux context. If adbd is running in the su domain ('adb root'), this behaves as expected. Otherwise, less files may be returned due to restrictive SELinux policies on adbd. """ return list(sorted(Client().list(directory)))
def unroot(): """Restarts adbd as AID_SHELL.""" log.info("Unrooting %s" % context.device) with context.quiet: with Client() as c: reply = c.unroot() if '0006closed' == reply: return # Emulator doesnt care if 'restarting adbd as non root' not in reply: log.error("Could not unroot:\n%s" % reply)
def exists(path): """Return :const:`True` if ``path`` exists on the target device. Examples: >>> adb.exists('/') True >>> adb.exists('/init') True >>> adb.exists('/does/not/exist') False """ with Client() as c: return bool(c.stat(path))
def isdir(path): """Return :const:`True` if ``path`` is a on the target device. Examples: >>> adb.isdir('/') True >>> adb.isdir('/init') False >>> adb.isdir('/does/not/exist') False """ with Client() as c: st = c.stat(path) return bool(st and stat.S_ISDIR(st['mode']))
def push(local_path, remote_path): """Upload a file to the device. Arguments: local_path(str): Path to the local file to push. remote_path(str): Path or directory to store the file on the device. Example: >>> write('./filename', 'contents') >>> _=adb.push('./filename', '/data/local/tmp') >>> adb.read('/data/local/tmp/filename') 'contents' >>> adb.push('./filename', '/does/not/exist') Traceback (most recent call last): ... PwnlibException: Could not stat '/does/not/exist' """ msg = "Pushing %r to %r" % (local_path, remote_path) remote_filename = os.path.basename(local_path) if log.isEnabledFor(logging.DEBUG): msg += ' (%s)' % context.device with log.waitfor(msg) as w: with Client() as c: # We need to discover whether remote_path is a directory or not. # If we cannot stat the full path, assume it's a path-plus-filename, # where the filename does not exist. stat_ = c.stat(remote_path) if not stat_: remote_filename = os.path.basename(remote_path) remote_path = os.path.dirname(remote_path) stat_ = c.stat(remote_path) # If we can't find the exact path, or its parent directory, bail! if not stat_: log.error('Could not stat %r' % remote_path) # If we found the parent directory, append the filename mode = stat_['mode'] if stat.S_ISDIR(mode): remote_path = os.path.join(remote_path, remote_filename) return c.write(remote_path, misc.read(local_path), callback=_create_adb_push_pull_callback(w))
def devices(serial=None): """Returns a list of ``Device`` objects corresponding to the connected devices.""" with Client() as c: lines = c.devices(long=True) result = [] for line in lines.splitlines(): # Skip the first 'List of devices attached' line, and the final empty line. if 'List of devices' in line or not line.strip(): continue device = AdbDevice.from_adb_output(line) if device.serial == serial: return device result.append(device) return tuple(result)
def disable_verity(): """Disables dm-verity on the device.""" with log.waitfor("Disabling dm-verity on %s" % context.device) as w: root() with Client() as c: reply = c.disable_verity() if 'Verity already disabled' in reply: return elif 'Now reboot your device' in reply: reboot(wait=True) elif '0006closed' in reply: return # Emulator doesnt support Verity? else: log.error("Could not disable verity:\n%s" % reply)
def unlink(path, recursive=False): """Unlinks a file or directory on the target device. Examples: >>> adb.unlink("/does/not/exist") Traceback (most recent call last): ... PwnlibException: Could not unlink '/does/not/exist': Does not exist >>> filename = '/data/local/tmp/unlink-test' >>> adb.write(filename, 'hello') >>> adb.exists(filename) True >>> adb.unlink(filename) >>> adb.exists(filename) False >>> adb.mkdir(filename) >>> adb.write(filename + '/contents', 'hello') >>> adb.unlink(filename) Traceback (most recent call last): ... PwnlibException: Cannot delete non-empty directory '/data/local/tmp/unlink-test' without recursive=True >>> adb.unlink(filename, recursive=True) >>> adb.exists(filename) False """ with Client() as c: st = c.stat(path) if not st: log.error("Could not unlink %r: Does not exist" % path) # If the directory is not empty, do not delete it if isdir(path) and c.list(path) and not recursive: log.error( "Cannot delete non-empty directory %r without recursive=True" % path) flags = '-rf' if recursive else '-r' output = c.execute(['rm', flags, path]).recvall() if output: log.error(output)
def root(): """Restarts adbd as root. >>> adb.root() """ log.info("Enabling root on %s" % context.device) with context.quiet: with Client() as c: reply = c.root() if 'already running as root' in reply: return elif not reply or 'restarting adbd as root' in reply: with context.quiet: wait_for_device() else: log.error("Could not run as root:\n%s" % reply)
def mkdir(path): """Create a directory on the target device. Note: Silently succeeds if the directory already exists. Arguments: path(str): Directory to create. Examples: >>> adb.mkdir('/') >>> path = '/data/local/tmp/mkdir_test' >>> adb.exists(path) False >>> adb.mkdir(path) >>> adb.exists(path) True >>> adb.mkdir('/init') Traceback (most recent call last): ... PwnlibException: mkdir failed for /init, File exists """ if not path.startswith('/'): log.error("Must provide an absolute path: %r" % path) with Client() as c: st = c.stat(path) # Don't re-create existing directories if st and stat.S_ISDIR(st['mode']): return result = process(['mkdir', path]).recvall() # Any output at all is an error if result: log.error(result)
def process(argv, *a, **kw): """Execute a process on the device. See :class:`pwnlib.tubes.process.process` documentation for more info. Returns: A :class:`pwnlib.tubes.process.process` tube. Examples: >>> adb.root() >>> print adb.process(['cat','/proc/version']).recvall() # doctest: +ELLIPSIS Linux version ... """ if isinstance(argv, (str, unicode)): argv = [argv] message = "Starting %s process %r" % ('Android', argv[0]) if log.isEnabledFor(logging.DEBUG): if argv != [argv[0]]: message += ' argv=%r ' % argv with log.progress(message) as p: return Client().execute(argv)