|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +author: Shomy |
| 4 | +title: "Unlocking the Motorola G23" |
| 5 | +date: 2025-02-13 |
| 6 | +categories: posts |
| 7 | +tags: |
| 8 | +- Android Modding |
| 9 | +- Bootloader Unlocking |
| 10 | +--- |
| 11 | + |
| 12 | +Unlocking the Motorola G23 was not an easy task, but we finally did it! |
| 13 | + |
| 14 | +In this article, I'll explain how I and a team of enthusiasts managed to unlock the bootloader of the Motorola G23, a device that was previously thought to be unlockable. |
| 15 | + |
| 16 | +## The Motorola G23 |
| 17 | + |
| 18 | +The Motorola Moto G23 is a smartphone that was released in January 2023. |
| 19 | +Out of the box, the device might seem quite clean and minimal, but that all changed when Android 14 came. |
| 20 | + |
| 21 | +I've been looking for to mod the device when Android 13 was still the latest version, but I couldn't find any information on XDA developers, or any other forums. |
| 22 | + |
| 23 | +So I started my own research. |
| 24 | + |
| 25 | +## The first tries |
| 26 | + |
| 27 | +I started by looking for known ways to unlock previous Motorola phones, starting by G22.<br> |
| 28 | + |
| 29 | +Here, I found out about how [mtkclient](https://github.com/bkerler/mtkclient) was used to unlock the bootloader on G22, so I thought giving it a try.<br> |
| 30 | +Unfortunately, the G23 BROM was blocked compared to G22, and only the preloader port was accessible.<br> |
| 31 | +This wouldn't be a problem, if only the preloader wasn't patched! Crash DA wasn't available, and the device would just reboot into preloader mode.<br><br> |
| 32 | + |
| 33 | +Just like that, I was stuck.<br><br> |
| 34 | + |
| 35 | +So, I tried extracting the firmware from the official rescue software, RSA, and I was able to find both the stock firmware and the flash tool, the latter being an encrypted zip file.<br> |
| 36 | +In the firmware I found a file named `MT6768_USER.bin`, which seemed to work at some extent.I tried using mtkclient's `da unlock` command, and it failed.<br> |
| 37 | +I knew RSA was able to flash stock firmware somehow, so tried getting the flash tool RSA used, and I was able to get the Flash Tool unencrypted by making RSA start a rescue, in which the tool had to be extracted beforehand.<br> |
| 38 | +In the Flash Tool, I've found another Download Agent, which I used with mtkclient, and this one booted too! Unfortunately, it seemed like the DA wasn't able to read partitions or flash anything.<br><br> |
| 39 | + |
| 40 | +Some months later, thanks to [@DiabloSat](https://github.com/progzone122), we were able to use this DA file to dump the firmware.<br><br> |
| 41 | + |
| 42 | +These tries were all made in early 2024, and I decided to just not bother with the device anymore, until Android 14 came. |
| 43 | + |
| 44 | +## The Helio G85 telegram group |
| 45 | + |
| 46 | +In late 2024, I once again tried to look up for an unlocking method for the device, because of how laggy the device became with Android 14. |
| 47 | +I searched for `penangf` (Moto G23 codename) on GitHub, and I found that someone was able to extract the Flash Tool from RSA, the same way I did.<br><br> |
| 48 | + |
| 49 | +I looked at the Flash Tool files once again, and thought about how I could use it to unlock the bootloader.<br> |
| 50 | +Unfortunately, as already said before, the Download Agent was not able to read partitions or flash anything that wasn't signed.<br> |
| 51 | +I decided to look up on telegram, and I found a group where people were discussing on ways to unlock the bootloader, and found out that [DiabloSat](https://github.com/progzone122), the same person which uploaded the flash tool on GitHub, was on the group.<br><br> |
| 52 | + |
| 53 | +For some time, I occasionally checked the group to see if someone managed to unlock the bootloader. Unfortunately, no one did.<br><br> |
| 54 | + |
| 55 | +Near Novemeber 2024, I decided to open an issue on the Flash Tool repository, after I've found out we could use other flash tools to flash the firmware.<br><br> |
| 56 | + |
| 57 | +Unfortunately, this concluded nothing, and I was stuck once again, and decided to once again occasionally check the group. |
| 58 | + |
| 59 | +## The testpoints |
| 60 | + |
| 61 | +Around December 2024, I found another repository popup with the schematics for the phone, and I found out that the device had testpoints, which could be used to force BROM. |
| 62 | + |
| 63 | +I decided to open an issue on the schematics repository, and I was able to get in touch with the DiabloSat, who uploaded the schematics. |
| 64 | + |
| 65 | +From that day to until February 2025, we decided to team up to finally unlock the bootloader of the phone.<br> |
| 66 | +We shared ideas, possible testpoints and more, but unfortunately, we couldn't find a way to force BROM. |
| 67 | + |
| 68 | +We started to document all the discoveries we made, which can be accessed [here](https://penangf.fuckyoumoto.xyz). |
| 69 | + |
| 70 | +In the meantime, I decided to decompile the bootloader and the preloader, to find out how the device worked, and I found out that the preloader should be able to. |
| 71 | + |
| 72 | +```c |
| 73 | +#define KPDL1 KPCOL0 // 0 |
| 74 | +#define KPDL2 PWRKEY_HW // 8 |
| 75 | +#define KPDL3 HOMEKEY_RST // 17 |
| 76 | + |
| 77 | +bool are_dl_keys_pressed() |
| 78 | +{ |
| 79 | + if(mtk_detect_key(KPDL1) && mtk_detect_key(KPDL2) && mtk_detect_key(KPDL3)) |
| 80 | + { |
| 81 | + pr_debug("dl keys are pressed\n"); |
| 82 | + return true; |
| 83 | + } |
| 84 | + |
| 85 | + return false; |
| 86 | +} |
| 87 | +``` |
| 88 | + |
| 89 | +```c |
| 90 | +#define MODULE "[PLFM]" |
| 91 | + |
| 92 | +void platform_emergency_download(int timeout) |
| 93 | +{ |
| 94 | + pr_debug("%S emergency download mode(timeout=%d)\n", MODULE, timeout); |
| 95 | + |
| 96 | + platform_safe_mode(1, timeout); |
| 97 | + |
| 98 | + mtk_arch_reset(0); |
| 99 | + |
| 100 | + while(1); |
| 101 | +} |
| 102 | +``` |
| 103 | +
|
| 104 | +One of these keys is the KPCOL0 testpoint, which was tested thanks to DiabloSat. |
| 105 | +
|
| 106 | + |
| 107 | +_Photo by DiabloSat_ |
| 108 | +
|
| 109 | +We were able to find the logs in the `expdb` partition, in which the phone seemed to indeed call the `platform_emergency_download` function, but unfortunately, the device would just reboot into preloader mode. |
| 110 | +
|
| 111 | +## Decompiling the bootloader |
| 112 | +
|
| 113 | +While DiabloSat was testing the testpoints and trying to force mtkclient to send the device to BROM, I decided to decompile **lk.img**, the bootloader of the device.<br> |
| 114 | +
|
| 115 | +There I found something really interesting, our device was indeed able to be unlocked, compared to what official sources said.<br> |
| 116 | +
|
| 117 | +The problem was, the device needed a key to be unlocked.<br> |
| 118 | +We were blocked again.<br> |
| 119 | +
|
| 120 | +But, one day Diablo found out about two important commands for us: `fastboot oem get_key` and `fastboot oem key <KEY>`.<br> |
| 121 | +
|
| 122 | +We had it, we thought.<br> |
| 123 | +The key from the first command, unfortunately, was not the one we were looking for.<br> |
| 124 | +Or so, we thought at first.<br><br> |
| 125 | +
|
| 126 | +I tried looking back at LK, and I found out the function that generates the key, which used a SHA256, and for a few days, we tried to reverse engineer the key, but we couldn't.<br> |
| 127 | +
|
| 128 | +Then for another week or two, we focused on trying again to force BROM, and Diablo contacted [R0rt1z2](https://github.com/R0rt1z2), who apparently had experience with MediaTek devices.<br> |
| 129 | +
|
| 130 | +Roger bought a Moto G13, and he tried to try some of the testpoints we found, but unfortunately, BROM was apparently blocked by efuse, and unfortunately, his device broke. |
| 131 | +
|
| 132 | +We thought about exploiting a buffer overflow, but then..<br><br> |
| 133 | +
|
| 134 | +I decided to finally reverse engineer how the key was generated from the phone. |
| 135 | +
|
| 136 | +```c |
| 137 | +#define UNLOCK_KEY_SIZE 32 |
| 138 | +#define SOC_ID "0123456789ABCDEF0123456789ABCDEF" // Generic SOC ID |
| 139 | +
|
| 140 | +int fastboot_flashing_unlock_chk_key(void) |
| 141 | +{ |
| 142 | + char unlock_key[UNLOCK_KEY_SIZE + 1]; |
| 143 | + unsigned char thing_to_hash[65] = {0}; |
| 144 | + unsigned char hashed_value[64] = {0}; |
| 145 | + int len; |
| 146 | +
|
| 147 | + memset(thing_to_hash, 0, 65); |
| 148 | +
|
| 149 | + len = strlen(SOC_ID); |
| 150 | + if (len == UNLOCK_KEY_SIZE) { |
| 151 | + fastboot_info(SOC_ID); |
| 152 | + mtk_memcpy(thing_to_hash, SOC_ID, UNLOCK_KEY_SIZE); |
| 153 | + mtk_memcpy(thing_to_hash + 32, thing_to_hash, 32); |
| 154 | +
|
| 155 | + fastboot_info("start fastboot unlock"); |
| 156 | + fastboot_info(fb_unlock_key_str); |
| 157 | +
|
| 158 | + printf("To hash: %s\n", thing_to_hash); |
| 159 | +
|
| 160 | + // This calculates the hash of the SOC_ID and stores it in hashed_value |
| 161 | + sha256(thing_to_hash, 64, hashed_value); |
| 162 | + |
| 163 | +
|
| 164 | + printf("Hash is: "); |
| 165 | + for (int i = 0; i < 32; i++) printf("%02x", hashed_value[i]); |
| 166 | +
|
| 167 | + printf("\n"); |
| 168 | +
|
| 169 | + len = compare_strings_until_length(fb_unlock_key_str, (char*)hashed_value, UNLOCK_KEY_SIZE); |
| 170 | + if (len != 0) { |
| 171 | + fastboot_fail("Unlock key code is incorrect!"); |
| 172 | + return 0x7001; |
| 173 | + } |
| 174 | +
|
| 175 | + fastboot_info("Unlock Success"); |
| 176 | + len = 0; |
| 177 | + } |
| 178 | + else { |
| 179 | + len = 0x7000; |
| 180 | + fastboot_fail("Unlock key length is incorrect!"); |
| 181 | + } |
| 182 | +
|
| 183 | + return len; |
| 184 | +} |
| 185 | +``` |
| 186 | + |
| 187 | +<img src="/media/posts/2025/unlock_key_algorithm.png" style="width: 50%; heigth: 50%"/> |
| 188 | + |
| 189 | +And just like that, I made a python script and asked the other members of the team to try it out. |
| 190 | + |
| 191 | +```python |
| 192 | + |
| 193 | +def oem_keygen(key: str) -> str: |
| 194 | + to_hash: str = key * 2 |
| 195 | + |
| 196 | + hash: str = sha256(to_hash.encode()).hexdigest() |
| 197 | + |
| 198 | + print("Unlock key: %s" % (hash[:32])) |
| 199 | + return hash |
| 200 | +``` |
| 201 | + |
| 202 | +```bash |
| 203 | +➜ fuckyoumoto git:(main) ✗ python oem_keygen.py 061A757D042B2A378D9761E60C9D3FBC |
| 204 | +Unlock key: 87f3aef774eb3edbcdef39e2e94d05c9 |
| 205 | + |
| 206 | +➜ fuckyoumoto git:(main) ✗ fastboot oem key 87f3aef774eb3edbcdef39e2e94d05c9 |
| 207 | +(bootloader) open fastboot unlock |
| 208 | +OKAY [ 0.000s] |
| 209 | +Finished. Total time: 0.000s |
| 210 | +➜ fuckyoumoto git:(main) ✗ fastboot flashing unlock |
| 211 | +(bootloader) Start unlock flow |
| 212 | + |
| 213 | +(bootloader) 061A757D042B2A378D9761E60C9D3FBC |
| 214 | +(bootloader) start fastboot unlock |
| 215 | +(bootloader) 87f3aef774eb3edbcdef39e2e94d05c9 |
| 216 | +(bootloader) Unlock Success |
| 217 | +(bootloader) fastboot unlock success |
| 218 | +OKAY [ 5.320s] |
| 219 | +Finished. Total time: 5.320s |
| 220 | +➜ fuckyoumoto git:(main) ✗ fastboot oem lks |
| 221 | +(bootloader) lks = 0 |
| 222 | +OKAY [ 0.005s] |
| 223 | +Finished. Total time: 0.005s |
| 224 | +``` |
| 225 | + |
| 226 | +> We did it.<br> |
| 227 | +> The bootloader got unlocked! |
| 228 | +
|
| 229 | +## Moving forward |
| 230 | + |
| 231 | +We were able to unlock the bootloader of the Motorola G23, and thanks to [Roger](https://github.com/R0rt1z2), who got another G13 with UART too, we were able to confirm that the same method worked on the G13. |
| 232 | + |
| 233 | +The days later were spent on trying to find a way to boot TWRP (thanks [@GitFASTBOOT](https://github.com/GitFASTBOOT) for making it), and testing GSIs.<br> |
| 234 | + |
| 235 | +<img src="/media/posts/2025/twrp_mainscreen.jpg" alt="TWRP main screen" style="width: 30%; heigth: 30%"/> |
| 236 | + |
| 237 | + |
| 238 | +The plans for the future are to try to port LineageOS, and spread the word about the device, and how it can be unlocked. |
| 239 | + |
| 240 | +## Chouchou (Custom bootloader) |
| 241 | + |
| 242 | +Now that the phone got unlocked, Roger decided to build a payload to inject code into LK, to be able to add new features to fastboot. |
| 243 | + |
| 244 | + |
| 245 | + |
| 246 | +This payload protects the device from being relocked and blocks flashing of protected partitions that might hard brick the device. |
| 247 | + |
| 248 | + |
| 249 | +## Video Guide |
| 250 | + |
| 251 | +<iframe height="315" src="https://www.youtube-nocookie.com/embed/3fHfiqM7UUg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> |
| 252 | + |
| 253 | +## Conclusion |
| 254 | + |
| 255 | +We finally were able to unlock the bootloader of the phone, after 2 years from its release date, finally making the device fully ours. |
| 256 | + |
| 257 | +Special thanks to DiabloSat, R0rt1z2 (Roger) for helping me out with this project, GitFASTBOOT for making TWRP, and everyone else who helped us out.<br><br> |
| 258 | + |
| 259 | + |
| 260 | + |
| 261 | +Check [our documentation](https://penangf.fuckyoumoto.xyz) for more information on the device! |
0 commit comments