Emil's Projects & Reviews

OpenHardware & OpenSource

Unbricking a SEGGER J-Link v9 debug probe 15th May 2019
J-Link Genuine Segger


Case



PCB

Some time ago my SEGGER J-Link v9 stopped working. I wasn't sure what I did but I suspected it was a hardware failure. I've opened it and checked voltages with a multimeter and I couldn't find anything wrong. Then I've noticed it was using a familiar processor (STM32F205RC) and a PCB header which after I've reversed it turned out to be a JTAG connector:

I've soldered wires and connected my STLinkV2 and it was nothing wrong with the CPU, it was just empty! I have then tried to reflash it with an old version which I have found on the net and after programming my J-Link came back to life.

J-Link V9 memory map
TypeAddressLength
IVT0x080000000x200
Bootloader0x080002000x3e00
Signature0x0800b7000x100
Serial Nr0x0800bf004
Licenses0x0800bf200xc0
Config Data0x0800c0000x100
User Licenses0x0800c1000x3f00
FW IVT0x080100000x200
FW Code0x080102000x2fdfe
FW CRC160x0803fffe2
Code in RAM0x200000000x30d0
Data in RAM0x200030d00x10f30

The firmware which I have found had no bootloader so I had to program it at address 0x08010000 but at the same time I had to copy the interrupt vector table (IVT) also to 0x08000000 so that the firmware reset vector points to the main firmware.

When I've tried to use it the software was automatically trying to update it and since it had no bootloader it was failing.

Connecting to J-Link via USB...Updating firmware:  J-Link V9 compiled Feb 22 2222 22:22:22
Replacing firmware: J-Link V9 compiled May 17 2119 09:50:41
FAILED: Failed to activate bootloader (timeout)

I have later discovered that the software was comparing the version in the J-Link with the latest version available inside the libjlinkarm library. The version string looks like this "J-Link V9 compiled May 17 2019 09:50:41". There are no numbers but instead the date is interpreted and compared. There are two such version strings, one for the bootloader and one for the firmware.

Bootloader version0x8000210
FW version0x8010210

To make the J-Link work without a bootloader all it was needed was to set the date in advance for the FW version and then the software wasn't trying to update it anymore. But I also wanted to have a relatively recent firmware so I've started to investigate where was this firmware stored and how could I extract it from the J-Link software.

It turned out that all the latest firmware versions for the SEGGER products are stored (some compressed, some not) in the libjlinkarm.so library: File: firmwares.txt
[ 0] [0x005400->0x005400] J-Trace ARM Rev.1
[ 1] [0x00f5e6->0x030000] J-Trace ARM CS Rev.1
[ 2] [0x014895->0x03c000] J-Trace Cortex-M Rev.3 
[ 3] [0x039aa9->0x100000] J-Trace PRO V1 Cortex-M 
[ 4] [0x000000->0x100000] J-Trace PRO V2 Cortex  (JTrace_PRO_V2_Cortex.bin)
[ 5] [0x000000->0x100000] J-Trace PRO V2 Cortex-M  (JTrace_PRO_V2_CortexM.bin)
[ 6] [0x000000->0x190000] J-Trace PRO V3 Cortex  (JTrace_PRO_V3_Cortex.bin)
[ 7] [0x000000->0x190000] J-Trace PRO V3 Cortex-M  (JTrace_PRO_V3_CortexM.bin)
[ 8] [0x00e049->0x03c000] J-Link Ultra Rev.1 
[ 9] [0x02f59b->0x070000] J-Link Ultra V4 
[10] [0x000000->0x100000] J-Link Ultra V5  (JLink_ULTRA_V5.bin)
[11] [0x000000->0x190000] J-Link Ultra V5-1  (JLink_ULTRA_V5_1.bin)
[12] [0x015e28->0x030000] J-Link V9 
[13] [0x02c49a->0x078000] J-Link V10 
[14] [0x000000->0x078000] J-Link V11  (JLink_V11.bin)
[15] [0x00f042->0x018800] J-Link EDU Mini V1 
[16] [0x000000->0x078000] J-Link WiFi-V1  (JLink_WiFi_V1.bin)
[17] [0x005400->0x005400] Rev.5
[18] [0x006e00->0x006e00] J-Link ARM V6 
[19] [0x006e00->0x006e00] J-Link ARM V7 
[20] [0x00dc00->0x00dc00] J-Link ARM V8 
[21] [0x00dc00->0x00dc00] J-Link ARM-OB SAM7 
[22] [0x008094->0x00dc00] J-Link OB RX200 V1 
[23] [0x00d89c->0x00dc00] J-Link ARM Lite V8 
[24] [0x0155d0->0x018800] J-Link Lite V9 
[25] [0x00a7d8->0x00dc00] J-Link Lite-Cortex-M V8 
[26] [0x01047c->0x018800] J-Link Lite-Cortex-M V9 
[27] [0x00854c->0x00dc00] J-Link LITE-Cortex-M-5V 
[28] [0x000000->0x019c00] J-Link Lite Synergy  (JLink_Lite_Synergy.bin)
[29] [0x005000->0x005000] J-Link ARM-LPC Rev.1 
[30] [0x018000->0x018000] J-Link ARM-LPC2146 Rev.2 
[31] [0x008980->0x020000] J-Link Lite-XMC4000 Rev.1 
[32] [0x00f6ec->0x020000] J-Link Lite-XMC4200 Rev.1 
[33] [0x00d378->0x018000] J-Link Lite-ADI Rev.1 
[34] [0x010000->0x010000] J-Link Lite-LPC Rev.1 
[35] [0x006000->0x008000] J-Link ARM-STR711
[36] [0x005c00->0x005c00] J-Link ARM-OB STM32 
[37] [0x00b800->0x00b800] J-Link Lite-STM32 Rev.1 
[38] [0x006e00->0x006e00] J-Link CF V1 
[39] [0x00b800->0x00b800] J-Link Lite-FSL V1 
[40] [0x0387c4->0x060000] J-Link / Flasher ATE Mainboard V1 
[41] [0x052b44->0x060000] J-Link / Flasher ATE Module V1 
[42] [0x015b4a->0x000000] J-Link ARM / Flasher ARM V2 
[43] [0x021482->0x000000] J-Link ARM / Flasher ARM V3 
[44] [0x03e292->0x000000] J-Link ARM / Flasher ARM V4 
[45] [0x07cb9e->0x000000] J-Link / Flasher ARM V5 
[46] [0x02c516->0x000000] J-Link / Flasher Portable V1 
[47] [0x03bf3e->0x000000] J-Link / Flasher Portable Plus V1 
[48] [0x01fa39->0x000000] J-Link RX / Flasher RX V1 
[49] [0x038f66->0x000000] J-Link RX / Flasher RX V4 
[50] [0x01deff->0x000000] J-Link PPC / Flasher PPC V1 
[51] [0x03731c->0x000000] J-Link PPC / Flasher PPC V4 
[52] [0x0445a8->0x000000] J-Link PRO / Flasher PRO V4 
[53] [0x088dc5->0x000000] J-Link / Flasher PRO V5 
[54] [0x075281->0x000000] J-Link / Flasher Compact V5 
[55] [0x0132ec->0x030000] J-Link ARM-Pro V1.x 
[56] [0x01403b->0x030000] J-Link ARM-Pro V3.x 
[57] [0x02f58e->0x070000] J-Link Pro V4 
[58] [0x000000->0x100000] J-Link Pro V5  (JLink_PRO_V5.bin)
[59] [0x000000->0x190000] J-Link Pro V5-1  (JLink_PRO_V5_1.bin)
[60] [0x004f30->0x038000] J-Link OB RX6xx V1 
[61] [0x0096c2->0x038000] J-Link OB RX621-ARM-SWD V1 
[62] [0x00488d->0x038000] J-Link OB-RX621-RX1xx V1 
[63] [0x00b9ec->0x039000] J-Link MCU-Link V1 
[64] [0x000000->0x018800] J-Link OB-K22-Cortex-A  (JLink_OB_K22_CortexA.bin)
[65] [0x000000->0x018800] J-Link OB-K22-Cortex-M  (JLink_OB_K22_CortexM.bin)
[66] [0x000000->0x018800] J-Link OB-K22-RISCV  (JLink_OB_K22_RISCV.bin)
[67] [0x000000->0x01a000] J-Link OB-K22-NordicSemi  (JLink_OB_K22_NordicSemi.bin)
[68] [0x000000->0x018800] J-Link OB-K22-Qorvo  (JLink_OB_K22_Qorvo.bin)
[69] [0x0172b0->0x018800] J-Link OB-K22-SiFive 
[70] [0x000000->0x0f9000] J-Link OB-nRF5340-NordicSemi  (JLink_OB_nRF5340_NordicSemi.bin)
[71] [0x000000->0x019c00] J-Link OB-S124  (JLink_OB_S124.bin)
[72] [0x012904->0x016e00] J-Link OB-SAM3U128-V2-NordicSemi 
[73] [0x011d80->0x01c000] J-Link OB-SAM3U128 V1 
[74] [0x015da4->0x019e00] J-Link OB-SAM3U128 V3 
[75] [0x000000->0x01b800] J-Link OB-STM32F103 V1  (JLink_OB_STM32F103.bin)
[76] [0x008153->0x00b800] J-Link OB-STM32F072-CortexAR 
[77] [0x0080c0->0x00b800] J-Link OB-STM32F072-CortexM 
[78] [0x00bf5d->0x01a000] J-Link OB-STM32F072-128KB-CortexM 
[79] [0x009114->0x01c000] J-Link OB-MB9AF312K-Spansion 
[80] [0x00c3e9->0x0f0000] J-Link OB-STM32F4-Arduino V1 
[81] [0x00d16c->0x036000] J-Link OB-RA4M2 

