FreeCalypso > hg > freecalypso-sw
changeset 984:8c83777f856c
tfc139 reworked for the new "universal" break-in method
author | Mychaela Falconia <falcon@ivan.Harhan.ORG> |
---|---|
date | Sat, 12 Dec 2015 03:17:12 +0000 |
parents | 7166c8311b0d |
children | 8109185528c1 |
files | rvinterf/lowlevel/tfc139.c |
diffstat | 1 files changed, 108 insertions(+), 15 deletions(-) [+] |
line wrap: on
line diff
--- a/rvinterf/lowlevel/tfc139.c Thu Dec 10 08:07:47 2015 +0000 +++ b/rvinterf/lowlevel/tfc139.c Sat Dec 12 03:17:12 2015 +0000 @@ -1,8 +1,13 @@ /* - * This program is a contender for the title of the ugliest hack - * in the FreeCalypso project. It will attempt to break into a - * locked-down TracFone C139 by mimicking the actions of the - * mot931c.exe TF "unlocker". + * This program facilitates the recovery of those Compal/Motorola phones + * whose bootloaders have been maliciously locked down. It connects + * to a running Mot C1xx firmware through the RVTMUX interface provided + * by the latter and uses the Test Mode memory write command (which + * these firmwares implement just like TI's reference fw) to inject + * some shellcode and to transfer control to it by overwriting a + * function return address on the stack. The injected shellcode then + * enables the Calypso boot ROM and jumps to it, allowing fc-loadtool + * to take over from there. */ #include <sys/types.h> @@ -48,11 +53,12 @@ 0x4B, 0x02 }; -static unsigned shellcode_load_addr = 0x800000; -static unsigned stack_smash_addr = 0x837C54; -static int thumb_entry = 0; +static unsigned shellcode_load_addr; +static unsigned stack_smash_addr; +static int thumb_entry = 1; static u_char stack_smash_payload[4]; +static int breakin_in_progress; static char *target_tty_port; @@ -80,10 +86,15 @@ } static void -build_stack_smash_payload() +initiate_breakin() { + char msgbuf[80]; unsigned jump_addr; + sprintf(msgbuf, + "Using shellcode load addr 0x%x, stack smash starting addr 0x%x", + shellcode_load_addr, stack_smash_addr); + output_line(msgbuf); jump_addr = shellcode_load_addr; if (thumb_entry) jump_addr += 1; @@ -93,6 +104,31 @@ stack_smash_payload[1] = jump_addr >> 8; stack_smash_payload[2] = jump_addr >> 16; stack_smash_payload[3] = jump_addr >> 24; + output_line("Sending shellcode RAM write"); + send_compal_memwrite(shellcode_load_addr, shellcode, sizeof shellcode); + breakin_in_progress = 1; +} + +static void +send_memcheck_query() +{ + u_char sendpkt[25]; + + output_line("Sending GPF MEMCHECK query"); + /* fill out the packet */ + sendpkt[0] = RVT_L23_HEADER; + sendpkt[1] = 0xB7; /* system prim */ + sendpkt[2] = 20; + sendpkt[3] = 0; + /* send zeros for the timestamp */ + sendpkt[4] = 0; + sendpkt[5] = 0; + sendpkt[6] = 0; + sendpkt[7] = 0; + /* fixed string with all fields */ + strcpy(sendpkt + 8, "PCO L1 MEMCHECK"); + /* send it! */ + send_pkt_to_target(sendpkt, 24); } main(argc, argv) @@ -104,11 +140,14 @@ fd_set fds; baudrate_name = "57600"; /* what C139 firmware uses */ - while ((c = getopt(argc, argv, "a:B:l:s:tw:")) != EOF) + while ((c = getopt(argc, argv, "a:AB:l:s:w:")) != EOF) switch (c) { case 'a': shellcode_load_addr = strtoul(optarg, 0, 16); continue; + case 'A': + thumb_entry = 0; + continue; case 'B': baudrate_name = optarg; continue; @@ -118,9 +157,6 @@ case 's': stack_smash_addr = strtoul(optarg, 0, 16); continue; - case 't': - thumb_entry = 1; - continue; case 'w': wakeup_after_sec = strtoul(optarg, 0, 0); continue; @@ -132,6 +168,10 @@ } if (argc - optind != 1) goto usage; + if (stack_smash_addr && !shellcode_load_addr) { + fprintf(stderr, "usage error: -a option required with -s\n"); + exit(1); + } open_target_serial(argv[optind]); target_tty_port = argv[optind]; @@ -147,9 +187,10 @@ fprintf(logF, "*** Log of TFC139 break-in session ***\n"); } time(&logtime); - output_line("Sending shellcode RAM write"); - send_compal_memwrite(shellcode_load_addr, shellcode, sizeof shellcode); - build_stack_smash_payload(); + if (stack_smash_addr) + initiate_breakin(); + else + send_memcheck_query(); for (;;) { FD_ZERO(&fds); FD_SET(target_fd, &fds); @@ -171,6 +212,10 @@ { char msgbuf[80]; + if (!breakin_in_progress) { + output_line("TM response unexpected at this time"); + return; + } if (rxpkt_len != 4 || rxpkt[1] != 0x40 || rxpkt[2] || rxpkt[3] != 0x40){ output_line("TM response differs from expected"); return; @@ -181,6 +226,52 @@ stack_smash_addr += 4; } +static void +analyze_gpf_packet() +{ + unsigned stackbase, untouched; + static char format[] = + "Name:L1 Stat:%*s Count:%*s Prio:%*s Stack:%x Size:%*s Untouched:%u"; + char msgbuf[80]; + + if (rxpkt_len < 17 || rxpkt_len > 128) + return; + /* it needs to be a trace packet */ + if ((rxpkt[1] & 0xF0) != 0xA0) + return; + /* check the length */ + if (rxpkt[2] + 4 != rxpkt_len) + return; + if (rxpkt[3]) + return; + /* skip timestamp, check src and dest */ + if (strncmp(rxpkt + 8, "SYSTPCO ", 8)) + return; + /* terminating NUL for sscanf */ + rxpkt[rxpkt_len] = '\0'; + if (sscanf(rxpkt, format, &stackbase, &untouched) != 2) + return; + /* success! */ + sprintf(msgbuf, + "Parsed L1 stack location: base=0x%x, untouched=%u (0x%x)", + stackbase, untouched, untouched); + output_line(msgbuf); + if (stackbase & 3) { + output_line("Error: stack base address is not word-aligned"); + exit(1); + } + untouched &= ~3; + if (!shellcode_load_addr) { + if (untouched < sizeof shellcode) { + output_line("Error: not enough room for shellcode"); + exit(1); + } + shellcode_load_addr = stackbase; + } + stack_smash_addr = stackbase + untouched; + initiate_breakin(); +} + handle_rx_packet() { if (rxpkt_len == 2 && rxpkt[0] == 'O' && rxpkt[1] == 'K') { @@ -201,6 +292,8 @@ return; case RVT_L23_HEADER: print_g23_trace(); + if (!breakin_in_progress) + analyze_gpf_packet(); return; case RVT_TM_HEADER: print_tm_output_raw();