Android Hardware Reverse Engineering

OpenOCD Scripts for Android JTAG: Automating Firmware Extraction and Analysis

Google AdSense Native Placement - Horizontal Top-Post banner

Introduction to JTAG and Android Reverse Engineering

Joint Test Action Group (JTAG) is an industry-standard for verifying designs and testing printed circuit boards after manufacture. More importantly for reverse engineers, JTAG provides a powerful debug interface into System-on-Chips (SoCs), allowing direct access to CPU registers, memory, and peripherals. For Android devices, this translates into an invaluable tool for low-level analysis, firmware extraction, and even bypassing bootloader protections. While often disabled or restricted on production devices, JTAG access points (test points) can sometimes be found, especially on development boards or older/cheaper consumer devices.

Extracting firmware from an Android device often involves complex interactions with various flash memory types (eMMC, UFS, NAND). Traditional methods might rely on software exploits or hardware chip-off techniques. JTAG, coupled with OpenOCD (Open On-Chip Debugger), offers a non-invasive, programmatic way to read flash memory directly via the SoC’s debug interface. This article will guide you through setting up OpenOCD for Android JTAG, configuring common debug probes, and writing scripts to automate firmware extraction.

Setting Up Your JTAG Debugging Environment

Required Hardware and Software

  • JTAG Debug Probe: Common options include FT2232H-based adapters (e.g., Bus Pirate, various cheap Chinese clones), SEGGER J-Link, or Raspberry Pi acting as a JTAG adapter. For this guide, we’ll primarily focus on FT2232H-based adapters and Raspberry Pi due to their versatility and cost-effectiveness with OpenOCD.
  • Target Android Device/SoC: A device with exposed JTAG test points. Identifying these often requires schematics, board view files, or careful visual inspection and multimeter probing.
  • OpenOCD: The open-source on-chip debugger. Install it on your host system (Linux is preferred for ease of setup).
  • Soldering Equipment: Fine-tip soldering iron, flux, and thin wires to connect to test points.
  • Multimeter/Oscilloscope: Useful for identifying JTAG pins and verifying signals.

OpenOCD Installation

On Debian/Ubuntu based systems:

sudo apt update
sudo apt install openocd

For other distributions or if you need the latest version, compiling from source is recommended:

git clone http://git.code.sf.net/p/openocd/code openocd-code
cd openocd-code
./bootstrap
./configure --enable-ftdi --enable-jlink --enable-rpi --prefix=/usr/local
make -j$(nproc)
sudo make install

Connecting to the Android SoC via JTAG

Identifying JTAG Pins

The JTAG interface typically consists of five pins: TDI (Test Data In), TDO (Test Data Out), TCK (Test Clock), TMS (Test Mode Select), and TRST (Test Reset, optional). There’s also usually a VREF (voltage reference) and GND. Always verify the voltage levels (typically 1.8V or 3.3V) to avoid damaging your hardware.

Wiring the JTAG Probe

Connect your JTAG probe to the identified test points. For an FT2232H-based adapter, common pinouts are:

  • ADBUS0 -> TCK
  • ADBUS1 -> TMS
  • ADBUS2 -> TDI
  • ADBUS3 -> TDO
  • VREF and GND as appropriate

Ensure a stable power supply for your Android device.

OpenOCD Configuration for Android SoCs

OpenOCD requires configuration files to understand your JTAG interface, the target SoC, and its memory layout. These files are typically found in /usr/local/share/openocd/scripts/ (or similar, depending on your installation).

Interface Configuration (e.g., FT2232H)

Create a file, say interface.cfg:

# interface.cfg for an FT2232H based adapter
interface ftdi
ftdi_device_desc "Dual RS232-HS"
ftdi_vid_pid 0x0403 0x6010
ftdi_channel 0
ftdi_layout_init 0x0008 0x000b
ftdi_layout_signal nTRST -lvalue 0x0010
ftdi_layout_signal nSRST -lvalue 0x0020
jtag_rclk 1000

Adjust ftdi_vid_pid and ftdi_device_desc to match your specific adapter. Some adapters might need ftdi_layout_init and signal definitions adjusted. For Raspberry Pi as a JTAG adapter, use interface/raspberrypi-swd.cfg (or raspberrypi-native.cfg for native JTAG) and configure GPIOs.

Target Configuration (e.g., ARM Cortex-A)

Android SoCs often use ARM Cortex-A cores. You’ll need to include the relevant ARM target script and define the SoC specifics. For example, for a basic Cortex-A target:

# target.cfg for a generic Cortex-A based SoC
source [find target/armv7a.cfg]

# Configure work-area (optional, but good practice)
# This is a small piece of RAM OpenOCD can use for operations
# Typically, address is from internal SRAM, size varies.
# You MUST know your SoC's RAM layout.
# An example for a common address (check your SoC documentation!)
set _WORKAREA_ADDR 0x40000000
set _WORKAREA_SIZE 0x4000
armv7a configure -work-area-phys $_WORKAREA_ADDR -work-area-size $_WORKAREA_SIZE -work-area-backup 0