Finding the above table in the library was easy but unfortunately some of the firmwares are compressed (seems that the ZIP format is used) and it has headers and tables at various address and it is not easy to decompress and extract the firmware.

Instead I've took advantage of the dlopen function (in Linux) and loaded that library in my software. The library exports the JLINK_GetEmbeddedFWString function which uncompresses the firmware to read the date string. I then intercept the malloc function and simply call that extract function and dump the memory allocated by malloc before the free is called. This allows me to extract any of the stored firmwares.

After version 720 the firmware date code was changed and it only decompresses the first 1 KB of code. My quick solution to this was to restore the previous behaviour and expand the entire firmware. If you follow the JLINK_GetEmbeddedFWString function you will find two calls to malloc, The size parameter of the second call is in r12d (in linux x64 code) and I've restored that value to the actual decompressed size as ilustrated in the assembler code bellow (one assembler instruction is replaced in libjlinkarm.so): File: patch
------------------- Original Code ----------------------------------------------------
8B 78 24	      mov     edi, [rax+24h]
45 8D A6 7F 04 00 00  lea     r12d, [r14+47Fh]
48 8D 35 7E 12 1F 00  lea     rsi, aEmu_firmwareCo ; "EMU_Firmware: Compress workspace"
41 81 E4 00 FC FF FF  and     r12d, 0FFFFFC00h
01 FF		      add     edi, edi
E8 A0 60 0F 00	      call    cc_malloc
48 8D 35 9F 0A 1F 00  lea     rsi, aEmu_firmwareFw ; "EMU_Firmware: FW image buffer"
44 89 E7	      mov     edi, r12d
49 89 C7	      mov     r15, rax
E8 8E 60 0F 00	      call    cc_malloc
49 89 C5	      mov     r13, rax
-------------------- Patched Code (mov r12d) -----------------------------------------
8B 78 24	      mov     edi, [rax+24h]
45 8D A6 7F 04 00 00  lea     r12d, [r14+47Fh]
48 8D 35 7E 12 1F 00  lea     rsi, aEmu_firmwareCo ; "EMU_Firmware: Compress workspace"
44 8B 60 1C	      mov     r12d, [rax+1Ch]  <-------- replaced instruction
90		      nop
90		      nop
90		      nop
01 FF		      add     edi, edi
E8 A0 60 0F 00	      call    cc_malloc
48 8D 35 9F 0A 1F 00  lea     rsi, aEmu_firmwareFw ; "EMU_Firmware: FW image buffer"
44 89 E7	      mov     edi, r12d
49 89 C7	      mov     r15, rax
E8 8E 60 0F 00	      call    cc_malloc
49 89 C5	      mov     r13, rax
-------------------- Example: Differences for JLink_Linux_V758b_x86_64 ----------------
libjlinkarm.so.7.58.2
002AAE52: 41 44
002AAE53: 81 8B
002AAE54: E4 60
002AAE55: 00 1C
002AAE56: FC 90
002AAE57: FF 90
002AAE58: FF 90

