pwnlib.adb — Android Debug Bridge

Provides utilities for interacting with Android devices via the Android Debug Bridge.

# Using Android Devices with Pwntools

Pwntools tries to be as easy as possible to use with Android devices.

If you have only one device attached, everything “just works”.

If you have multiple devices, you have a handful of options to select one, or iterate over the devices.

First and most important is the context.device property, which declares the “currently” selected device in any scope. It can be set manually to a serial number, or to a Device instance.

# Take the first available device
context.device = adb.wait_for_device()

# Set a device by serial number
context.device = 'ZX1G22LH8S'

# Set a device by its product name
for device in adb.devices():
    if device.product == 'shamu':
        break
else:
    error("Could not find any shamus!")

Once a device is selected, you can operate on it with any of the functions in the pwnlib.adb module.

# Get a process listing
print adb.process(['ps']).recvall()

# Fetch properties
print adb.properties.ro.build.fingerprint

# Read and write files
print adb.read('/proc/version')
adb.write('/data/local/tmp/foo', 'my data')
class pwnlib.adb.adb.AdbDevice(serial, type, port=None, product='unknown', model='unknown', device='unknown', features=None, **kw)[source]

Encapsulates information about a connected device.

Example

>>> device = adb.wait_for_device()
>>> device.arch
'arm'
>>> device.bits
32
>>> device.os
'android'
>>> device.product
'sdk_phone_armv7'
>>> device.serial
'emulator-5554'
pwnlib.adb.adb.adb(argv, *a, **kw)[source]

Returns the output of an ADB subcommand.

>>> adb.adb(['get-serialno'])
'emulator-5554\n'
pwnlib.adb.adb.boot_time() → int[source]
Returns:Boot time of the device, in Unix time, rounded to the nearest second.
pwnlib.adb.adb.build(*a, **kw)[source]

Returns the Build ID of the device.

pwnlib.adb.adb.compile(source)[source]

Compile a source file or project with the Android NDK.

pwnlib.adb.adb.current_device(any=False)[source]

Returns an AdbDevice instance for the currently-selected device (via context.device).

Example

>>> device = adb.current_device(any=True)
>>> device
AdbDevice(serial='emulator-5554', type='device', port='emulator', product='sdk_phone_armv7', model='sdk phone armv7', device='generic')
>>> device.port
'emulator'
pwnlib.adb.adb.devices(*a, **kw)[source]

Returns a list of Device objects corresponding to the connected devices.

pwnlib.adb.adb.disable_verity(*a, **kw)[source]

Disables dm-verity on the device.

pwnlib.adb.adb.exists(*a, **kw)[source]

Return True if path exists on the target device.

Examples

>>> adb.exists('/')
True
>>> adb.exists('/init')
True
>>> adb.exists('/does/not/exist')
False
pwnlib.adb.adb.fastboot(*a, **kw)[source]

Executes a fastboot command.

Returns:The command output.
pwnlib.adb.adb.find_ndk_project_root(source)[source]

Given a directory path, find the topmost project root.

tl;dr “foo/bar/jni/baz.cpp” ==> “foo/bar”

pwnlib.adb.adb.fingerprint(*a, **kw)[source]

Returns the device build fingerprint.

pwnlib.adb.adb.forward(*a, **kw)[source]

Sets up a port to forward to the device.

pwnlib.adb.adb.getprop(*a, **kw)[source]

Reads a properties from the system property store.

Parameters:name (str) – Optional, read a single property.
Returns:If name is not specified, a dict of all properties is returned. Otherwise, a string is returned with the contents of the named property.
pwnlib.adb.adb.install(apk, *arguments)[source]

Install an APK onto the device.

This is a wrapper around ‘pm install’, which backs ‘adb install’.

Parameters:
  • apk (str) – Path to the APK to intall (e.g. 'foo.apk')
  • arguments – Supplementary arguments to ‘pm install’, e.g. '-l', '-g'.
pwnlib.adb.adb.interactive(*a, **kw)[source]

Spawns an interactive shell.

pwnlib.adb.adb.isdir(*a, **kw)[source]

Return True if path is a on the target device.

Examples

>>> adb.isdir('/')
True
>>> adb.isdir('/init')
False
>>> adb.isdir('/does/not/exist')
False
pwnlib.adb.adb.listdir(*a, **kw)[source]

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.

