Exemple #1
0
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:

    .. doctest::
       :skipif: skip_android

        >>> device = adb.wait_for_device()
    """
    with log.waitfor("Waiting for device to come online") as w:
        with AdbClient() as c:
            if kick:
                try:
                    c.reconnect()
                except Exception:
                    pass

            serial = ''
            if context.device:
                serial = str(context.device)

        with AdbClient() 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
Exemple #2
0
def reboot_bootloader():
    """Reboots the device to the bootloader.
    """
    log.info('Rebooting %s to bootloader' % context.device)

    with AdbClient() as c:
        c.reboot_bootloader()
Exemple #3
0
def unlock_bootloader():
    """Unlocks the bootloader of the device.

    Note:
        This requires physical interaction with the device.
    """
    w = log.waitfor("Unlocking bootloader")
    with w:
        if getprop('ro.oem_unlock_supported') == '0':
            log.error("Bootloader cannot be unlocked: ro.oem_unlock_supported=0")

        if getprop('ro.boot.oem_unlock_support') == '0':
            log.error("Bootloader cannot be unlocked: ro.boot.oem_unlock_support=0")

        if getprop('sys.oem_unlock_allowed') == '0':
            log.error("Bootloader cannot be unlocked: Enable OEM Unlock in developer settings first", context.device)

        AdbClient().reboot_bootloader()

        # Check to see if it's unlocked before attempting unlock
        unlocked = fastboot(['getvar', 'unlocked'])
        if 'unlocked: yes' in unlocked:
            w.success("Already unlocked")
            fastboot(['continue'])
            return

        fastboot(['oem', 'unlock'])
        unlocked = fastboot(['getvar', 'unlocked'])

        fastboot(['continue'])

        if 'unlocked: yes' not in unlocked:
            log.error("Unlock failed")
Exemple #4
0
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:

    .. doctest::
       :skipif: skip_android

        >>> adb.root()
        >>> print(adb.process(['cat','/proc/version']).recvall().decode('utf-8')) # doctest: +ELLIPSIS
        Linux version ...
    """
    if isinstance(argv, (bytes, six.text_type)):
        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 AdbClient().execute(argv)
Exemple #5
0
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.AdbClient.read``.

    Examples:

        >>> print(adb.read('/proc/version').decode('utf-8')) # doctest: +ELLIPSIS
        Linux version ...
        >>> adb.read('/does/not/exist')
        Traceback (most recent call last):
        ...
        PwnlibException: Could not stat '/does/not/exist'
    """
    with AdbClient() 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
Exemple #6
0
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.

    Returns:
        Remote path of the file.

    Example:

    .. doctest::
       :skipif: skip_android

        >>> write('./filename', 'contents')
        >>> adb.push('./filename', '/data/local/tmp')
        '/data/local/tmp/filename'
        >>> adb.read('/data/local/tmp/filename')
        b'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 AdbClient() 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)

            c.write(remote_path,
                    misc.read(local_path),
                    callback=_create_adb_push_pull_callback(w))

    return remote_path
Exemple #7
0
def unlock_bootloader():
    """Unlocks the bootloader of the device.

    Note:
        This requires physical interaction with the device.
    """
    AdbClient().reboot_bootloader()
    fastboot(['oem', 'unlock'])
    fastboot(['continue'])
Exemple #8
0
def reboot(wait=True):
    """Reboots the device.
    """
    log.info('Rebooting device %s' % context.device)

    with AdbClient() as c:
        c.reboot()

    if wait:
        wait_for_device()
Exemple #9
0
def remount():
    """Remounts the filesystem as writable."""
    with log.waitfor("Remounting filesystem on %s" % context.device):
        disable_verity()
        root()

        with AdbClient() as c:
            reply = c.remount()

        if 'remount succeeded' not in reply:
            log.error("Could not remount filesystem:\n%s" % reply)
Exemple #10
0
def walk(top, topdown=True):
    join = os.path.join
    isdir = lambda x: stat.S_ISDIR(x['mode'])
    client = AdbClient()
    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
Exemple #11
0
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(AdbClient().list(directory)))
Exemple #12
0
def unroot():
    """Restarts adbd as AID_SHELL."""
    log.info("Unrooting %s" % context.device)
    with context.quiet:
        with AdbClient() 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)
Exemple #13
0
def walk(top, topdown=True):
    join = os.path.join
    isdir = lambda x: stat.S_ISDIR(x['mode'])
    client = AdbClient()
    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
Exemple #14
0
def exists(path):
    """Return :const:`True` if ``path`` exists on the target device.

    Examples:

        >>> adb.exists('/')
        True
        >>> adb.exists('/etc/hosts')
        True
        >>> adb.exists('/does/not/exist')
        False
    """
    with AdbClient() as c:
        return bool(c.stat(path))
Exemple #15
0
def unlink(path, recursive=False):
    """Unlinks a file or directory on the target device.

    Examples:

    .. doctest::
       :skipif: skip_android

        >>> 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 AdbClient() 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 '-f'

        output = c.execute(['rm', flags, path]).recvall()

        if output:
            log.error(output.decode('utf-8'))
Exemple #16
0
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 AdbClient() as c:
        st = c.stat(path)
        return bool(st and stat.S_ISDIR(st['mode']))
Exemple #17
0
def devices(serial=None):
    """Returns a list of ``Device`` objects corresponding to the connected devices."""
    with AdbClient() 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)
Exemple #18
0
def disable_verity():
    """Disables dm-verity on the device."""
    with log.waitfor("Disabling dm-verity on %s" % context.device):
        root()

        with AdbClient() 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)
Exemple #19
0
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:

    .. doctest::
       :skipif: skip_android

        >>> 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 AdbClient() 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.rstrip().decode('utf-8'))
Exemple #20
0
def root():
    """Restarts adbd as root.

    >>> adb.root()
    """
    log.info("Enabling root on %s" % context.device)

    with context.quiet:
        with AdbClient() 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)