Python Scripts

This section presents the help and usage text for each of the scripts included with Depthcharge. This same information can be viewed by invoking these scripts with a -h or --help argument.

The first script one will usually want to run when working with a device is depthcharge-inspect. This script collects information from a device and stores it into a device configuration file specified by a -c, --config command-line argument. This configuration can be passed other Depthcharge scripts in order to allow them to skip redundant device inspections before performing their requested actions.

The configuration file itself is a simple JSON file, which contains much of the information one would normally jot down in notes about a device. The depthcharge-print script can be used to quickly view all, or a subset of, information stored in the device configuration file. For example, one might use this to view a target’s environment variables in a fully expanded form (i.e., with all variable definitions recursively resolved).

Given the availability of necessary operations, the depthcharge-read-mem and depthcharge-write-mem scripts can be used to extract data from and write data to target memory locations. By default, these select the “best” available implementation to do so. However, those familiar with the Python API can exercise full control over these scripts and their underling behavior using the --op and -X, --extra arguments.

Once a a memory of flash dump has been obtained, either using depthcharge-read-mem or through a chip-off approach, a few different scripts can be used to locate different types of data.

The depthcharge-find-cmd script can be used to locate the U-Boot “linker lists” containing the console command structures. In situations where a limited-functionality console is observed, the presence of more than one unique command table may suggest that functionality is “hidden” or otherwise gated based upon some form of vendor-specific authentication or “debug enable” functionality (e.g., GPIO state, a value in a specific flash location).

U-Boot environments (collections of variable definitions) can be identified and extracted using depthcharge-find-env. Even when platform designers have attempted to “lock down” or remove their console interfaces, it is often the case that these unauthenticated collections of commands can be tampered with offline and re-written to storage media in order to perform arbitrary actions on the target. Always keep a lookout for console messages denoting that a built-in default environment is being used due to an invalid CRC32 checksum – this may indicate that you can inject an environment at an address normally defined by the U-Boot compile-time CONFIG_ENV definition, with a size defined by CONFIG_ENV_SIZE. The depthcharge-mkenv script can be used to convert a textual environment description (as seen in printenv output) in to its binary form, padded to the correct size and prefixed with the correct CRC32 checksum. In situations where redundant environments are store, an optional --flags argument can be used to insert the counter value in the environment header in order to ensure that your environment is the one marked as in-use.

Flattened Device Tree (FDT) data structures are used by U-Boot and the Linux kernel to describe the availability and configuration of hardware. When taken at face value, these data structures may seem “uninteresting” to an attacker, but they do provide quite a bit of insight into memory-mapped peripheral subsystems, drivers in use, and oftentimes pin multiplexing configurations. Like externally-stored environments, these too can be overlooked when a platform vendor seeks to authenticate data in a secure boot flow. In these situations, opportunities to add or tamper with a bootargs entry in a chosen node can be interesting. These data structures can be carved from a binary and converted to their textual “source” form using the depthcharge-find-fdt script. Note that the Device Tree Compiler (dtc) must be installed on your system in order to leverage dtb-to-dts conversion functionality.

Finally, depthcharge-stratagem allows depthcharge.Stratagem files to be produced. These are used by operations such as CRC32MemoryWriter and CpMemoryWriter to perform the request action, despite not being able to do so directly. In the case of CRC32MemoryWriter, these means identifying sequences of CRC32 operations that can write a desired payload to a target memory location. (Refer to the ReverseCRC32Hunter documentation for information about how this is achieved.)

As discussed in the introduction, the Depthcharge Python API is the primary focus of this project. The scripts presented here are largely thought of as a means to more conveniently expose the API functionality for quicker use. As such, users are strongly encouraged to explore and understand these scripts, along with the underlying API functionality they use.

depthcharge-inspect

usage: depthcharge-inspect [options] -c <device config>

Inspect a device's console environment and create a device configuration file.

