pok3rtool
pok3rtool copied to clipboard
Support for ISP bootrom's USB flash mechanism
ISP bootrom features programming via USB and UART using external software like HT32 Flash Programmer. Two important distinctions between ISP and IAP are that ISP bootrom is on all HT32 devices and ISP features a command to trigger mass erase (to clear flash security; to run QMK without lockups) without the need of an external SWD/JTAG debugger.
More information will be provided after analyzing USB packet captures on HT32F1654 and HT32F52352.
HT32 Flash Programmer Usage Notes
- Select IAP bootloader as target flash image (since it starts writing at address 0).
- Disable flash protection and security
- Tick 'All pages', 'Erase', 'Program', 'Verify'
- Short BOOT(1) pin to ground and plug in USB.
- leave pin shorted since the device needs to re-enter ISP after mass erase reset
- HT32F1654 and HT32F52352 in ISP shows up as "04d9:8010 Holtek Semiconductor, Inc."
- read user guide on VMCR register in FMC for more information.
- HT32F165x: BOOT0 should be shorted to 3V3 (if not already pulled up).
- Press 'Connect' then 'Programming'
- After keyboard is programmed, remove the pin short and reset the keyboard
- Proceed to flash application firmware with IAP mechanism as normal.
Tasks:
- [x] Test HT32 Flash Programmer (Windows support only)
- [x] Test with HT32F165x
- [x] Test with HT32F52xxx
- [x] Decode USB commands
- [x] Command format:
[ CMD, SUBCMD, CRC16, START_ADDR, END_ADDR, DATA ]- CMD (1 byte)
- SUBCMD (1 byte)
- CRC16 (2 bytes)
- START_ADDR (4 bytes)
- END_ADDR / LENGTH (4 bytes)
- DATA (52 bytes): pad with 0s
- [x] Mass erase:
[0x00,0x0a,CRC16,0x00000000,0x00000000] - [x] Page erase:
[0x00,0x08,CRC16,START_ADDR,END_ADDR] - [x] Flash write (52 bytes max):
[0x01,0x01,CRC16,START_ADDR,END_ADDR,DATA]- DATA is unencrypted
- [x] Flash check:
[0x01,0x00,CRC16,START_ADDR,END_ADDR,DATA]- check status buffer to confirm if check succeeded or not
- [x] Flash read:
[0x01,0x02,CRC16,START_ADDR,END_ADDR] - [x] Flash crc:
[0x02,0x00,CRC16,START_ADDR,LENGTH]- stores
[CRC16,0x4f]to status buffer
- stores
- [x] Info:
[0x03,0x00,CRC16] - [x] Reboot to IAP:
[0x04,0x01,CRC16] - [x] Reboot to AP:
[0x04,0x00,CRC16] - TODO
- [x] Command format:
- [x] Add support for ISP USB protocol to pok3rtool (to support Linux/macOS platforms)
- WIP branch: https://github.com/hansemro/pok3rtool/tree/holtek-isp-libusb-dev
- [x] Add ISP VID/PID: 0x04d9:0x8010 (treat as builtin)
- [x]
infocommand- [x] handle v101 info format
- [x] handle v100 info format
- [x] parse device model
- [x] parse ISP version
- [x] parse page size
- [x] parse flash page count to compute flash size
- [x] read option bytes to get flash security, option byte protection, and flash page protection status
- [x]
versioncommand - [x]
rebootcommand - [x]
dumpcommand- [x] get flash size from info
- [x] dump flash (dumps 0s if flash security is enabled)
- [x]
flashcommand- [x] trigger mass erase, reset, then reconnect ISP
- [x] write firmware
- [x] check firmware
- [x] crc firmware
- [x] reset to IAP/AP
- [x]
wipecommand- [x] trigger mass erase
Holtek HT32 Flash Commander is a command-line tool alternative to HT32 Flash Programmer described in the initial post. Unfortunately, it has bugs programming HT32F1654 where certain regions are left unprogrammed. The only difference I was able identify between Flash Commander and Flash Programmer is the frequency of status reports on the control endpoint.
As previously tested (https://gist.github.com/hansemro/acdb861d4bb9c5b52bac57d4dbf39601), IAP/ISP instructions (up-to 64) return codes are stored in a 64-byte buffer which are read over the control endpoint after sending the GET_REPORT control message (bmRequestType=0xa1, bRequest=0x01, wValue=0x0100, wLength=64). Once the status buffer is full, no entries will be saved until cleared by 4 new entries after filled or buffer read. Another thing to note is that a return code is saved after the operation is completed so the buffer may have fewer elements if read from too early.
HT32 Flash Programmer likely utilizes the buffer as a method to synchronize transactions (where 30 write requests yields 30 status entries over the span of one or more status requests). In contrast, HT32 Flash Commander does not wait for an equal number of write requests and may end up writing at a rate faster than can be consumed. More prototyping work is required to prove this theory...
If status report requests are necessary, then we may need to update rawhid to transmit/receive control messages in a way that is supported on all platforms.
Update: When buffer is full and gets 4 new instructions, the device reboots (which clears the buffer). So clearing the buffer before it gets full seems necessary for ISP flash programming.
Updated cooler master gist python script for Holtek ISP with basic status report tests: https://gist.github.com/hansemro/76493b59cbade75309dde1fdbe1b103b
This is very interesting! I never thought about the ROM bootloader in the HT32, because the user manuals just didn't say anything specific about it.
The HT32 ISP User Manual doesn't say anything at all about USB functionality. But that document is pretty old, so I guess they just never published the updated document after they added USB to the HT32 ISP?
The format and commands of the protocol you've figured out look very similar to the HID-based protocol the original non-RGB POK3R used for firmware updates. So, I suspect this protocol was based on the USB version of the IAP protocol.
Flash Commander user manual can be found in its install location and does describe connecting to ISP via USB. The command line tool features an engineering mode to do specific operations (mass erase, read/set flash security, program, crc, reset). It is just unfortunate that it cannot write properly to HT32F1654 (but works fine on HT32F52352).
Kinda funny how I did recognize the ISP USB VID/PID (https://github.com/mateuszradomski/re-masterkeys/issues/1#issuecomment-1146783414) months ago, but was a bit too panicked to check how it was even possible for my bricked keyboard to be recognized over USB.
Proof of concept branch with working writeFirmware operation: https://github.com/hansemro/pok3rtool/tree/holtek-isp-libusb-linux-poc
This targets Linux with new libusb-1.0 backend for now. My plan is to eventually replace rawhid backend drivers with a common libusb-1.0 driver to make development easier across platforms.
Branch with Linux+Windows support: https://github.com/hansemro/pok3rtool/tree/holtek-isp-libusb-linux-windows-poc
Reboot delays may need to be extended if libusb fails to find/reopen devices as done with ISP protocol.
Cherry-pick this commit to build and install from msys2: https://github.com/hansemro/pok3rtool/commit/095864f9900c048db5a9876f872d7628e35cfb40
Branch with Linux+Windows+macOS support: https://github.com/hansemro/pok3rtool/tree/holtek-isp-libusb-linux-windows-macos-poc
Not sure if the vulnerability can be assigned CVE since the vendor is not based in the US and not in the database, but I will still try to reach out the vendor so that they can fix it in future hardware revisions, notify their customers, etc.
Wow, that's very cool! Is the flash just not protected via the ISP read command? Or did you find a bug in it? IIRC, the flash security protection just disables flash reading altogether if a debug probe is detected, or if it is not booted from flash.
I think I have the firmware and bootloaders for all the Holtek-based keyboards I have. But good to know!
Is the flash just not protected via the ISP read command?
Read command obeys flash security at least by reading out 0s to the endpoint buffers.
Or did you find a bug in it?
Didn't find find a bug in the read command. If I had to define it, there is a security design flaw that was overlooked for an ISP feature. The flaw is pretty inconspicuous at first glance.
IIRC, the flash security protection just disables flash reading altogether if a debug probe is detected...
Close. Flash access is only partially disabled with debugger attached: the processor will continue to fetch/decode/execute instructions but with the caveat that the processor loads 0s when loading from flash memory (this ultimately breaks firmware in flash). This is to prevent the debugger from overwriting an argument of a load instruction to read out an address from flash (https://blog.includesecurity.com/2015/11/firmware-dumping-technique-for-an-arm-cortex-m0-soc/). Also, the user manual specifies that only DCODE read access is blocked (and not ICODE).
IIRC, the flash security protection just disables flash reading altogether ... if it is not booted from flash.
I guess ROM bootloader counts as flash since it is able to access flash memory somehow.
Found a new workaround that does not require WinUSB driver filter step or libusb.
Relevant change: https://github.com/hansemro/pok3rtool/commit/1259eb514b5dee9b679a6ed0d590cce45654295c Branch: https://github.com/hansemro/pok3rtool/tree/holtek-isp-dev
Decided to write a standalone tool for flashing ISP devices: https://github.com/hansemro/ht32-dfu-tool