Hello fellow hackers, I just pushed an update to our tfc139 host utility that makes it capable of breaking into (hopefully) *any* Mot C1xx phone that came with a maliciously locked bootloader, and not just TracFone-branded C139 units with fw version 8.8.17 it supported previously.
Background: back in the spring of 2014 I became aware of the existence of a Windows tool (binary w/o source) called mot931c.exe that unlocks one specific flock of phones with locked-down bootloaders: US-band C139 units with TracFone branding, fw version 8.8.17. A bit of reverse eng revealed how it works: it connects to the RVTMUX interface provided by Mot/Compal's TI-based fw (one needs to key in the **16379# magic sequence on the keypad to re-enable the UART on the headset jack), injects a piece of shellcode into the phone (using a raw memory write Test Mode command which we now know came straight from TI's reference fw, although at first I mistakenly thought it was Compal's non-std addition), causes this shellcode to gain execution with more memory writes that appear to smash a function return address on the stack, and once it gains code execution on the phone, it reflashes sector 0 with an unlocked bootloader version. Also back in the spring of 2014 I wrote FreeCalypso host utility tfc139 that reproduced one-for-one the just-described actions of mot931c.exe, but in a source-enabled Unix/Linux-based host program instead of Windows, and without the Heisenbergian action of immediately reflashing the boot sector without saving the old one first. I then used this tfc139 utility many a time to unlock and reflash TF-branded C139s from ebay, but it was still limited to these TF-branded units. My most recent ebay acquisition of a batch of C139s included three Cingular-branded units with fw version 1.9.24 in them, instead of the previously familiar to me version 1.0.24. Back in the spring of 2014 someone posted on the OsmocomBB mailing list about not being able to break into a phone with that fw version, so I prepared myself for the possibility of a locked-down bootloader - and sure enough, one of the 3 phones I got with this fw version has its bootloader locked down. (The other two did not have the lock activated, even though the provision for it is always present in this fw version.) At first I (and we as a community) lacked the ability to break into that locked-down phone with fw version 1.9.24: mot931c.exe wouldn't work on it as it queries the fw version before doing anything else, and if one ran our original tfc139 tool (exactly mimicking the actions of mot931c.exe, but without the version check) against this non-TF locked-down fw version, the result would be a firmware hang instead of a successful break-in. But the new tfc139 version which I just pushed into the freecalypso-sw repository breaks into this phone beautifully, and I expect it to work just as well with any other locked-down fw version that may be out there, without having any special a priori knowledge of particular fw versions. This breakthrough happened as a result of me taking a closer look at some of the oddities in mot931c.exe's break-in procedure, figuring out what that tool does wrong, and doing the same shellcode injection and seizure of code execution in a more proper way. Back when I reversed the operation of mot931c.exe a year and a half ago, one detail struck me as odd: it writes its shellcode at address 0x800000, the shellcode consists entirely of ARM instructions, not Thumb, it needs to be jumped to in the ARM instruction set state and not Thumb in order to execute correctly, and the payload given to the subsequent memory write commands (presumably seeking to smash the stack) is 00 00 80 00, that is, 0x800000 in the LE byte order: the least-significant bit is cleared, indicating ARM instruction set state. But the oddity is that most of the code in standard Calypso GSM firmwares is compiled in Thumb mode, and the ABI used by TI's compiler implements ARM/Thumb interworking in such a way that most functions compiled in Thumb mode effect the function return with a Thumb POP instruction. And here's the rub: on the ARM7TDMI only the BX instruction can switch between ARM and Thumb; LDR, LDM and POP writing into PC cannot. Thus if one smashes the return address on the stack while a Thumb function is executing, the jump to the shellcode will occur in the Thumb instruction set state no matter what the least- significant bit of the overwritten return address is set to. Now remember that I realized only recently that the TM memory write commands used by mot931c.exe come from TI's old reference fw code from pre-ETM days; previously I thought they were Compal's inventions. Thus back then I didn't give the ARM-instead-of-Thumb oddity much thought: I just figured that for one reason or another Compal had their TM memory write command implementation in a module compiled in ARM mode rather than Thumb. But now that we know that the memory write command in question comes from TI's reference fw, it wasn't difficult at all to find it in the object blob version of L1 that came with our TCS211: it is implemented in a function named l1tm_mem_write() in the l1tm_func.obj module in the l1_ext.lib blob library. And sure enough, this module is compiled in Thumb mode, such that the function in question became $l1tm_mem_write, and it performs its return with a POP instruction, i.e., if one smashes the stack used by this function, the jump will always happen in the Thumb state. I then did a binary grep to see if this $l1tm_mem_write Thumb function is present in the same verbatim form in various Mot C1xx firmwares, and sure enough, there it is, completely unchanged, identical to TI's version byte for byte. The question then becomes: how can mot931c.exe's break-in procedure possibly work if the fw function being exploited performs a Thumb-only return but the shellcode at the jump address expects to receive control in the ARM instruction set state? The answer came to me upon further investigation. As you should know from the Firmware_Architecture document I wrote a few months ago, there are many stacks in TI's fw architecture running under the control of Nucleus RTOS, and each component has its own stack. TI's old (non-enhanced) Test Mode commands are implemented within L1 and run in the context of the L1A task, thus the stack in effect when the memory write function executes is that of L1A. And it just so happens that one can easily determine the location of this L1A stack in an unknown fw version without any source or symbols or map file by querying the running fw itself: send a MEMCHECK system primitive to any GPF task (e.g., the very same L1), and GPF will respond with a flurry of trace messages about all GPF tasks (including L1), and this info includes the base address and size of each task's stack, and even how much of that stack space remains untouched. And guess what: the L1A stack in the TFC139 fw which mot931c.exe successfully breaks into turns out to be in a completely different place than where the "stack smashing" memory writes are hitting. Thus it turns out that mot931c.exe does its dirty job by smashing some other stack, not the one immediately in effect when the memory write function itself executes. It appears that whoever concocted that mot931c.exe hack did not understand the operation of the fw to the same degree as I do now, and only did a superficial job of finding some other stacks in the running fw's RAM usage. It appears that they just wrote the code that smashes the first stack they found staring at a RAM dump, by some dumb luck this not-properly-thought-out hack just happened to work with this fw version, and they declared their hack job to be good enough for their purposes. My newly reworked version of tfc139 does the break-in job in a *much* cleaner way. It first sends a GPF MEMCHECK query to the target fw, parses the response and thus determines the location of the L1A stack. It then smashes this L1A stack at the address provided by the to-be- broken-into fw itself, not some version-specific hard-coded address, and the shellcode now gains execution in the Thumb state, not ARM. Furthermore, because there is plenty of unused space in the "victim" L1A stack itself (at the lowest addresses of the allocated stack space), the shellcode itself is now written into that unused stack space instead of 0x800000. Thus the process no longer depends on the target fw not making use of the whatever code or data it has at that fixed address, and this new break-in procedure is expected to work with *all* existing Mot C1xx firmware versions, without requiring the user to do anything different: just run tfc139 /dev/ttyXXX. Now I need to update the documentation, and then put out a new packaged release of FreeCalypso host tools: this universal Mot C1xx unlocker definitely needs to be in a packaged end user release ASAP. :-) Happy hacking, Mychaela _______________________________________________ Community mailing list [email protected] https://www.freecalypso.org/mailman/listinfo/community