options:
  -h, --help            show this help message and exit
  --arch <architecture>
                        CPU architecture.
  -c <cfg>, --config <cfg>
                        Device configuration file to load and update. It will
                        be created if it does not exist.
  -i <console dev>[:baudrate], --iface <console dev>[:baudrate]
                        Serial port interface connected to U-Boot console.
  -C <device>[:setting=value,...], --companion <device>[:setting=value,...]
                        Depthcharge companion device to use and its associated
                        settings. See the depthcharge.Companion documentation
                        for supported settings.
  -m <type>[:options,...], --monitor <type>[:options,...]
                        Attach a console monitor. Valid types: file, pipe,
                        colorpipe, term
  -X <key>[=<value>], --extra <key>[=<value>]
                        Specify extra operation-specific parameters as a key-
                        value pair. A value of True is implicit if a value is
                        not explicitly provided. Multiple instances of this
                        argument are permitted. See the documentation for
                        subclasses of depthcharge.Operation for supported
                        keyword arguments.
  -P <prompt str>, --prompt <prompt str>
                        Override expected U-Boot prompt string.
  -A, --allow-deploy    Allow payloads to be deployed and executed.
                        Functionality may be limited if this is not specified.
  -S, --skip-deploy     Skip payload deployment but allow execution; assume
                        payloads are already deployed and execute as-needed.
                        This has no effect when -A, --allow-deploy is used.
  -R, --allow-reboot    Allow operations that require crashing or rebooting
                        the target to be performed.

notes:
  This is generally the first Depthcharge script one will want to run when
  interacting with a new device.

  The resulting configuration file can passed to other Depthcharge scripts,
  alleviating the need to re-inspect the device each time a context object
  is created. (See depthcharge.Depthcharge.load() documentation.)

examples:
  Save results to a "dev.cfg" file and use the default serial interface
  settings (/dev/ttyUSB0 at 115200 baud). This will use the default "Generic"
  32-bit little endian CPU architecture, and will avoid the use of any
  operations that require rebooting/crashing the platform or deploying
  and executing payloads.

    depthcharge-inspect -c dev.cfg

  Use the serial console located at /dev/ttyUSB2 at a speed of 19200 baud.
  Here, we additionally specify that the target is a 32-bit ARM device,
  and that we want to opt-in to the use of operations that necessitate
  crashing/rebooting the platform, as well as payload deployment and execution.

    depthcharge-inspect --arch arm -AR -i /dev/ttyUSB2:19200 -c dev.cfg

  Use a companion device attached to /dev/ttyACM1.  Configure the companion
  to operate on the target's I2C bus #2, for a speed of 250kHz. (Here, -i is
  omitted again to use the default settings.)

    depthcharge-inspect --arch arm -AR -c dev.cfg \
                        -C /dev/ttyACM1:i2c_bus=2,i2c_speed=250000

  Supply a known prompt string to look for instead of having Depthcharge attempt
  to determine it:

    depthcharge-inspect --arch arm -AR --prompt "ACMEcorp >" -c my_config.cfg

depthcharge-print

usage: depthcharge-print -c <device config> -i <info>[:options]

Pretty-print information in a device configuration file.

options:
  -h, --help            show this help message and exit
  -c <cfg>, --config <cfg>
                        Configuration file to print.
  -i <item>, --item <item>
                        Configuration item(s) to print.

supported items:
  all                   - All of the below items

  arch                  - Device architecture

  commands[:details]    - Console commands supported by a target, optionally
                          with detailed help text, if the target provides it

  env[:expand]          - Target's environment variables, optionally
                          with all definitions expanded.

  gd                    - U-Boot global data structure information, if known.

  version               - Target's reported version information

examples:
  Print all information contained in a device configuration ("dev.cfg"):

    depthcharge-print-config -c dev.cfg -i all

  Print all commands supported by a device. Note that if you only
  want a summary of the commands, the detail help text can be omitted
  by not including '=details'

    depthcharge-print-config -c dev.cfg -i commands=details

  Print all environment variables, with all definitiions fully
  expanded. To view these as they are on the device, omit '=expand'.

    depthcharge-print-config -c dev.cfg -i env=expand

  Print both the target's architechture, U-Boot version information,
  and expanded environment variables. Both usages are acceptable.

    depthcharge-print-config -c dev.cfg -i arch,version,env=expand
    depthcharge-print-config -c dev.cfg -i arch -i version -i env=expand

depthcharge-read-mem

usage: 
depthcharge-read-mem [options] -c <device config> -a <address> -l <length>
depthcharge-read-mem [options] -c <device config> -a <address> -l <length> -f <file>


Read memory contents to a file or display them in a hex dump.

