Universal Mot C1xx unlocker

Mychaela Falconia falcon at ivan.Harhan.ORG
Sat Dec 12 06:59:53 CET 2015


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


More information about the Community mailing list