This is automatically done by dump_segger_fw in memory after it loads the libjlinkarm.so (this may break in future versions). Without patching your .dll/.so library the dump_segger_fw program will only be able to extract the plain uncompressed firmwares.

You can get the dump_segger_fw source code and linux executable. This program also prompts for a serial number and builds a complete flash image with the correct CRC16 ready to be programmed (but only for the J-Link v9 probe). If you also have a previously extracted bootloader file jlink_v9_bootloader.bin (more about this later) then the bootloader is included as part of the image, otherwise the IVT copy trick is used. The serial number of a probe can be any 4 bytes number but in practice the decimal version of this serial usually includes the hardware revision of your probe. Example: for hardware revision 9.4 the serial number is in the format 26940xxxx.

J-Link Serial Number

I have used my restored J-Link probe with the date set in advance for a while but then I've seen a colleague using a chinese clone which was updating normally. This intrigued me because that meant the clone had a bootloader, which is not present anywhere in the SEGGER software, it is only programmed once at manufacture time.

J-Link Segger Clones
Case (1)
PCB (1)
Case (2)
PCB (2)

I have found these schematics for the chinese clones: JlinkV93_sch and JlinkV95_sch

I've quickly purchased a clone myself and hooked the STLinkV2 to it. Then surprise, the flash memory was protected. I could stop the processor and dump its RAM (even modify it) but as soon as I was trying to read from the flash memory (either directly or by inserting code in RAM) I was getting CPU exceptions. Dumping the RAM turned up useful because a small part of the flash is expanded and executed from RAM (when upgrading or adding licenses) and also I had a snapshot of the variable values.

My first idea of extracting the bootloader was to overwrite the firmware with my own program which will then dump the bootloader to USB. I've made a project J-Link-Dump-Bootloader which I've tested on my original J-Link which had no valid bootloader just to make sure it was working properly (and it did). Then I've used my dump_segger_fw (compiled with a LIB_OVERLAY define) to overlay my created binary in the libjlinkarm library and let the SEGGER software do the update. Unfortunately this didn't work and I had to manually restore the main firmware back. I have later found out that this was failing because the firmware should have been padded to the full length (0x30000) which I didn't know at the time.

Connecting to J-Link via USB...Updating firmware:  J-Link V9 compiled Feb 22 2222 22:22:22
Replacing firmware: J-Link V9 compiled May 17 2019 09:50:41
FAILED: Communication timed out: Requested 1 bytes, received 0 bytes !
Communication timed out after firmware update
I've then captured the USB transactions during a firmware update: File: USB-Capture_Update_Firmware.html