options:
  -h, --help            show this help message and exit
  --arch <architecture>
                        CPU architecture.
  -c <cfg>, --config <cfg>
                        Device configuration file to load and update. It will
                        be created if it does not exist.
  -i <console dev>[:baudrate], --iface <console dev>[:baudrate]
                        Serial port interface connected to U-Boot console.
  -C <device>[:setting=value,...], --companion <device>[:setting=value,...]
                        Depthcharge companion device to use and its associated
                        settings. See the depthcharge.Companion documentation
                        for supported settings.
  -m <type>[:options,...], --monitor <type>[:options,...]
                        Attach a console monitor. Valid types: file, pipe,
                        colorpipe, term
  -X <key>[=<value>], --extra <key>[=<value>]
                        Specify extra operation-specific parameters as a key-
                        value pair. A value of True is implicit if a value is
                        not explicitly provided. Multiple instances of this
                        argument are permitted. See the documentation for
                        subclasses of depthcharge.Operation for supported
                        keyword arguments.
  -P <prompt str>, --prompt <prompt str>
                        Override expected U-Boot prompt string.
  -A, --allow-deploy    Allow payloads to be deployed and executed.
                        Functionality may be limited if this is not specified.
  -S, --skip-deploy     Skip payload deployment but allow execution; assume
                        payloads are already deployed and execute as-needed.
                        This has no effect when -A, --allow-deploy is used.
  -R, --allow-reboot    Allow operations that require crashing or rebooting
                        the target to be performed.
  -f <path>, --file <path>
                        Optional file to store data in.
  -a <value>, --address <value>
                        Target address to read from
  -l <n>, --length <n>  Number of bytes to read
  --op <name>[,name,...]
                        Request that one of the specified
                        depthcharge.Operation implementations be used.
                        Depthcharge will attempt to choose the best available
                        option if this is not provided.

notes:
    If a filename is not provided, a textual hex dump will be printed.

    The following address and length suffixes are supported:

        * kB = 1000
        * K or kiB = 1024
        * MB = 1000 * 1000
        * M or MiB = 1024 * 1024
        * GB = 1000 * 1000 * 1000
        * G or GiB = 1024 * 1024 * 1024

    While optional, the use of the -c, --config option is STRONGLY ENCOURAGED.
    This will greatly speed up the execution time of this script, if it will
    be used multiple times for a given target. Similarly, once any payloads
    needed by a reader have been deployed to RAM, the -D, --skip-deploy
    option can be used to further speed up execution.

examples:
    Read 16384 bytes from 0x82000000 and display a hex dump:

      depthcharge-read-mem -c dev.cfg -a 0x82000000 -l 16384

    The following example is equivalent, but uses supported suffixes:

      depthcharge-read-mem -c dev.cfg -a 2080M  -l 16K

    This example instead reads data to a file. Note that Python's underscore
    syntax for readability is supported.

      depthcharge-read-mem -c dev.cfg -a 0x8200_0000 -l 16K -f data.bin

    Request Depthcharge to use the depthcharge.memory.SetexprMemoryReader class
    to read memory. Note that the `MemoryReader` suffix can be omitted, and
    that this argument is case-insensitve.

      depthcharge-read-mem -c dev.cfg -a 0x8200_0000 -l 1M -f data.bin --op setexpr

depthcharge-write-mem

usage: 
depthcharge-write-mem [options] -c <device config> -a <address> -f <file>
depthcharge-write-mem [options] -c <device config> -a <address> -d <hex data>
depthcharge-write-mem [options] -c <device config> -a <address> -s <stratagem>


Write data to a specified memory address.

options:
  -h, --help            show this help message and exit
  --arch <architecture>
                        CPU architecture.
  -c <cfg>, --config <cfg>
                        Device configuration file to load and update. It will
                        be created if it does not exist.
  -i <console dev>[:baudrate], --iface <console dev>[:baudrate]
                        Serial port interface connected to U-Boot console.
  -C <device>[:setting=value,...], --companion <device>[:setting=value,...]
                        Depthcharge companion device to use and its associated
                        settings. See the depthcharge.Companion documentation
                        for supported settings.
  -m <type>[:options,...], --monitor <type>[:options,...]
                        Attach a console monitor. Valid types: file, pipe,
                        colorpipe, term
  -X <key>[=<value>], --extra <key>[=<value>]
                        Specify extra operation-specific parameters as a key-
                        value pair. A value of True is implicit if a value is
                        not explicitly provided. Multiple instances of this
                        argument are permitted. See the documentation for
                        subclasses of depthcharge.Operation for supported
                        keyword arguments.
  -P <prompt str>, --prompt <prompt str>
                        Override expected U-Boot prompt string.
  -A, --allow-deploy    Allow payloads to be deployed and executed.
                        Functionality may be limited if this is not specified.
  -S, --skip-deploy     Skip payload deployment but allow execution; assume
                        payloads are already deployed and execute as-needed.
                        This has no effect when -A, --allow-deploy is used.
  -R, --allow-reboot    Allow operations that require crashing or rebooting
                        the target to be performed.
  -a <value>, --address <value>
                        Target memory address
  -f <path>, --file <path>
                        File containing data to write
  -d <hex str>, --data <hex str>
                        Data to write as a hexadecimal string
  -s <file>, --stratagem <file>
                        Stratagem needed to write payload
  --op <name>[,name,...]
                        Request that one of the specified
                        depthcharge.Operation implementations be used.
                        Depthcharge will attempt to choose the best available
                        option if this is not provided.