pwnlib.adb.adb.logcat(*a, **kw)[source]

Reads the system log file.

By default, causes logcat to exit after reading the file.

Parameters:stream (bool) – If True, the contents are streamed rather than read in a one-shot manner. Default is False.
Returns:If stream is False, returns a string containing the log data. Otherwise, it returns a tube connected to the log output.
pwnlib.adb.adb.makedirs(*a, **kw)[source]

Create a directory and all parent directories on the target device.

Note

Silently succeeds if the directory already exists.

Examples

>>> adb.makedirs('/data/local/tmp/this/is/a/directory/heirarchy')
>>> adb.listdir('/data/local/tmp/this/is/a/directory')
['heirarchy']
pwnlib.adb.adb.mkdir(*a, **kw)[source]

Create a directory on the target device.

Note

Silently succeeds if the directory already exists.

Parameters: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
pwnlib.adb.adb.packages(*a, **kw)[source]

Returns a list of packages installed on the system

pwnlib.adb.adb.pidof(*a, **kw)[source]

Returns a list of PIDs for the named process.

pwnlib.adb.adb.proc_exe(*a, **kw)[source]

Returns the full path of the executable for the provided PID.

pwnlib.adb.adb.process(*a, **kw)[source]

Execute a process on the device.

See pwnlib.tubes.process.process documentation for more info.

Returns:A process tube.

Examples

>>> adb.root()
>>> print adb.process(['cat','/proc/version']).recvall() 
Linux version ...
pwnlib.adb.adb.product(*a, **kw)[source]

Returns the device product identifier.

pwnlib.adb.adb.pull(*a, **kw)[source]

Download a file from the device.

Parameters:
  • remote_path (str) – Path or directory of the file on the device.
  • local_path (str) – Path to save the file to. Uses the file’s name by default.
Returns:

The contents of the file.

Example

>>> _=adb.pull('/proc/version', './proc-version')
>>> print read('./proc-version') 
Linux version ...
pwnlib.adb.adb.push(*a, **kw)[source]

Upload a file to the device.

Parameters:
  • 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'
pwnlib.adb.adb.read(*a, **kw)[source]

Download a file from the device, and extract its contents.

Parameters:
  • 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') 
Linux version ...
>>> adb.read('/does/not/exist')
Traceback (most recent call last):
...
PwnlibException: Could not stat '/does/not/exist'
pwnlib.adb.adb.reboot(*a, **kw)[source]

Reboots the device.

pwnlib.adb.adb.reboot_bootloader(*a, **kw)[source]

Reboots the device to the bootloader.

pwnlib.adb.adb.remount(*a, **kw)[source]

Remounts the filesystem as writable.

pwnlib.adb.adb.root(*a, **kw)[source]

Restarts adbd as root.

>>> adb.root()
pwnlib.adb.adb.setprop(*a, **kw)[source]

Writes a property to the system property store.

pwnlib.adb.adb.shell(*a, **kw)[source]

Returns an interactive shell.

pwnlib.adb.adb.uninstall(package, *arguments)[source]

Uninstall an APK from the device.

This is a wrapper around ‘pm uninstall’, which backs ‘adb uninstall’.

Parameters:
  • package (str) – Name of the package to uninstall (e.g. 'com.foo.MyPackage')
  • arguments – Supplementary arguments to 'pm install', e.g. '-k'.

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
pwnlib.adb.adb.unlock_bootloader(*a, **kw)[source]

Unlocks the bootloader of the device.

Note

This requires physical interaction with the device.

pwnlib.adb.adb.unroot(*a, **kw)[source]

Restarts adbd as AID_SHELL.

pwnlib.adb.adb.uptime() → float[source]
Returns:Uptime of the device, in seconds
pwnlib.adb.adb.wait_for_device(*a, **kw)[source]

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.

Returns:An AdbDevice instance for the device.

Examples

>>> device = adb.wait_for_device()
pwnlib.adb.adb.which(*a, **kw)[source]

Retrieves the full path to a binary in PATH on the device

>>> adb.which('sh')
'/system/bin/sh'
pwnlib.adb.adb.write(*a, **kw)[source]

Create a file on the device with the provided contents.

Parameters:
  • path (str) – Path to the file on the device
  • data (str) – Contents to store in the file

Examples