Type Title Device Endpoint Direction Status Size Data Text
Bus state Reset 1.4 seconds 0
Bus state Suspended 143.0 milliseconds 0
Bus state Reset 54.8 milliseconds 0
Bus state High speed handshake 0
Container GetDescriptor (Device) 0 (16) 0 In OK 18 12 01 00 02
Transaction SETUP 0 (16) 0 Out ACK 8 80 06 00 01
Transaction IN 0 (16) 0 In ACK 18 12 01 00 02
Transaction OUT 0 (16) 0 Out ACK 0
Bus state Reset 54.8 milliseconds 0
Bus state High speed handshake 0
Container SetAddress (16) 0 (16) 0 Out OK 0
Transaction SETUP 0 (16) 0 Out ACK 8 00 05 10 00
Transaction IN 0 (16) 0 In ACK 0
Container GetDescriptor (Device) 16 0 In OK 18 12 01 00 02
Transaction SETUP 16 0 Out ACK 8 80 06 00 01
Transaction IN 16 0 In ACK 18 12 01 00 02
Transaction OUT 16 0 Out ACK 0
Container GetDescriptor (Device qualifier) 16 0 In STALLED 0
Transaction SETUP 16 0 Out ACK 8 80 06 00 06
Transaction IN 16 0 In STALL 0
Container GetDescriptor (Device qualifier) 16 0 In STALLED 0
Transaction SETUP 16 0 Out ACK 8 80 06 00 06
Transaction IN 16 0 In STALL 0
Container GetDescriptor (Device qualifier) 16 0 In STALLED 0
Transaction SETUP 16 0 Out ACK 8 80 06 00 06
Transaction IN 16 0 In STALL 0
Container GetDescriptor (Configuration) 16 0 In OK 9 09 02 62 00
Transaction SETUP 16 0 Out ACK 8 80 06 00 02
Transaction IN 16 0 In ACK 9 09 02 62 00
Transaction OUT 16 0 Out ACK 0
Container GetDescriptor (Configuration) 16 0 In OK 98 09 02 62 00
Transaction SETUP 16 0 Out ACK 8 80 06 00 02
Transaction IN 16 0 In ACK 64 09 02 62 00
Transaction IN 16 0 In ACK 34 02 40 00 01
Transaction OUT 16 0 Out ACK 0
Container GetDescriptor (String lang IDs) 16 0 In OK 4 04 03 09 04
Transaction SETUP 16 0 Out ACK 8 80 06 00 03
Transaction IN 16 0 In ACK 4 04 03 09 04
Transaction OUT 16 0 Out ACK 0
Container GetDescriptor (String iProduct) 16 0 In OK 14 0E 03 4A 00 J.-.L.i.n.k.
Transaction SETUP 16 0 Out ACK 8 80 06 02 03
Transaction IN 16 0 In ACK 14 0E 03 4A 00 J.-.L.i.n.k.
Transaction OUT 16 0 Out ACK 0
Container GetDescriptor (String iManufacturer) 16 0 In OK 14 0E 03 53 00 S.E.G.G.E.R.
Transaction SETUP 16 0 Out ACK 8 80 06 01 03
Transaction IN 16 0 In ACK 14 0E 03 53 00 S.E.G.G.E.R.
Transaction OUT 16 0 Out ACK 0
Container GetDescriptor (String iSerialNumber) 16 0 In OK 26 1A 03 30 00 0.0.0.5.8.3.6.4.8.1.2.5.
Transaction SETUP 16 0 Out ACK 8 80 06 03 03
Transaction IN 16 0 In ACK 26 1A 03 30 00 0.0.0.5.8.3.6.4.8.1.2.5.
Transaction OUT 16 0 Out ACK 0
Container SetConfiguration (1) 16 0 Out OK 0
Transaction SETUP 16 0 Out ACK 8 00 09 01 00
Transaction IN 16 0 In ACK 0
Container GetDescriptor (String iConfiguration) 16 0 In OK 28 1C 03 43 00 C.o.n.f.i.g.u.r.a.t.i.o.n.
Transaction SETUP 16 0 Out ACK 8 80 06 04 03
Transaction IN 16 0 In ACK 28 1C 03 43 00 C.o.n.f.i.g.u.r.a.t.i.o.n.
Transaction OUT 16 0 Out ACK 0
Container GetDescriptor (String iInterface) 16 0 In OK 8 08 03 43 00 C.D.C.
Transaction SETUP 16 0 Out ACK 8 80 06 05 03
Transaction IN 16 0 In ACK 8 08 03 43 00 C.D.C.
Transaction OUT 16 0 Out ACK 0
Container SetLineCoding 16 0 Out OK 7 80 25 00 00
Transaction SETUP 16 0 Out ACK 8 21 20 00 00
Transaction OUT 16 0 Out ACK 7 80 25 00 00
Transaction IN 16 0 In ACK 0
Container GetDescriptor (String iInterface) 16 0 In OK 38 26 03 43 00 &.C.D.C. .D.A.T.A. .i.n.t.e.r.f.a.c.e.
Transaction SETUP 16 0 Out ACK 8 80 06 06 03
Transaction IN 16 0 In ACK 38 26 03 43 00 &.C.D.C. .D.A.T.A. .i.n.t.e.r.f.a.c.e.
Transaction OUT 16 0 Out ACK 0
Container GetDescriptor (String iInterface) 16 0 In OK 30 1E 03 42 00 B.U.L.K. .i.n.t.e.r.f.a.c.e.
Transaction SETUP 16 0 Out ACK 8 80 06 07 03
Transaction IN 16 0 In ACK 30 1E 03 42 00 B.U.L.K. .i.n.t.e.r.f.a.c.e.
Transaction OUT 16 0 Out ACK 0
Container OUT Bulk transfer 16 3 Out OK 1 01
Transaction OUT 16 3 Out ACK 1 01
Container IN Bulk transfer 16 3 In OK 2 70 00
Transaction IN 16 3 In ACK 2 70 00
Container IN Bulk transfer 16 3 In OK 112 4A 2D 4C 69 J-Link V9 compiled May 17 2019 09:50:41.Copyright 2003-2012 SEGGER: www.segger.com
Transaction IN 16 3 In ACK 64 4A 2D 4C 69 J-Link V9 compiled May 17 2019 09:50:41.Copyright 2003-2012 SEGG
Transaction IN 16 3 In ACK 48 45 52 3A 20 ER: www.segger.com
Container OUT Bulk transfer 16 3 Out OK 1 01
Transaction OUT 16 3 Out ACK 1 01
Container IN Bulk transfer 16 3 In OK 2 70 00
Transaction IN 16 3 In ACK 2 70 00
Container IN Bulk transfer 16 3 In OK 112 4A 2D 4C 69 J-Link V9 compiled May 17 2019 09:50:41.Copyright 2003-2012 SEGGER: www.segger.com
Transaction IN 16 3 In ACK 64 4A 2D 4C 69 J-Link V9 compiled May 17 2019 09:50:41.Copyright 2003-2012 SEGG
Transaction IN 16 3 In ACK 48 45 52 3A 20 ER: www.segger.com
Container OUT Bulk transfer 16 3 Out OK 1 01
Transaction OUT 16 3 Out ACK 1 01
Container IN Bulk transfer 16 3 In OK 2 70 00
Transaction IN 16 3 In ACK 2 70 00
Container IN Bulk transfer 16 3 In OK 112 4A 2D 4C 69 J-Link V9 compiled May 17 2019 09:50:41.Copyright 2003-2012 SEGGER: www.segger.com
Transaction IN 16 3 In ACK 64 4A 2D 4C 69 J-Link V9 compiled May 17 2019 09:50:41.Copyright 2003-2012 SEGG
Transaction IN 16 3 In ACK 48 45 52 3A 20 ER: www.segger.com
Container OUT Bulk transfer 16 3 Out OK 1 06
Transaction OUT 16 3 Out ACK 1 06
Container IN Bulk transfer 16 3 In OK 1 01
Transaction IN 16 3 In ACK 1 01
Bus state Reset 70.9 milliseconds 0
Bus state High speed handshake 0
Bus state Suspended 145.1 milliseconds 0
Bus state Reset 54.8 milliseconds 0
Bus state High speed handshake 0
Container GetDescriptor (Device) 0 (14) 0 In OK 18 12 01 00 02
Transaction SETUP 0 (14) 0 Out ACK 8 80 06 00 01
Transaction IN 0 (14) 0 In ACK 18 12 01 00 02
Transaction OUT 0 (14) 0 Out ACK 0
Bus state Reset 54.8 milliseconds 0
Bus state High speed handshake 0
Container SetAddress (14) 0 (14) 0 Out OK 0
Transaction SETUP 0 (14) 0 Out ACK 8 00 05 0E 00
Transaction IN 0 (14) 0 In ACK 0
Container GetDescriptor (Device) 14 0 In OK 18 12 01 00 02
Transaction SETUP 14 0 Out ACK 8 80 06 00 01
Transaction IN 14 0 In ACK 18 12 01 00 02
Transaction OUT 14 0 Out ACK 0
Container GetDescriptor (Device qualifier) 14 0 In STALLED 0
Transaction SETUP 14 0 Out ACK 8 80 06 00 06
Transaction IN 14 0 In STALL 0
Container GetDescriptor (Device qualifier) 14 0 In STALLED 0
Transaction SETUP 14 0 Out ACK 8 80 06 00 06
Transaction IN 14 0 In STALL 0
Container GetDescriptor (Device qualifier) 14 0 In STALLED 0
Transaction SETUP 14 0 Out ACK 8 80 06 00 06
Transaction IN 14 0 In STALL 0
Container GetDescriptor (Configuration) 14 0 In OK 9 09 02 20 00
Transaction SETUP 14 0 Out ACK 8 80 06 00 02
Transaction IN 14 0 In ACK 9 09 02 20 00
Transaction OUT 14 0 Out ACK 0
Container GetDescriptor (Configuration) 14 0 In OK 32 09 02 20 00
Transaction SETUP 14 0 Out ACK 8 80 06 00 02
Transaction IN 14 0 In ACK 32 09 02 20 00
Transaction OUT 14 0 Out ACK 0
Container GetDescriptor (String lang IDs) 14 0 In OK 4 04 03 09 04
Transaction SETUP 14 0 Out ACK 8 80 06 00 03
Transaction IN 14 0 In ACK 4 04 03 09 04
Transaction OUT 14 0 Out ACK 0
Container GetDescriptor (String iProduct) 14 0 In OK 14 0E 03 4A 00 J.-.L.i.n.k.
Transaction SETUP 14 0 Out ACK 8 80 06 02 03
Transaction IN 14 0 In ACK 14 0E 03 4A 00 J.-.L.i.n.k.
Transaction OUT 14 0 Out ACK 0
Container GetDescriptor (String iManufacturer) 14 0 In OK 14 0E 03 53 00 S.E.G.G.E.R.
Transaction SETUP 14 0 Out ACK 8 80 06 01 03
Transaction IN 14 0 In ACK 14 0E 03 53 00 S.E.G.G.E.R.
Transaction OUT 14 0 Out ACK 0
Container GetDescriptor (String iSerialNumber) 14 0 In OK 26 1A 03 30 00 0.0.0.5.8.3.6.4.8.1.2.5.
Transaction SETUP 14 0 Out ACK 8 80 06 03 03
Transaction IN 14 0 In ACK 26 1A 03 30 00 0.0.0.5.8.3.6.4.8.1.2.5.
Transaction OUT 14 0 Out ACK 0
Container SetConfiguration (1) 14 0 Out OK 0
Transaction SETUP 14 0 Out ACK 8 00 09 01 00
Transaction IN 14 0 In ACK 0
Container OUT Bulk transfer 14 1 Out OK 1 01
Transaction OUT 14 1 Out ACK 1 01
Container IN Bulk transfer 14 1 In OK 2 70 00
Transaction IN 14 1 In ACK 2 70 00
Container IN Bulk transfer 14 1 In OK 112 4A 2D 4C 69 J-Link V9 compiled Oct 12 2012 BTL .Copyright 2003-2012 SEGGER: www.segger.com
Transaction IN 14 1 In ACK 64 4A 2D 4C 69 J-Link V9 compiled Oct 12 2012 BTL .Copyright 2003-2012 SEGG
Transaction IN 14 1 In ACK 48 45 52 3A 20 ER: www.segger.com
Container OUT Bulk transfer 14 1 Out OK 1 06
Transaction OUT 14 1 Out ACK 1 06
Container IN Bulk transfer 14 1 In OK 1 00
Transaction IN 14 1 In ACK 1 00
Container OUT Bulk transfer 14 1 Out OK 2 F8 11
Transaction OUT 14 1 Out ACK 2 F8 11
Container OUT Bulk transfer 14 1 Out OK 4600 00 80 01 20 J-Link V9 compiled Feb 22 2222 22:22:22.Copyright 2003-2012 SEGGER: www.segger.com
Transaction OUT 14 1 Out ACK 64 00 80 01 20
Transaction OUT 14 1 Out ACK 64 B9 11 01 08
Transaction OUT 14 1 Out ACK 64 B9 11 01 08
Transaction OUT 14 1 Out ACK 64 B9 11 01 08
Transaction OUT 14 1 Out ACK 64 B9 11 01 08
Transaction OUT 14 1 Out ACK 64 B9 11 01 08
Transaction OUT 14 1 Out ACK 64 B9 11 01 08
Transaction OUT 14 1 Out ACK 64 FF FF FF FF
Transaction OUT 14 1 Out ACK 64 00 00 00 00 J-Link V9 compiled Feb 22 2222 22:22:22.Copyrigh
Transaction OUT 14 1 Out ACK 64 74 20 32 30 t 2003-2012 SEGGER: www.segger.com
Transaction OUT 14 1 Out ACK 64 FF FF FF FF
Transaction OUT 14 1 Out ACK 64 FF FF FF FF
Transaction OUT 14 1 Out ACK 64 03 48 04 4B
Transaction OUT 14 1 Out ACK 64 10 B5 06 4C
Transaction OUT 14 1 Out ACK 64 08 00 00 20
Transaction OUT 14 1 Out ACK 64 EC 11 01 08
Transaction OUT 14 1 Out ACK 64 2D E9 F0 47
Transaction OUT 14 1 Out ACK 64 08 F9 21 0C
Transaction OUT 14 1 Out ACK 64 80 F0 07 81
Transaction OUT 14 1 Out ACK 64 83 F7 00 2F
Transaction OUT 14 1 Out ACK 64 F8 FE 08 FB
Transaction OUT 14 1 Out ACK 64 00 F1 FF 33
Transaction OUT 14 1 Out ACK 64 09 FB 08 FA
Transaction OUT 14 1 Out ACK 64 89 B2 41 EA
Transaction OUT 14 1 Out ACK 64 22 FA 07 F3
Transaction OUT 14 1 Out ACK 64 02 F4 07 D9
Transaction OUT 14 1 Out ACK 64 0E 01 40 EA
Transaction OUT 14 1 Out ACK 64 02 0E 2B 44
Transaction OUT 14 1 Out ACK 64 CD E9 02 44
Transaction OUT 14 1 Out ACK 64 CD E9 06 44
Transaction OUT 14 1 Out ACK 64 18 63 18 6B
Transaction OUT 14 1 Out ACK 64 CD E9 05 35
Transaction OUT 14 1 Out ACK 64 00 F0 7A FB
Transaction OUT 14 1 Out ACK 64 01 22 4F F4
Transaction OUT 14 1 Out ACK 64 70 47 00 BF
Transaction OUT 14 1 Out ACK 64 70 47 00 BF
Transaction OUT 14 1 Out ACK 64 1A 60 1A 68
Transaction OUT 14 1 Out ACK 64 20 00 00 20
Transaction OUT 14 1 Out ACK 64 0C 02 04 2A
Transaction OUT 14 1 Out ACK 64 9F 07 39 D4
Transaction OUT 14 1 Out ACK 64 01 F0 0C 01
Transaction OUT 14 1 Out ACK 64 29 D0 91 68
Transaction OUT 14 1 Out ACK 64 23 69 21 F0
Transaction OUT 14 1 Out ACK 64 52 D8 6B 6F
Transaction OUT 14 1 Out ACK 64 D0 E7 00 23
Transaction OUT 14 1 Out ACK 64 22 7A 1A 70
Transaction OUT 14 1 Out ACK 64 F8 00 8A 40
Transaction OUT 14 1 Out ACK 64 7F F5 1A AF
Transaction OUT 14 1 Out ACK 64 B2 D8 2B 68
Transaction OUT 14 1 Out ACK 64 01 3A 43 EA
Transaction OUT 14 1 Out ACK 64 8B 68 03 F0
Transaction OUT 14 1 Out ACK 64 08 BD 08 48
Transaction OUT 14 1 Out ACK 64 8B 42 01 D0
Transaction OUT 14 1 Out ACK 64 0D 46 20 D5
Transaction OUT 14 1 Out ACK 64 B3 EB 82 0F
Transaction OUT 14 1 Out ACK 64 5D FF 14 4B
Transaction OUT 14 1 Out ACK 64 9E 03 A8 D4
Transaction OUT 14 1 Out ACK 64 00 ED 00 E0
Transaction OUT 14 1 Out ACK 64 D2 B2 0A DB
Transaction OUT 14 1 Out ACK 64 70 47 00 BF
Transaction OUT 14 1 Out ACK 64 00 25 D1 F8
Transaction OUT 14 1 Out ACK 64 02 EA 0A 0A
Transaction OUT 14 1 Out ACK 64 03 F1 80 43
Transaction OUT 14 1 Out ACK 64 00 F0 83 80
Transaction OUT 14 1 Out ACK 64 04 30 A7 03
Transaction OUT 14 1 Out ACK 64 6F 00 BA 40
Transaction OUT 14 1 Out ACK 64 46 EA 0C 06
Transaction OUT 14 1 Out ACK 64 03 27 07 FA www.segg
Transaction OUT 14 1 Out ACK 64 65 72 2E 63 er.com.Copyright (c) 2003 - 2012 SEGGER Microcontroller. May be
Transaction OUT 14 1 Out ACK 64 75 73 65 64 used in original J-Links and products manufactured under license
Transaction OUT 14 1 Out ACK 64 20 6F 6E 6C only
Transaction OUT 14 1 Out ACK 56 F8 BC 08 BC
Container ClearFeature (Endpoint 1 OUT, Halt) 14 0 Out OK 0
Transaction SETUP 14 0 Out ACK 8 02 01 00 00
Transaction IN 14 0 In ACK 0