notes:
    The following address suffixes are supported:

        * kB = 1000
        * K or kiB = 1024
        * MB = 1000 * 1000
        * M or MiB = 1024 * 1024
        * GB = 1000 * 1000 * 1000
        * G or GiB = 1024 * 1024 * 1024

    While optional, the use of the -c, --config option is STRONGLY ENCOURAGED.
    This will greatly speed up the execution time of this script, if it will
    be used multiple times for a given target.

examples:
    Write the contents of "data.bin" to address 0x87f00000:

      depthcharge-write-mem -c dev.cfg -a 0x87f00000 -f data.bin

    Write the bytes [0x01, 0x00, 0xa0, 0xe3] to 0x87f014a0:

      depthcharge-write-mem -c dev.cfg -a 0x87f00000 -d 0100a0e3

    Write data to address 0x87f01400 using depthcharge.memory.CRC32MemoryWriter
    and the Stratagem conteind within "stratagem.json".

      depthcharge-write-mem -c dev.cfg -a 0x87f01400 -s stratagem.json

    Request Depthcharge to use the depthcharge.memory.LoadbMemoryWriter class
    to memory. Note that the `MemoryWriter` suffix can be omitted, and
    that this argument is case-insensitve.

      depthcharge-write-mem -c dev.cfg --op loadb -a 0x8200_0000 -f data.bin

depthcharge-find-cmd

usage: depthcharge-find-cmd [options] -f <image file>

Search for U-Boot command tables within a memory or flash dump.

options:
  -h, --help            show this help message and exit
  -a <value>, --address <value>
                        Base address of image.
  --arch <architecture>
                        CPU architecture.
  -f <path>, --file <path>
                        Flash or memory image to inspect
  --longhelp {Y,N}      Value of U-Boot CONFIG_SYS_LONGHELP setting.
  --autocomplete {Y,N}  Value of U-Boot CONFIG_AUTO_COMPLETE setting.
  --threshold THRESHOLD
                        Minimum table size to report. Default: 5
  --subcmds             Include sub-command tables in displayed results
  --details             Display more detailed output

notes:
  If the --longhelp and --autocomplete options are not specified, Depthcharge
  will attempt to infer the state of these compile-time configuration settings.

  When --subcmds is specified, output will include any subcommand handler tables.
  This may require a lower --threshold setting, which could yield false positives.

example:
  Search for command table entries provide detailed output, given an ARM
  device and a memory dump taken from address 0x87800000.

    depthcharge-find-cmd --arch arm -a 0x8780000 -f dump.bin --details

depthcharge-find-env

usage: depthcharge-find-env [options] -f <image file>

Search for U-Boot environment data (env_t structures) in a flash or memory dump

options:
  -h, --help            show this help message and exit
  -f <path>, --file <path>
                        Binary image to search
  -a <value>, --address <value>
                        Base address of the flash or memory dump. Result are
                        shown with respect to this address. Use the default of
                        0 if interested in relative offsets.
  --arch <architecture>
                        CPU architecture.
  -o <path>, --outfile <path>
                        Filename prefix for output file(s). No files are
                        written if this is not provided. A .txt or .bin suffix
                        will be added to each file.
  -E, --expand          Expand environment variable definitions, such thatall
                        defined variable usages are resolved. Warningwill be
                        printed for any unresolved variables.
  -B, --binary          When saving an output file, write the binary
                        environment contents.This will include the env_t
                        metadata (CRC32 word, flags byte).
  -S, --summary         Only print the summary of located environment(s). Do
                        not print environment contents.

 examples:
    Print all environment instances found in mtdblock0.bin:

      depthcharge-find-env -f mtdblock0.bin

    Expand environment variables, and save the printed text to
    individual files named uboot_env_<address>_exp.txt.  The _exp
    portion is only added when -E, --expand is used.

      depthcharge-find-env -E -o uboot_env -f mtdblock0.bin

    Save the raw binary environment instances, including metadata,
    and print only a summary of the extracted items. Files will
    be saved to individual files named uboot_env_<address>.bin

      depthcharge-find-env -o uboot_env -S -B -f mtdblock0.bin

depthcharge-mkenv

usage: depthcharge-mkenv [options] -f <infile> -o <outfile>

Make an environment that can be inserted into a target devices' NV storage

