J-Link Genuine Segger | |
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 | ||
Type | Address | Length |
---|---|---|
IVT | 0x08000000 | 0x200 |
Bootloader | 0x08000200 | 0x3e00 |
Signature | 0x0800b700 | 0x100 |
Serial Nr | 0x0800bf00 | 4 |
Licenses | 0x0800bf20 | 0xc0 |
Config Data | 0x0800c000 | 0x100 |
User Licenses | 0x0800c100 | 0x3f00 |
FW IVT | 0x08010000 | 0x200 |
FW Code | 0x08010200 | 0x2fdfe |
FW CRC16 | 0x0803fffe | 2 |
Code in RAM | 0x20000000 | 0x30d0 |
Data in RAM | 0x200030d0 | 0x10f30 |
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 version | 0x8000210 |
FW version | 0x8010210 |
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] [0x000000->0x190000] J-Trace PRO V3 RISC-V (JTrace_PRO_V3_RISCV.bin) [ 9] [0x00e049->0x03c000] J-Link Ultra Rev.1 [10] [0x02f5ac->0x070000] J-Link Ultra V4 [11] [0x000000->0x100000] J-Link Ultra V5 (JLink_ULTRA_V5.bin) [12] [0x000000->0x190000] J-Link Ultra V5-1 (JLink_ULTRA_V5_1.bin) [13] [0x000000->0x190000] J-Link Ultra V6 (JLink_ULTRA_V6.bin) [14] [0x015e28->0x030000] J-Link V9 [15] [0x02c9cf->0x078000] J-Link V10 [16] [0x000000->0x078000] J-Link V11 (JLink_V11.bin) [17] [0x000000->0x078000] J-Link V12 (JLink_V12.bin) [18] [0x000000->0x018800] J-Link EDU Mini V1 (JLinkEDUMini_V1.bin) [19] [0x000000->0x078000] J-Link WiFi-V1 (JLink_WiFi_V1.bin) [20] [0x005400->0x005400] Rev.5 [21] [0x006e00->0x006e00] J-Link ARM V6 [22] [0x006e00->0x006e00] J-Link ARM V7 [23] [0x00dc00->0x00dc00] J-Link ARM V8 [24] [0x00dc00->0x00dc00] J-Link ARM-OB SAM7 [25] [0x008094->0x00dc00] J-Link OB RX200 V1 [26] [0x00d89c->0x00dc00] J-Link ARM Lite V8 [27] [0x0155d0->0x018800] J-Link Lite V9 [28] [0x00a7d8->0x00dc00] J-Link Lite-Cortex-M V8 [29] [0x01047c->0x018800] J-Link Lite-Cortex-M V9 [30] [0x00854c->0x00dc00] J-Link LITE-Cortex-M-5V [31] [0x000000->0x019c00] J-Link Lite Synergy (JLink_Lite_Synergy.bin) [32] [0x005000->0x005000] J-Link ARM-LPC Rev.1 [33] [0x018000->0x018000] J-Link ARM-LPC2146 Rev.2 [34] [0x008980->0x020000] J-Link Lite-XMC4000 Rev.1 [35] [0x00f6ec->0x020000] J-Link Lite-XMC4200 Rev.1 [36] [0x00d378->0x018000] J-Link Lite-ADI Rev.1 [37] [0x010000->0x010000] J-Link Lite-LPC Rev.1 [38] [0x006000->0x008000] J-Link ARM-STR711 [39] [0x005c00->0x005c00] J-Link ARM-OB STM32 [40] [0x00b800->0x00b800] J-Link Lite-STM32 Rev.1 [41] [0x006e00->0x006e00] J-Link CF V1 [42] [0x00b800->0x00b800] J-Link Lite-FSL V1 [43] [0x0387c4->0x060000] J-Link / Flasher ATE Mainboard V1 [44] [0x052b44->0x060000] J-Link / Flasher ATE Module V1 [45] [0x015b4a->0x000000] J-Link ARM / Flasher ARM V2 [46] [0x021482->0x000000] J-Link ARM / Flasher ARM V3 [47] [0x03e568->0x000000] J-Link ARM / Flasher ARM V4 [48] [0x000000->0x000000] J-Link / Flasher ARM V5 (FlasherARM_V5.bin) [49] [0x000000->0x000000] J-Link / Flasher ARM V5-1 (FlasherARM_V5_1.bin) [50] [0x02c516->0x000000] J-Link / Flasher Portable V1 [51] [0x03b833->0x000000] J-Link / Flasher Portable Plus V1 [52] [0x000000->0x000000] J-Link / Flasher Portable PLUS V5 (Flasher_Portable_PLUS_V5.bin) [53] [0x01fa39->0x000000] J-Link RX / Flasher RX V1 [54] [0x038fc5->0x000000] J-Link RX / Flasher RX V4 [55] [0x01deff->0x000000] J-Link PPC / Flasher PPC V1 [56] [0x037383->0x000000] J-Link PPC / Flasher PPC V4 [57] [0x04483d->0x000000] J-Link PRO / Flasher PRO V4 [58] [0x000000->0x000000] J-Link / Flasher PRO V5 (FlasherPRO_V5.bin) [59] [0x000000->0x000000] J-Link / Flasher PRO V5-1 (FlasherPRO_V5_1.bin) [60] [0x000000->0x000000] J-Link / Flasher Compact V5 (FlasherCompact_V5.bin) [61] [0x0132ec->0x030000] J-Link ARM-Pro V1.x [62] [0x01403b->0x030000] J-Link ARM-Pro V3.x [63] [0x02f59f->0x070000] J-Link Pro V4 [64] [0x000000->0x100000] J-Link Pro V5 (JLink_PRO_V5.bin) [65] [0x000000->0x190000] J-Link Pro V5-1 (JLink_PRO_V5_1.bin) [66] [0x000000->0x190000] J-Link Pro V6 (JLink_PRO_V6.bin) [67] [0x004f30->0x038000] J-Link OB RX6xx V1 [68] [0x0096c2->0x038000] J-Link OB RX621-ARM-SWD V1 [69] [0x00488d->0x038000] J-Link OB-RX621-RX1xx V1 [70] [0x00baad->0x039000] J-Link MCU-Link V1 [71] [0x000000->0x034000] J-Link OB-Apollo4-CortexM (JLink_OB_Apollo4_CortexM.bin) [72] [0x000000->0x018800] J-Link OB-K22-Cortex-A (JLink_OB_K22_CortexA.bin) [73] [0x000000->0x018800] J-Link OB-K22-Cortex-M (JLink_OB_K22_CortexM.bin) [74] [0x000000->0x018800] J-Link OB-K22-RISCV (JLink_OB_K22_RISCV.bin) [75] [0x000000->0x01a000] J-Link OB-K22-NordicSemi (JLink_OB_K22_NordicSemi.bin) [76] [0x000000->0x018800] J-Link OB-K22-Qorvo (JLink_OB_K22_Qorvo.bin) [77] [0x0179d0->0x018800] J-Link OB-K22-SiFive [78] [0x000000->0x0f9000] J-Link OB-nRF5340-NordicSemi (JLink_OB_nRF5340_NordicSemi.bin) [79] [0x000000->0x019c00] J-Link OB-S124 (JLink_OB_S124.bin) [80] [0x000000->0x019c00] J-Link Lite-S124 (JLink_Lite_S124.bin) [81] [0x000000->0x016e00] J-Link OB-SAM3U128-V2-NordicSemi (JLink_OB_SAM3U128_V2_NordicSemi.bin) [82] [0x000000->0x01c000] J-Link OB-SAM3U128 V1 (JLink_OB_SAM3U128_V1.bin) [83] [0x000000->0x019e00] J-Link OB-SAM3U128 V3 (JLink_OB_SAM3U128_V3.bin) [84] [0x000000->0x01b800] J-Link OB-STM32F103 V1 (JLink_OB_STM32F103.bin) [85] [0x008153->0x00b800] J-Link OB-STM32F072-CortexAR [86] [0x0080c0->0x00b800] J-Link OB-STM32F072-CortexM [87] [0x00c62f->0x01a000] J-Link OB-STM32F072-128KB-CortexM [88] [0x009114->0x01c000] J-Link OB-MB9AF312K-Spansion [89] [0x00c3e9->0x0f0000] J-Link OB-STM32F4-Arduino V1 [90] [0x000000->0x036000] J-Link OB-RA4M2 (JLink_OB_RA4M2_Renesas.bin) [91] [0x000000->0x036000] J-Link OB-RA4M2-CortexM (JLink_OB_RA4M2_CortexM.bin) [92] [0x000000->0x036000] J-Link OB-RA4M2-RISCV (JLink_OB_RA4M2_RISCV.bin) [93] [0x000000->0x036000] J-Link OB-RA4M2-Full (JLink_OB_RA4M2_Full.bin) [94] [0x000000->0x01a000] J-Link OB-CALLIOPE-MINI V2.1 (JLink_OB_Calliope_MINI_V2_1.bin)
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_V784f_x86_64 --------------- libjlinkarm.so.7.84.6 002f1cf2: 41 44 002f1cf3: 81 8b 002f1cf4: e4 60 002f1cf5: 00 1c 002f1cf6: fc 90 002f1cf7: ff 90 002f1cf8: ff 90
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.
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 | |
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 updateI'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:PID | Company | Device |
---|---|---|
1366:0105 | SEGGER | J-Link_J-Link V9.3 Plus |
1366:0101 | SEGGER | J-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.txt0x801173C 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:
- first it maintains a list of hacked serial numbers and checks against these: 11111117, 20100214, 50331647, 20090626, 20080696, 20064001, 20101001, 24446459, 805306163, 377001345, 270676280, 17892859, 99999994, 286370559
- second it looks for old licenses which are not in use anymore: "GDBFull", "RDDI"
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.