You can see that the device is enumerated as "J-Link Plus" then command "01" is send to retrieve the version string. If there is a newer version available then command "06" is sent. This resets the device and executes the bootloader which now enumerates as "J-Link ARM". The entire firmware is then transmitted and the bootloader takes care to flash it to the proper address.

VID:PIDCompanyDevice
1366:0105SEGGERJ-Link_J-Link V9.3 Plus
1366:0101SEGGERJ-Link ARM

At this point I've turned to disassembly. I've built myself an ELF file from the extracted firmware and the dumped RAM and I've loaded it into IDA. The J-Link is driven by a 1 byte command list:

File: command_list.txt
0x801173C byte_801173C  DCB 'I', 'D', 'S', 'E', 'G', 'G', 'E', 'R'
0x8011744 dword_8011744 DCD 0xB9FF7BBF       
0x8011748 usb_commands  DCD cmd_unsupported
0x801174C               DCD cmd_01_version
0x8011750               DCD cmd_02_reset_trst
0x8011754               DCD cmd_03_reset_target
0x8011758               DCD cmd_04_get_info
0x801175C               DCD cmd_05_set_speed
0x8011760               DCD cmd_06_update_firmware
0x8011764               DCD cmd_07_get_state
0x8011768               DCD cmd_08_set_ks_power
0x801176C               DCD cmd_09_register_unreg
0x8011770               DCD cmd_0a_indicators
0x8011774               DCD cmd_0b_permit
0x8011778               DCD cmd_0c_pcode
0x801177C               DCD cmd_0d_prot_version
0x8011780               DCD cmd_0e_set_emu_option
0x8011784               DCD cmd_unsupported
0x8011788               DCD cmd_unsupported
0x801178C               DCD cmd_11_merge_commands
0x8011790               DCD cmd_12_update_config_c000
0x8011794               DCD cmd_13_update_config_bf00
0x8011798               DCD cmd_unsupported
0x801179C               DCD cmd_15_spi
0x80117A0               DCD cmd_16_update_config_data
0x80117A4               DCD cmd_17_handle_c2
0x80117A8               DCD cmd_18_verify_signature
0x80117AC               DCD cmd_19
0x80117B0               DCD cmd_1a
0x80117B4               DCD cmd_unsupported
0x80117B8               DCD cmd_1c
0x80117BC               DCD cmd_unsupported
0x80117C0               DCD cmd_unsupported
0x80117C4               DCD cmd_unsupported
0x80117C8               DCD cmd_unsupported
0x80117CC               DCD cmd_unsupported
0x80117D0               DCD cmd_unsupported
0x80117D4               DCD cmd_c0_get_speeds
0x80117D8               DCD cmd_c1_get_hw_info
0x80117DC               DCD cmd_c2_get_counters
0x80117E0               DCD cmd_c3_test_net_speed
0x80117E4               DCD cmd_c4_cpu2_set_config
0x80117E8               DCD cmd_c5_cpu2_exec_cmd
0x80117EC               DCD cmd_c6_get_cpu2_caps
0x80117F0               DCD cmd_c7_select_if
0x80117F4               DCD cmd_c8_hw_clock
0x80117F8               DCD cmd_c9_hw_tms0
0x80117FC               DCD cmd_ca_hw_tms1
0x8011800               DCD cmd_cb_hw_data0
0x8011804               DCD cmd_cc_hw_data1
0x8011808               DCD cmd_cd_hw_jtag
0x801180C               DCD cmd_ce_hw_jtag2
0x8011810               DCD cmd_cf_hw_jtag3
0x8011814               DCD cmd_d0_hw_release_reset_stop_ex
0x8011818               DCD cmd_d1_hw_release_reset_stop_timed
0x801181C               DCD cmd_unsupported
0x8011820               DCD cmd_unsupported
0x8011824               DCD cmd_d4_get_max_mem_block
0x8011828               DCD cmd_d5_hw_jtag_write
0x801182C               DCD cmd_d6_hw_jtag_get_result
0x8011830               DCD cmd_unsupported
0x8011834               DCD cmd_unsupported
0x8011838               DCD cmd_unsupported
0x801183C               DCD cmd_da_hw_tck0
0x8011840               DCD cmd_db_hw_tck1
0x8011844               DCD cmd_dc_hw_reset0
0x8011848               DCD cmd_dd_hw_reset1
0x801184C               DCD cmd_de_hw_trst0
0x8011850               DCD cmd_df_hw_trst1
0x8011854               DCD cmd_e0_fine_write_read
0x8011858               DCD cmd_e1_cdc_exec
0x801185C               DCD cmd_unsupported
0x8011860               DCD cmd_unsupported
0x8011864               DCD cmd_unsupported
0x8011868               DCD cmd_e5_get_cpu2_caps_dll_version
0x801186C               DCD cmd_e6_read_config_bf00
0x8011870               DCD cmd_e7_sync_ks_power_from_config_data
0x8011874               DCD cmd_e8_get_caps
0x8011878               DCD cmd_e9_get_cpu_caps
0x801187C               DCD cmd_ea_exec_cpu_cmd
0x8011880               DCD cmd_eb_swo
0x8011884               DCD cmd_unsupported
0x8011888               DCD cmd_ed_get_caps_ex
0x801188C               DCD cmd_unsupported
0x8011890               DCD cmd_unsupported
0x8011894               DCD cmd_f0_get_hw_version
0x8011898               DCD cmd_f1_write_dcc
0x801189C               DCD cmd_f2_read_config_c000
0x80118A0               DCD cmd_f3_write_config_dummy
0x80118A4               DCD cmd_f4_write_mem
0x80118A8               DCD cmd_f5_read_mem
0x80118AC               DCD cmd_f6_measure_rtck_react
0x80118B0               DCD cmd_f7_write_mem_arm79
0x80118B4               DCD cmd_f8_read_mem_arm79
0x80118B8               DCD cmd_unsupported
0x80118BC               DCD cmd_fa_read_dcc
0x80118C0               DCD cmd_fb_write_dcc_ex
0x80118C4               DCD cmd_unsupported
0x80118C8               DCD cmd_unsupported
0x80118CC               DCD cmd_fe_read_emu_mem
0x80118D0               DCD cmd_unsupported

