If you found an active JTAG/SWD interface on a PCB it can be used to extract the firmware in some cases.
- Target Device
- JTAG/SWD Debugger ( like ST-Link, J-Link, or Bus Pirate.
- JTAG/SWD Header/Pinout (TCK, TMS, TDI, TDO for JTAG or SWDIO, SWCLK for SWD).
- Jumper Wires (to connect the debugger to the target device)
- Power Source
- Debugger-Tools: Open On-Chip Debugger (OpenOCD) or JLINK-Commander software for communicating with the JTAG/SWD interface.
- Drivers: Drivers for your specific debugger (e.g., ST-Link or J-Link drivers).
- Locate the JTAG or SWD pins on the target device. These are often labeled as follows:
- JTAG Pins:
- TCK (Test Clock)
- TMS (Test Mode Select)
- TDI (Test Data In)
- TDO (Test Data Out)
- GND (Ground)
- SWD Pins:
- SWDIO (Serial Wire Data Input/Output)
- SWCLK (Serial Wire Clock)
- GND (Ground)
- JTAG Pins:
- Consult the device datasheet or use tools like a multimeter or datasheets to map out the connections.
- Use jumper wires to connect the JTAG/SWD pins on the target device to the corresponding pins on the debugger:
- For JTAG: Connect TCK, TMS, TDI, TDO, and GND. (sometimes also RESET is needed)
- For SWD: Connect SWDIO, SWCLK, and GND.
- Make sure the connections are secure to avoid communication failures.
{% tabs %} {% tab title="OpenOCD" %}
- Install OpenOCD to manage communication between your debugger and the target device.
- GDB: Install GNU Debugger for low-level device control.
-
OpenOCD needs to be configured with the appropriate settings for your device. You can use pre-existing configuration files or create your own. For example:
-
Create a configuration file (
my_device.cfg
) that defines the target and interface:interface jlink transport select jtag source [find target/stm32f1x.cfg] ; for an STM32 device, adapt for others
-
Then, launch OpenOCD with:
-
openocd -f interface/jlink.cfg -f target/my_device.cfg
If the connection is correct we should see an output like this:
Open On-Chip Debugger 0.11.0 (2024-10-07)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : J-Link V10 compiled Aug 3 2024 15:23:43
Info : Hardware version: 10.10
Info : VTarget = 3.300 V
Info : clock speed 1000 kHz
Info : JTAG tap: stm32f429x.cpu tap/device found: 0x2ba01477 (mfg: 0x23b, part: 0xba01, ver: 0x2)
Info : stm32f429x.cpu: hardware has 8 breakpoints, 4 watchpoints
Info : starting gdb server for stm32f429x.cpu on 3333
Info : Listening on port 4444 for telnet connections
Info : Listening on port 3333 for gdb connections
We can see that we have two options to interact with OpenOCD: telnet and gdb
Telnet:
- Connect to OpenOCD via Telnet:
Open a separate terminal and connect to the OpenOCD server:
telnet localhost 4444
- Successful connection output:
Once connected, you should see something like this:
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
- Commands you can use via Telnet:
Here are a few example commands you might use via Telnet:
> reset halt # Reset and halt the target
> flash write_image erase firmware.bin 0x08000000 # Write firmware to flash memory
> mdw 0x08000000 # Read a memory word (32-bit) at the specified address
> mww 0x20000000 0x12345678 # Write a memory word (32-bit) to the specified address
> step # Step through the target's instructions
> resume # Continue execution
GDB:
# Launch GDB
arm-none-eabi-gdb
# Inside GDB, connect to OpenOCD via localhost on port 3333
(gdb) target remote localhost:3333
# Perform a reset and halt the target
(gdb) monitor reset halt
# Dump the firmware of the target
(gdb) dump binary memory <filename> <start-address> <end-address>
# example /Adjust the memory address range based on your target device’s memory map):
(gdb) dump binary memory firmware.bin 0x08000000 0x080FFFFF
# Continue execution
(gdb) continue
{% endtab %}
{% tab title="Jlink.exe" %}
-
Start J-Link Commander: Run the
JLinkExe
command to launch J-Link Commander.JLinkExe
-
Connect to the Target: You will need to specify the target device and the connection interface. For example, for an STM32F4 target connected via JTAG, you might see the following prompt:
SEGGER J-Link Commander V6.88b (Compiled Jul 22 2024 16:21:34) DLL version V6.88b, compiled Jul 22 2024 16:21:06 Connecting to J-Link via USB...O.K. Firmware: J-Link ARM V10 compiled Jul 3 2024 14:22:47 Hardware: V10.10 S/N: 123456789 License(s): RDI, FlashBP, GDB VTref=3.300V
Enter the target details:
Device> STM32F429ZI # Replace with your target device
Interface selection:
TIF> JTAG # Or SWD, depending on your setup
-
Halt the Target: To ensure a consistent firmware dump, halt the CPU:
halt
Expected output:
PC = 0x08000100, CycleCnt = 0x00000000 R0 = 0x20000000, R1 = 0x08001000, R2 = 0x20002000, R3 = 0x00000000 R4 = 0x00000000, R5 = 0x00000000, R6 = 0x00000000, R7 = 0x00000000 R8 = 0x00000000, R9 = 0x00000000, R10= 0x00000000, R11= 0x00000000 R12= 0x00000000, SP (R13)= 0x20002000, LR (R14)= 0x0800055F, PC = 0x08000100 CPSR = 0x60000010
-
Read Memory and Dump to a File: Use the
savebin
command to dump the firmware (Adjust the Offset and size depending on your targets memory map).savebin firmware_dump.bin 0x08000000 0x10000
firmware_dump.bin
: The name of the binary file where the memory content will be saved.0x08000000
: Start address of the firmware (for most STM32 devices, this is the start of flash memory).0x10000
: The size of the memory region to dump (in this case, 64KB).
$ JLinkExe
SEGGER J-Link Commander V6.88b (Compiled Jul 22 2024 16:21:34)
DLL version V6.88b, compiled Jul 22 2024 16:21:06
Connecting to J-Link via USB...O.K.
Firmware: J-Link ARM V10 compiled Jul 3 2024 14:22:47
Hardware: V10.10
S/N: 123456789
License(s): RDI, FlashBP, GDB
VTref=3.300V
Device> STM32F429ZI
TIF> JTAG
Speed> 1000 # Set speed to 1 MHz
JTAG speed set to 1000 kHz
Device "STM32F429ZI" selected.
J-Link> halt
PC = 0x08000100, CycleCnt = 0x00000000
R0 = 0x20000000, R1 = 0x08001000, R2 = 0x20002000, R3 = 0x00000000
R4 = 0x00000000, R5 = 0x00000000, R6 = 0x00000000, R7 = 0x00000000
R8 = 0x00000000, R9 = 0x00000000, R10= 0x00000000, R11= 0x00000000
R12= 0x00000000, SP (R13)= 0x20002000, LR (R14)= 0x0800055F, PC = 0x08000100
CPSR = 0x60000010
J-Link> savebin firmware_dump.bin 0x08000000 0x10000
Writing 65536 bytes to file firmware_dump.bin
O.K.
{% endtab %} {% endtabs %}
=> Jump to the Analyze Firmware section
https://sergioprado.blog/2020-02-20-extracting-firmware-from-devices-using-jtag/
https://wrongbaud.github.io/posts/jtag-hdd/