FreeCalypso > hg > freecalypso-tools
view rvinterf/lowlevel/tfc139.c @ 505:7bf0d909c87e
fc-loadtool flash ID check: change of reset after the check logic
This change only affects those flash configurations that have ID checks
enabled. The logic for resetting the flash after the ID check has been
changed as follows:
1) If the check fails, we return without attempting to reset the flash.
2) If the check is successful, we reset the flash using the configured
method (could be AMD or Intel or Intel W30) instead of always doing an
AMD flash reset as the original code did.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 27 May 2019 19:58:01 +0000 |
parents | 6f078c4a5506 |
children |
line wrap: on
line source
/* * 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> #include <sys/errno.h> #include <stdio.h> #include <string.h> #include <strings.h> #include <stdlib.h> #include <unistd.h> #include <time.h> #include "../include/pktmux.h" #include "../include/limits.h" extern int target_fd; extern u_char rxpkt[]; extern size_t rxpkt_len; char *logfname; FILE *logF; time_t logtime; int no_output; /* for output.c */ int wakeup_after_sec = 1; /* see ../../target-utils/tf-breakin/payload.S for the source */ static u_char shellcode[114] = { 0x78, 0x47, 0xC0, 0x46, 0xD3, 0xF0, 0x21, 0xE3, 0x50, 0x10, 0x9F, 0xE5, 0xF5, 0x00, 0xA0, 0xE3, 0xB2, 0x00, 0xC1, 0xE1, 0xA0, 0x00, 0xA0, 0xE3, 0xB2, 0x00, 0xC1, 0xE1, 0x40, 0x60, 0x9F, 0xE5, 0x05, 0x00, 0xD6, 0xE5, 0x20, 0x00, 0x10, 0xE3, 0xFC, 0xFF, 0xFF, 0x0A, 0x38, 0x10, 0x8F, 0xE2, 0x06, 0x20, 0xA0, 0xE3, 0x01, 0x00, 0xD1, 0xE4, 0x00, 0x00, 0xC6, 0xE5, 0x01, 0x20, 0x52, 0xE2, 0xFB, 0xFF, 0xFF, 0x1A, 0x05, 0x00, 0xD6, 0xE5, 0x40, 0x00, 0x10, 0xE3, 0xFC, 0xFF, 0xFF, 0x0A, 0x10, 0x10, 0x9F, 0xE5, 0x01, 0x2C, 0xA0, 0xE3, 0xB0, 0x20, 0xC1, 0xE1, 0x00, 0xF0, 0xA0, 0xE3, 0x02, 0xF8, 0xFF, 0xFF, 0x00, 0x58, 0xFF, 0xFF, 0x10, 0xFB, 0xFF, 0xFF, 0x02, 0x02, 0x02, 0x4F, 0x4B, 0x02 }; 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; static char *baudrate = "57600"; static void send_compal_memwrite(addr, payload, payload_len) unsigned addr; u_char *payload; { u_char pkt[MAX_PKT_TO_TARGET]; int i, csum, csum_offset; pkt[0] = RVT_TM_HEADER; pkt[1] = 0x40; /* old TM3 MEM_WRITE command */ pkt[2] = addr; pkt[3] = addr >> 8; pkt[4] = addr >> 16; pkt[5] = addr >> 24; bcopy(payload, pkt + 6, payload_len); csum_offset = payload_len + 6; csum = 0; for (i = 1; i < csum_offset; i++) csum ^= pkt[i]; pkt[i] = csum; send_pkt_to_target(pkt, i + 1); } static void 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; else jump_addr += 4; stack_smash_payload[0] = jump_addr; 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) char **argv; { extern char *optarg; extern int optind; int c; fd_set fds; while ((c = getopt(argc, argv, "a:AB:l:ms:w:")) != EOF) switch (c) { case 'a': shellcode_load_addr = strtoul(optarg, 0, 16); continue; case 'B': baudrate = optarg; continue; case 'l': logfname = optarg; continue; case 'm': /* mimic mot931c.exe */ shellcode_load_addr = 0x800000; stack_smash_addr = 0x837C54; /* FALL THRU */ case 'A': thumb_entry = 0; continue; case 's': stack_smash_addr = strtoul(optarg, 0, 16); continue; case 'w': wakeup_after_sec = strtoul(optarg, 0, 0); continue; case '?': default: usage: fprintf(stderr, "usage: %s [options] ttyport\n", argv[0]); exit(1); } 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_serial_port(argv[optind]); target_tty_port = argv[optind]; set_fixed_baudrate(baudrate); set_serial_nonblock(0); setlinebuf(stdout); if (logfname) { logF = fopen(logfname, "w"); if (!logF) { perror(logfname); exit(1); } setlinebuf(logF); fprintf(logF, "*** Log of TFC139 break-in session ***\n"); } time(&logtime); if (stack_smash_addr) initiate_breakin(); else send_memcheck_query(); for (;;) { FD_ZERO(&fds); FD_SET(target_fd, &fds); c = select(target_fd+1, &fds, 0, 0, 0); time(&logtime); if (c < 0) { if (errno == EINTR) continue; perror("select"); exit(1); } if (FD_ISSET(target_fd, &fds)) process_serial_rx(); } } static void handle_tm_response() { 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; } sprintf(msgbuf, "Sending stack smash write at 0x%x", stack_smash_addr); output_line(msgbuf); send_compal_memwrite(stack_smash_addr, stack_smash_payload, 4); 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 + 16, 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') { output_line( "Success: target should now be in boot ROM download wait"); printf("You can now run fc-loadtool -h compal -c none %s\n", target_tty_port); exit(0); } switch (rxpkt[0]) { case RVT_RV_HEADER: if (rxpkt_len < 6) goto unknown; print_rv_trace(); return; case RVT_L1_HEADER: print_l1_trace(); return; case RVT_L23_HEADER: print_g23_trace(); if (!breakin_in_progress) analyze_gpf_packet(); return; case RVT_TM_HEADER: print_tm_output_raw(); handle_tm_response(); return; default: unknown: print_unknown_packet(); } }