What I've discovered was that the user licenses (software licenses like to ones used by EMStudio) are stored in clear at address 0x0800c100, config licenses at 0x0800bf20, the serial number at 0x0800bf00 and there is one (256 byte) RSA digital signature at 0x0800b700. The signature is derived from the hardware ID of your microcontroller using 65537 as the public key and a 2048 bit modulus which is stored in the firmware. There is no way to calculate mathematically the digital signature without the private key which only SEGGER has. If SEGGER really wants to, it can always check this digital signature and detect a non genuine product. If this happens the only option is to patch the firmware (the code or the modulus). Fortunately, so far (up to software version V692), the only time the digital signature is used is when the licenses or serial number are updated.

The SEGGER software does some other checks to dissuade the use of clones:

Particularly the last "RDDI" check was introduced sometime is autumn of 2020 and the effect is that the software comes (a few seconds later) with a message saying that your probe is defective.

Analyzing the firmware further I have found a function (0xfe) which could be used to read any part of the probe memory (in 0x100 chuncks). When I've tried to use it all I was getting was timeout. Looking closer I've seen that a seed value was used and the function was working only when the seed was not zero. The seed is used to xor each returned word and then is advanced with another xor operation. To set this seed another (obscure) function must be used (0x0e) which sets various emu options and the subfunction 0x182 sets the value of this seed. All is left is to apply the xor in reverse to retrieve the dumped data.

