This post describes how to dump bootROM from Amlogic S905D3 SoC using Khadas VIM3L board. Since this board doesn't use Secure Boot, we can execute custom code in Secure World (a.k.a TrustZone) without exploiting any vulnerability. In addition, the board exposes an UART connector, which is convenient for communicating with baremetal code running on target.
The following resources were abused to complete this project :
- VIM3L board : SBC based on Amlogic S905D3 System-On-Chip.
- USB to TTL Converter : to enable communication between host and target using UART port.
- S905D3 SoC datasheet : Khadas published a datasheet for S905D3. It contains a memory map, including the bootROM address.
- khadas-uboot : U-Boot code released by Khadas contains a signing tool to package a bootloader image.
- khadas-utils : Khadas released a tool to communicate with the bootROM via USB.
In order to dump the bootROM, we need to execute custom code in Secure World.
On most firmwares provided by Khadas, U-Boot shell is accessible via UART port. However, U-Boot runs in Non-Secure World (a.k.a. Normal World) and therefore isn't helpful.
Instead, we need to execute our code earlier in the boot chain. Since Secure Boot is disabled on this board, we could modify the BL2 bootloader stored in flash memory. However, there's a more convienent solution : the bootROM implements a feature to load BL2 bootloader via the USB Type-C port. This in-RAM solution has the advantage of not altering the flash memory.
Finally, we also take advantage of the UART port to transfer data to our host.
The code to dump the bootROM is straightforward : each byte is read then sent to UART port.
Early tests revealed an issue : UART data transfers would stop inconsistently before completion, and the board would then reset. This issue was caused by a watchdog timeout. U-Boot source repository contains the code to reset the watchdog, which solves that issue.
The code is built using GNU C cross-compiler for the arm64 architecture (packages gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu on Debian) :
$ aarch64-linux-gnu-gcc -O3 -nostdlib -Wl,--build-id=none -o S905D3_dump_bootrom.elf S905D3_dump_bootrom.c $ aarch64-linux-gnu-objcopy -O binary -j .text S905D3_dump_bootrom.elf S905D3_dump_bootrom.bin
Then, the binary is packaged as regular BL2 image for this target using the aml_encrypt_g12a tool from khadas-uboot repository:
$ ./khadas-uboot/fip/g12a/aml_encrypt_g12a --bl2sig --input ./S905D3_dump_bootrom.bin --output ./S905D3_dump_bootrom.img
Khadas documentation explains how to connect UART port on VIM3L board. On host side, we use minicom software to communicate with this port :
$ sudo minicom -D /dev/ttyUSB0
Then, we boot the board in USB Upgrade mode (a.k.a. TST mode or USB Download mode) as explained in Khadas documentation. In minicom console, we can see :
This string ending with USB:0; means the board has started in USB Upgrade mode.
On the host side, we see a new USB device :
[10504.840173] usb 1-4.3.1: new high-speed USB device number 16 using xhci_hcd [10504.979469] usb 1-4.3.1: New USB device found, idVendor=1b8e, idProduct=c003, bcdDevice= 0.20 [10504.979495] usb 1-4.3.1: New USB device strings: Mfr=1, Product=2, SerialNumber=0 [10504.979514] usb 1-4.3.1: Product: GX-CHIP [10504.979525] usb 1-4.3.1: Manufacturer: Amlogic
In minicom, we use the capture feature (CTRL-A L) to save data sent by our program into a file minicom.cap.
Our code is uploaded and run on the board using the update tool from khadas-utils repository.
$ ./khadas-utils/aml-flash-tool/tools/linux-x86/update write ./S905D3_dump_bootrom.img 0xfffa0000 .. Transfer Complete! total size is 65536 Bytes $ ./khadas-utils/aml-flash-tool/tools/linux-x86/update run 0xfffa0000 [update]Run at Addr fffa0000 AmlUsbRunBinCode:ram_addr=fffa0000
In minicom console, we received the bootROM dump sent by our code :
e0031faae1031faae2031faae3031faae4031faae5031faae6031faae7031faae8031fa ae9031faaea031faaeb031faaec031faaed031faaee031faaef031faaf0031faaf1031f aaf2031faaf3031faaf4031faaf5031faaf6031faaf7031faaf8031faaf9031faafa031 [...]
Since the dump is encoded in hexadecimal representation, the last step is to convert it back to binary :
$ cat minicom.cap | xxd -r -p > VIM3L.bootrom.bin $ sha1sum VIM3L.bootrom.bin 5de02d2958d4d7214b28521239ec9b63fe9a2dbe VIM3L.bootrom.bin $ wc -c VIM3L.bootrom.bin 65536 VIM3L.bootrom.bin $ strings -13 VIM3L.bootrom.bin auth failed, reboot... 511f6b60cfd40c6 ken.amlogic.com 03/26/19_12:20:42 gcc version 4.8 511f6b60cfd40c6 INDXCHIPOPS_ROMVfb_e1 FAILkey error FAILkey len error FAILmissing var max-download-size FAILmissing var! FAILUnkonw chipinfo id FAILVariable not implemented FAILdata invalid size FAILdata too large FAILkey_len error FAILunknow command New World Cup usb_dnl_fastboot
The strings in the bootROM dump reveal that Fastboot protocol is implemented (different protocol than the one we just used to upload our code).