>>> adb.write('/dev/null', 'data')
>>> adb.write('/data/local/tmp/')

Implementation of the Android Debug Bridge (ADB) protocol, as far as Binjitsu needs it.

Documentation is available here: https://android.googlesource.com/platform/system/core/+/master/adb/protocol.txt

class pwnlib.adb.protocol.Client(level=None)[source]

ADB Client

c[source]

Client’s connection to the ADB server

devices(*a, **kw)[source]
Parameters:long (bool) – If True, fetch the long-format listing.
Returns:String representation of all available devices.
execute(*a, **kw)[source]

Executes a program on the device.

Returns:A tube which is connected to the process.

Examples

>>> adb.protocol.Client().execute(['echo','hello']).recvall()
'hello\n'
kill(*a, **kw)[source]

Kills the remote ADB server”

>>> c=adb.protocol.Client()
>>> c.kill()

The server is automatically re-started on the next request, if the default host/port are used.

>>> c.version() > (4,0)
True
list(path)[source]

Execute the LIST command of the SYNC API.

Parameters:path (str) – Path of the directory to list.
Returns:A dictionary, where the keys are relative filenames, and the values are a dictionary containing the same values as stat() supplies.

Note

In recent releases of Android (e.g. 7.0), the domain that adbd executes from does not have access to everything that the shell user does.

Because of this, while the shell user can get listings of e.g. the root directory (‘/’), adbd cannot.

The SYNC APIs are executed within the adbd context, not the shell user context.

This issue is not a problem if the phone is rooted via ‘adb root’, since adbd then runs in the su domain.

Examples

>>> pprint(adb.Client().list('/data/user'))
{'0': {'mode': 41471, 'size': 11, 'time': ...}}
>>> adb.Client().list('/does/not/exist')
Traceback (most recent call last):
...
PwnlibException: Cannot list directory '/does/not/exist': Does not exist
read(*a, **kw)[source]

Execute the READ command of the SYNC API.

Parameters:
  • path (str) – Path to the file to read
  • filesize (int) – Size of the file, in bytes. Optional.
  • callback (callable) –

    Callback function invoked as data becomes available. Arguments provided are:

    • File path
    • All data
    • Expected size of all data
    • Current chunk
    • Expected size of chunk
Returns:

The data received as a string.

recvl()[source]

Receives a length-prefixed data buffer from the ADB server

send(*a, **kw)[source]

Sends data to the ADB server

stat(*a, **kw)[source]

Execute the STAT command of the SYNC API.

Parameters:path (str) – Path to the file to stat.
Returns:On success, a dictionary mapping the values returned. If the file cannot be ``stat()``ed, None is returned.

Example

>>> expected = {'mode': 16749, 'size': 0, 'time': 0}
>>> adb.protocol.Client().stat('/proc')           == expected
True
>>> adb.protocol.Client().stat('/does/not/exist') == None
True
track_devices(*a, **kw)[source]
Returns:Generator which returns a short-format listing of available devices each time a device state changes.
transport(serial=None)[source]

Sets the Transport on the rmeote device.

Examples

>>> adb.protocol.Client().transport()
unpack(*a, **kw)[source]

Receives a hex-ascii packed integer from the ADB server

version(*a, **kw)[source]
Returns:Tuple containing the (major, minor) version from the ADB server

Example

>>> adb.protocol.Client().version() 
(4, 36)
write(path, data, mode=493, timestamp=None, callback=None)[source]

Execute the WRITE command of the SYNC API.

Parameters:
  • path (str) – Path to the file to write
  • data (str) – Data to write to the file
  • mode (int) – File mode to set (e.g. 0o755)
  • timestamp (int) – Unix timestamp to set the file date to
  • callback (callable) –

    Callback function invoked as data is written. Arguments provided are:

    • File path
    • All data
    • Expected size of all data
    • Current chunk
    • Expected size of chunk
class pwnlib.adb.protocol.Connection(host, port, level=None, *a, **kw)[source]

Connection to the ADB server

class pwnlib.adb.protocol.Message(string)[source]

An ADB hex-length-prefixed message

class pwnlib.adb.protocol.Process(host, port, level=None, *a, **kw)[source]

Duck-typed tubes.remote object to add properties of a tubes.process

pwnlib.adb.protocol.proxy(port=9999)[source]

Starts an ADB proxy on the specified port, for debugging purposes.