I've written a utility usb_segger_fw_dump source code and linux executable which can retieve the memory content from any address. I've used this to dump the entire memory of J-Link V9, V10 and J-Link EDU Mini. I presume it is working with all of the J-Link probes.

Now I have to resist buying a (high speed USB) V10 which uses a LPC4322 CPU with a dual Cortex-M4/Cortex-M0 core.

This page does not contain any proprietary code. Don't ask me for firmware dumps because you won't get any. Here you can find all the tools to extract your own.

Tags: bootloader, firmware, j-link, segger.

Comments On This Entry

anotherandrew Submitted at 19:16:57 on 1 January 2021
Thank you for this interesting look under the hood of the Segger probes. It looks like the "set emu" subfunction 0x182 is not present on the V8 probes (I have a V8-EDU that fails with this software, but my V10 works). V8-EDU uses the AT91SAM7S64 which should be able to dump flash at 0x00100000, but fails at the "set seed" function.
Emil Submitted at 04:38:55 on 2 January 2021
You are right, the V8 doesn't support the firmware dump. I didn't look closely at V8 because its support is very limited and I am not using it anymore.

Apparently it works with V11 too: electronix.ru forum
ThaDr Submitted at 09:06:01 on 12 January 2021
Great article!! Source and executable links at the bottom aren't working unfortunately. I'd be very interested to have a look at them.
Emil Submitted at 17:18:40 on 12 January 2021
Links work fine. It's a problem on your side.
Franck Submitted at 10:33:03 on 28 January 2021
Newer versions of libjlinkarm.so don't provide the _init symbol so dump_segger_fw doesn't work.
Emil Submitted at 15:40:19 on 28 January 2021
After Rolf Segger reading my article and commenting on Hackaday you should expect some countermeasures. I don't plan to keep up with the firmware extraction, I've achieved my goal of extracting the bootloader and these are not changed often (if at all). Just use V692 (the latest one I've checked it was working).

If someone wants a newer firmware there will always be ways to get it. It just won't be as easy as running dump_segger_fw.
Franck Submitted at 16:14:32 on 28 January 2021
No problem. I understand. I just wanted to let you know.
Thanks for your work.
Emil Submitted at 23:23:44 on 28 January 2021
Fixed now, I'm not relying on the _init symbol anymore.
Shahar Hadas Submitted at 14:33:04 on 29 January 2021
Hi,
Out of curiosity purchased the same as one of your clones (the V9.6 one - PCB (1) one)
Managed to connect the SWD interface, and was indeed locked... so I erased the chip and then I was able to re-program the clone.
I have the same issue right now (with no boot loader) - but the firmware itself does run (and the jlink clone is usable).
One interesting thing is that I can't seem to communicate with the STM32 on the clone via SWD interface any more.
It simply notify me there's no such chip (tried with Segger J-Link and ST-Link/V2)
So I'm blocked in trying to re-program the clone in any way...
Do you have any idea as to why?
Emil Submitted at 19:39:56 on 29 January 2021
The SwD interface is always enabled but the reset line is not available on the clone connector. Try to solder a small wire on CPU pin 7 and connect it to your STLinkV2.
Shahar Hadas Submitted at 13:50:57 on 30 January 2021
That was my assumption ... but instead of soldering I ordered some micro IC clamps from AliExpress (your blog doesn't allow links) and waiting for them to arrive.

But to fully understand my situation, if I wanted to recover the boot loader for the clone, I need to order another clone and dump its bootloader using the J-Link-Dump-Bootloader ?
Emil Submitted at 17:14:40 on 30 January 2021
There is no clamp capable of 0.5 mm pitch. Your only option is to solder one wire on pin 7. Also you can use your probe with only the main firmware and no bootloader. My program ' 'dump_segger_fw' does this automatically if it cannot find a pre-saved bootloader. The drawback is that the probe won't update automatically.
Shahar Hadas Submitted at 21:06:54 on 14 February 2021
I can't paste links here, but look for 4000307558588 on AliExpress. This is what I ordered (package seems to taking its time...)

According to the photos and the reviews, seems to be able to work with the 0.5mm - or I actually wasted my money?
Emil Submitted at 00:28:39 on 15 February 2021
The pitch is 0.5mm but the pin width is 0.22mm. Good luck fitting your probe clamps through a 0.28mm space without touching the neighboring pins.

My advice is (if you don't want to destroy your ARM chip) to use magnet wire and a soldering iron. It's just one pin, it can't be that hard to solder even for a beginner.
Bulba Submitted at 19:42:38 on 28 February 2021
Thank you for this article. I have a question about calculating the firmware checksum. How is it implemented? Which firmware blocks are included in the calculation?
Emil Submitted at 22:05:32 on 28 February 2021
It is CRC16 with 0x8408 generator polynom calculated over the entire firmware including the gap at the end. For Jlink V9 it covers 0x2fffe in length.
Bulba Submitted at 11:13:48 on 1 March 2021
Thank you for your answer. I found firmware for v9 on the internet. I don't know what I'm doing wrong. I'm using HxD hex editor. After selecting the block from the address 0x08010000 with the length 0x2fffe, HxD calculates CRC-16 equal to 72e9. Firmware at the address 0x0803fffe contains the value e445. Can you help me, because I understand that saving FW with wrong checksum will damage j-link?
Emil Submitted at 16:44:02 on 1 March 2021
The CRC only affects the firmware, it won't "damage" anything while the bootloader is still there. For the CRC calculation see the source of my dump_segger_fw program.
Shahar Hadas Submitted at 22:24:13 on 9 March 2021
So ... got another "2nd clone". downloaded the bootloader.bin ... and burned it on the "1st clone".

Opened JLink config ... it auto-detected it needs a firmware - and just flashed the latest.

Interesting part was the issue wasn't the NRST pin after all, didn't tried it until I got the 2nd clone - but I was using ST-Link / Segger J-Link EDU - with 4Khz for SWD (like I did in the initial erase ...). And that was the issue. once I used 2000Hz - everything worked!

So now I ended up with 2 clones, 2 Segger EDUs and 3 ST-Link V2 - way more than I need :)
Mike Submitted at 16:37:50 on 22 March 2021
Do you have J-link V10 schematic?
Shahar Hadas Submitted at 20:20:44 on 17 April 2021
Trying to figure out the serial number.
On the "clone" I erased it's flash completely I now have a serial number of "-1".

I was wondering what are my options here in setting a non-blocked serial number.
I thought about erasing it again, writing the serial number in the correct location in the flash and then putting the bootloader.bin again (which will lock the flash again I assume?)
Emil Submitted at 02:15:02 on 18 April 2021
Any number is good if it's not in that list but original numbers tend to incorporate the hardware version in the decimal serial number as described above.
Also the flash doesn't get locked automatically.

Add A Comment

Your Name
Your EMail
Your Comment

Your submission will be ignored if any field is left blank or if you include clickable links (URLs without the "http://" start are fine). English only please. Your email address will not be displayed.