Unlock Qualcomm Bootloader

1 view
Skip to first unread message

Walda Caesar

unread,
Aug 4, 2024, 4:16:29 PM8/4/24
to riddvapenmay
Qualcommdevices all use fuse based logic to dictate permanent feature configurations/cryptographic key sets. As stated above, the physical version of which is called a QFUSE, and is stored in a region on the SoC called QFPROM in rows.

Aboot has also matured from LittleKernel (an open source bootloader) with some additions into a fully independent solution now called the proprietary Android Bootloader (ABL). Thisnew bootloader allows the use of UEFI, among many other security and quality-of-life enhancements for developers/OEMs.


A few months ago I purchased an Android phone to do some research around a specific series of NFC chips, which required me to gain root access to the device in order to fully access its hardware capabilities.


Gaining root access on Android phones generally requires unlocking the bootloader, an action which disables the signature verification requirements of the phone so that a modified Android boot image can be deployed. On Qualcomm chipsets this is a standardised process which uses commands in the Android Bootloader to perform the unlock. Smartphone manufacturers often modify the bootloader to add their own restrictions, and require their own tools.


The phone that I had purchased had these restrictions, requiring me to wait seven days before being allowed to root the device. Due to this, I decided to investigate whether I could bypass the waiting period on an older smartphone that was produced by the same manufacturer. I set myself a challenge to break the bootloader protection before the end of the seven day waiting period.


I did not want to use either of these approaches, and instead wanted to attack the second-stage bootloader. Emergency Download mode is accessed from the first stage bootloader, however additional diagnostics and management tools are available at the next stage in the boot chain.


Analysis of the custom unlock functionality implemented by the manufacturer demonstrated that a small unique value was sent from the phone to the unlock tool, and a signature was generated on their servers. After seven days, this would be sent to the phone and verified, performing the unlock. I analysed this process using a Windows host and the USBPCAP USB analysis software.


This tool facilitates standard and custom functions, including flashing partitions, getting OEM-specific data, or booting into different modes. Analysis of this tool demonstrated that the fastboot protocol is very simple, and could be implemented using basic C++ code and LibUSB.


All commands were found to be sent as ASCII text over a single USB endpoint, and responses to the commands were sent asynchronously from another endpoint. I found that libraries existed to facilitate access to the fastboot interface, however I decided to use LibUSB, as this would give me greater control over the communication.


Brief analysis of the bootloader demonstrated that all of the fastboot commands were stored in a table, consisting of the ASCII command, and a function callback for that command. This allowed for rapid analysis of any potentially hidden commands, and would aid in analysis of specific functionality. The bootloader was also found to contain a huge number of debugging strings, which made understanding of the code much easier.


As I was approaching the fastboot protocol from a reverse-engineering perspective, rather than reading any documentation, I had made some assumptions about how data uploads were performed. The correct sequence for uploading is as follows:


Unplugging the device from the USB port and plugging it back in found that it would no longer enumerate over USB, meaning that it was completely non-functional. Holding down the power and volume down buttons for ten seconds caused a hard reboot , with no persistent damage to the device.


In order to confirm that what I had stumbled upon was a valid buffer overflow, I decided to try a smaller payload size. I had started with a 10 megabyte payload, and attempted the same sequence a 4 kilobyte payload. This smaller payload did not crash the phone, and it continued to function normally.


As smaller payloads did not cause a crash, I elected to perform a binary search in order to identify the largest payload which would not crash the phone. I sent payload sizes half way between the small and large value, and then reduced the largest payload size, or increase the smallest payload size depending on whether the phone crashed or not. This led me to the maximum payload which would not crash the device, which was 0x11bae0 (1161952) bytes in size.


As this was an unusual memory size, I was reasonably sure that this was a buffer overflow of some kind, however as I had no access to the internal hardware, any debugging capabilities, or an overview of the memory map of the bootloader there would be a lot of uncertainty about exactly what was overflowing. I had noted that the bootloader implemented stack canaries using randomised values, meaning that if I was overflowing the stack and hitting the canary, this would likely not be exploitable.