# Define the flash memory (e.g., eMMC/NAND/QSPI)
# This is crucial for extraction. You need to know the flash type and its base address.
# Example for a hypothetical eMMC at 0x0 base address:
# (This often requires a vendor-specific flash driver or direct memory access)
# For eMMC, you might interact with the eMMC controller registers directly or use 'nand' commands.
# Let's assume direct memory access for simplicity for now, treating it as raw memory.

Finding the exact armv7a.cfg or similar for your SoC’s core and then customizing it is key. The most challenging part is often figuring out the memory map (RAM, ROM, flash controller registers).

Automating Firmware Extraction

Once OpenOCD is configured and connected, you can interact with the target via its Telnet interface. Start OpenOCD:

openocd -f interface.cfg -f target.cfg

In a new terminal, connect via Telnet:

telnet localhost 4444

Identifying Flash Memory Regions

This is often the trickiest part without documentation. You might need to:

  • Check CPU Registers: Some SoCs expose memory map information in specific registers.
  • Try Common Addresses: Start probing common flash memory regions (e.g., 0x0, 0x10000000, 0x80000000).
  • Observe Boot Process: If you can halt the CPU during boot, you might see accesses to flash.

Reading Flash Memory with OpenOCD

Once you’ve identified a flash region, you can use the dump_image command. For example, to dump 16MB starting from address 0x0:

dump_image firmware.bin 0x0 0x1000000

This command will read data byte by byte or word by word from the specified address and save it to firmware.bin. For large flash sizes (e.g., 8GB eMMC), this can take a very long time. It’s often more efficient to dump partitions rather than the entire device.

OpenOCD Script for Automated Extraction

You can create an OpenOCD script (extraction.tcl) to automate dumping multiple regions or to handle specific flash types.

# extraction.tcl

# Source existing configs
source [find interface.cfg]
source [find target.cfg]

# Wait for target to halt upon connection
init
reset halt

# Define flash memory regions you want to extract
# These addresses and sizes are examples; replace with actual values for your SoC
set BL1_ADDR 0x0
set BL1_SIZE 0x40000 ; # 256KB
set BL2_ADDR 0x40000
set BL2_SIZE 0x40000 ; # 256KB
set KERNEL_ADDR 0x8000000
set KERNEL_SIZE 0x2000000 ; # 32MB

puts "Beginning firmware extraction..."

# Extract Bootloader Stage 1
puts "Dumping BL1 from 0x[format %X $BL1_ADDR] to bl1.bin..."
dump_image bl1.bin $BL1_ADDR $BL1_SIZE

# Extract Bootloader Stage 2
puts "Dumping BL2 from 0x[format %X $BL2_ADDR] to bl2.bin..."
dump_image bl2.bin $BL2_ADDR $BL2_SIZE

# Extract Kernel (example)
puts "Dumping Kernel from 0x[format %X $KERNEL_ADDR] to kernel.bin..."
dump_image kernel.bin $KERNEL_ADDR $KERNEL_SIZE

# Example of more complex extraction if a specific flash driver is available
# If your target config supports 'flash driver' operations (e.g. 'nand dump_bank'):
# puts "Attempting to dump NAND bank 0..."
# nand dump_bank 0 nand_full_dump.bin

puts "Firmware extraction complete."

# Resume execution or shutdown
# resume
shutdown

Run this script with OpenOCD:

openocd -f extraction.tcl

This script connects, halts the CPU, then sequentially dumps specified memory regions. You can extend it to include more partitions or even integrate custom Tcl procedures for more advanced interactions with flash controllers.

Challenges and Troubleshooting

  • Finding JTAG Pins: This is often the biggest hurdle. Look for common JTAG pin patterns, pull-up/down resistors, and test points near the SoC.
  • Correct Voltage Levels: Ensure your JTAG probe matches the SoC’s VREF (1.8V vs. 3.3V).
  • Clock Speed: JTAG jtag_rclk speed might need adjustment. Start low and increase gradually.
  • SoC Specifics: Every SoC has its quirks. Documentation (if available) is invaluable for memory maps and register definitions. Community forums and existing OpenOCD target configurations for similar SoCs can provide clues.
  • Power Management: Ensure the device is properly powered and doesn’t shut down during the process.
  • Intermittent Connection: Bad soldering, incorrect wiring, or ground loops can cause connection issues.

Conclusion

OpenOCD, combined with JTAG, provides a powerful and often overlooked pathway for Android firmware extraction and analysis. While identifying and wiring JTAG points can be challenging, the ability to directly access the SoC’s memory and CPU offers unparalleled insight into the device’s low-level operation. By mastering OpenOCD configurations and scripting, reverse engineers can automate complex data acquisition tasks, paving the way for deeper security analysis, vulnerability research, and custom firmware development. This methodology serves as a cornerstone for advanced hardware reverse engineering, moving beyond software-only approaches to unlock the true potential of device understanding.

Android Mobile Specs & Compare Directory

Are you researching mobile hardware properties, processor SoCs, GPU chipsets, or RAM configurations? Access our complete specs catalog to compare up to 5 devices side-by-side!

Compare Devices Specs →
Google AdSense Inline Placement - Content Footer banner