options:
  -h, --help            show this help message and exit
  -f <path>, --file <path>
                        Input file containing environment in text form.
  --arch <architecture>
                        CPU architecture.
  -o <path>, --outfile <path>
                        Output file for binary environment.
  -S SIZE, --size SIZE  Environment size. Must match target's CONFIG_ENV_SIZE.
  -F FLAGS, --flags FLAGS
                        Set a value for the flags bytes. It is not included
                        otherwise.
  -H, --no-hdr          Do not include header metadata (CRC word, flag).

 examples:

    Create an environment for a target whose U-Boot image was not built with
    CONFIG_SYS_REDUNDAND_ENV, and CONFIG_ENV_SIZE=0x2000.

        depthcharge-mkenv -S 0x2000 -f env.txt -o env.bin

    Create an environment for use on a target device whose U-Boot image
    was built with CONFIG_SYS_REDUNDAND_ENV and CONFIG_ENV_SIZE=0x10000.
    Note that the flags value must be greater than or equal to that of the
    active environment that is being replaced.

        depthcharge-mkenv -S 0x10000 -F 0x5 -f env.txt -o env.bin

    Convert 2 KiB environment, but do not prepend a CRC32
    checksum (nor a flag word).

        depthcharge-mkenv -S 2K -H -f env.txt -o env.bin

depthcharge-find-fdt

usage: depthcharge-find-fdt [options] -f <image file>

Search for instances of Flattened Device Tree blobs in a flash or memory dump

options:
  -h, --help            show this help message and exit
  -f <path>, --file <path>
                        Binary image to search
  -a <value>, --address <value>
                        Base address of the flash or memory dump. Results are
                        shown with respect to this address. Use the default of
                        0 if interested in relative offsets.
  --arch <architecture>
                        CPU architecture.
  -o <path>, --outfile <path>
                        Filename prefix for output file(s). No files are
                        written if this is not provided. A .dts or .dtb suffix
                        will be added to each file.
  --no-dts              Do not save .dts files.
  --no-dtb              Do not save .dtb files.

 examples:
  Print locations and sizes of FDT (DTB) instances found within an image.

    depthcharge-find-fdt --arch arm -f image.bin

  Extract FDT instances and save them to .dtb and .dts files named
  "image_<address>.[dts|dtb]". Additionally, specify a base address
  for the image.

    depthcharge-find-fdt --arch arm -a 0xa000 -f image.bin -o image

  Same as the above, but only save .dts files.

    depthcharge-find-fdt --arch arm -a 0xa000 -f image.bin -o image --no-dtb

depthcharge-stratagem

usage: depthcharge-stratagem -a <address> -f <infile> -s <type> -P <payload file> -o <outfile>

Create a Stratagem file, given a memory or flash dump and a desired payload.

options:
  -h, --help            show this help message and exit
  -a <value>, --address <value>
                        Base address of image.
  -f <path>, --file <path>
                        Input file containing memory or flash image
  -s <type>, --stratagem <type>
                        Type of the Stratagem to produce
  -P PAYLOAD, --payload PAYLOAD
                        File containing desired binary payload
  -o <path>, --outfile <path>
                        Output file to store produced Stratagem in
  -X <key>[=<value>], --extra <key>[=<value>]
                        Parameters passed to Hunter implementation used for
                        Stratagem creation.
  -l, --list            List supported Stratagem types and their -X
                        parameters.

notes:
    In Depthcharge parlance, a "Stratagem" is a sequence of meta-operations
    used to perform a desired operation, such as writing a specific value to
    a target region, abusing U-boot functionality not intended for this.

    In general, a subset of Depthcharge "Hunter" implementations are used
    to search for and produce these Stratagem.

    The available Hunter-specific settings that can be specified using -X/--extra
    can be found in the output of depthcharge-stratagem --list. Refer to the
    corresponding depthcharge.hunter.Hunter subclass for more information
    about these "extra" parameters, which correspond to the keyword arguments
    (**kwargs) their constructors and methods support.

    In general, use of this script will require an understanding of the
    corresponding Depthcharge Hunter and Stratagem API items.

example:
    Create a Depthcharge Stratagem for use with a CRC32MemoryWriter:
        depthcharge-stratagem -f dump.bin -s crc32 -P payload.bin -o stratagem.json

    Consider a situation where the above command reports a failure to produce a
    Stratagem. We can use the -X, --extra argument to both expend more memory when
    searching for a result (via `revlut_maxlen`) and permit longer-running deploy-time
    operations (via `max_iterations). Below is an example -X usage that would
    increase the defaults used by Depthcharge's CRC32MemoryWriter:

        -X revlut_maxlen=512,max_iterations=8192