By constantly power cycling, finding the valid byte value, and then moving to the next byte in the sequence, a reasonable representation of the data in memory at that point could be generated. It would not necessarily be the exact data, but would be close enough not to crash the bootloader. Once this sequence was generated, it would probably be possible to use it to gain code execution in the bootloader, however this would be a long winded process if it could not be automated.


Automation of power cycling could be performed by removing the battery from the phone, and using a USB relay to cut the power when it was connected to the host PC, but this would require disassembly of the phone and removal of glue around the case. Also, if I was disassembling the phone I could have directly accessed the EMMC and unlocked the bootloader using a hardware-based approach.


While trying to come up with a solution for this, I attempted to constantly hold down the power and volume down buttons of the phone. This caused the phone to be in a boot-loop: it would restart and load the bootloader for a few seconds, and then restart again. I noticed that during this process the USB interface would start functioning for enough time for me to send fastboot commands.


There were a few reasons why this may have been the case. ARM64 operations can often have the same or similar functionality even if bits are flipped in the opcode, registers can be accessed in both 32-bit (Wx) and 64-bit (Xx) mode, and Branch instructions can have conditions that were unintentionally met due to the brute forcing being performed.


Further checking of the rest of the operations demonstrated that these were also extremely similar. This meant that my bootloader buffer overflow was overwriting the bootloader itself. This also meant that the bootloader was extracted from the EFI filesystem and executed from RAM.


Further analysis of the addresses in use outlined that the bootloader code was overwritten after 0x101000 bytes, and allowed me to overwrite the entire bootloader with the code I had extracted from the Portable Executable, overwriting the bootloader with itself. This would prevent subsequent crashes and allow me to modify any functionality I required by patching the bootloader itself, including the bootloader unlocking code.


The bootloader code was found to verify the RSA signature provided by the unlock tool, and then perform the unlock. I wanted to jump past this verification and go straight to unlocking. I noticed that the bootloader unlock functionality was performed in a Branch and Link instruction, which are generated by compilers for function calls, and I decided to modify the code I had used for my initial buffer overflow to jump to this. I generated the correct relative address for this, and using an online ARM64 compiler I generated the appropriate BL instruction. I then patched this into the bootloader for this jump.


While it would be difficult to debug this process, a successful unlock would be obvious: the phone would restart, erase the userdata partition, and boot into an unlocked state. This approach was found to be effective, and the device was unlocked.


Additional patching of the bootloader could allow for more functionality, such as some limited RAM dumping back from the device for debugging purposes, however this would not allow for any Cold-boot attacks due to restrictions on what areas of RAM could be accessed by the bootloader.


To confirm my theory that this was possible on all SDM660 devices, I purchased a phone with the same chipset by a different manufacturer. This was released a couple of years after the first device, and was found to have completely disabled bootloader unlocking.


The manufacturer had achieved this by implementing a similar signature protection mechanism to bootloader unlocking as was identified on the first device, but without releasing any tools for this to be performed.


I attempted to perform the same buffer overflow as before, unfortunately it was unsuccessful. However, by sending a much larger payload the new device did crash. By using the same binary search as before, it was possible to identify that this bootloader was overwritten after 0x403000 bytes, rather than the 0x101000 bytes of the first one. With this information a bootloader unlock could be swiftly developed.


Bootloader access is not required for users where unlocking is not permitted, it is possible to disable fastboot access entirely in order to prevent attacks against it. Fastboot can then be reactivated via Engineering apps in the main Android OS. Manufacturers who disable bootloader unlocking by consumers often use this approach.


I decided to see if would be possible to modify the bootloader to swap between a signed and unsigned Android image between these two calls. If this was successful, I would be able to execute an unsigned Android image, without unlocking the bootloader and gain full access to the encrypted userdata partition.

3a8082e126
Reply all
Reply to author
Forward
0 new messages