comparison rvinterf/lowlevel/tfc139.c @ 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
comparison
equal deleted inserted replaced
983:7166c8311b0d 984:8c83777f856c
1 /* 1 /*
2 * This program is a contender for the title of the ugliest hack 2 * This program facilitates the recovery of those Compal/Motorola phones
3 * in the FreeCalypso project. It will attempt to break into a 3 * whose bootloaders have been maliciously locked down. It connects
4 * locked-down TracFone C139 by mimicking the actions of the 4 * to a running Mot C1xx firmware through the RVTMUX interface provided
5 * mot931c.exe TF "unlocker". 5 * by the latter and uses the Test Mode memory write command (which
6 * these firmwares implement just like TI's reference fw) to inject
7 * some shellcode and to transfer control to it by overwriting a
8 * function return address on the stack. The injected shellcode then
9 * enables the Calypso boot ROM and jumps to it, allowing fc-loadtool
10 * to take over from there.
6 */ 11 */
7 12
8 #include <sys/types.h> 13 #include <sys/types.h>
9 #include <sys/errno.h> 14 #include <sys/errno.h>
10 #include <stdio.h> 15 #include <stdio.h>
46 0x02, 0xF8, 0xFF, 0xFF, 0x00, 0x58, 0xFF, 0xFF, 51 0x02, 0xF8, 0xFF, 0xFF, 0x00, 0x58, 0xFF, 0xFF,
47 0x10, 0xFB, 0xFF, 0xFF, 0x02, 0x02, 0x02, 0x4F, 52 0x10, 0xFB, 0xFF, 0xFF, 0x02, 0x02, 0x02, 0x4F,
48 0x4B, 0x02 53 0x4B, 0x02
49 }; 54 };
50 55
51 static unsigned shellcode_load_addr = 0x800000; 56 static unsigned shellcode_load_addr;
52 static unsigned stack_smash_addr = 0x837C54; 57 static unsigned stack_smash_addr;
53 static int thumb_entry = 0; 58 static int thumb_entry = 1;
54 59
55 static u_char stack_smash_payload[4]; 60 static u_char stack_smash_payload[4];
61 static int breakin_in_progress;
56 62
57 static char *target_tty_port; 63 static char *target_tty_port;
58 64
59 static void 65 static void
60 send_compal_memwrite(addr, payload, payload_len) 66 send_compal_memwrite(addr, payload, payload_len)
78 pkt[i] = csum; 84 pkt[i] = csum;
79 send_pkt_to_target(pkt, i + 1); 85 send_pkt_to_target(pkt, i + 1);
80 } 86 }
81 87
82 static void 88 static void
83 build_stack_smash_payload() 89 initiate_breakin()
84 { 90 {
91 char msgbuf[80];
85 unsigned jump_addr; 92 unsigned jump_addr;
86 93
94 sprintf(msgbuf,
95 "Using shellcode load addr 0x%x, stack smash starting addr 0x%x",
96 shellcode_load_addr, stack_smash_addr);
97 output_line(msgbuf);
87 jump_addr = shellcode_load_addr; 98 jump_addr = shellcode_load_addr;
88 if (thumb_entry) 99 if (thumb_entry)
89 jump_addr += 1; 100 jump_addr += 1;
90 else 101 else
91 jump_addr += 4; 102 jump_addr += 4;
92 stack_smash_payload[0] = jump_addr; 103 stack_smash_payload[0] = jump_addr;
93 stack_smash_payload[1] = jump_addr >> 8; 104 stack_smash_payload[1] = jump_addr >> 8;
94 stack_smash_payload[2] = jump_addr >> 16; 105 stack_smash_payload[2] = jump_addr >> 16;
95 stack_smash_payload[3] = jump_addr >> 24; 106 stack_smash_payload[3] = jump_addr >> 24;
107 output_line("Sending shellcode RAM write");
108 send_compal_memwrite(shellcode_load_addr, shellcode, sizeof shellcode);
109 breakin_in_progress = 1;
110 }
111
112 static void
113 send_memcheck_query()
114 {
115 u_char sendpkt[25];
116
117 output_line("Sending GPF MEMCHECK query");
118 /* fill out the packet */
119 sendpkt[0] = RVT_L23_HEADER;
120 sendpkt[1] = 0xB7; /* system prim */
121 sendpkt[2] = 20;
122 sendpkt[3] = 0;
123 /* send zeros for the timestamp */
124 sendpkt[4] = 0;
125 sendpkt[5] = 0;
126 sendpkt[6] = 0;
127 sendpkt[7] = 0;
128 /* fixed string with all fields */
129 strcpy(sendpkt + 8, "PCO L1 MEMCHECK");
130 /* send it! */
131 send_pkt_to_target(sendpkt, 24);
96 } 132 }
97 133
98 main(argc, argv) 134 main(argc, argv)
99 char **argv; 135 char **argv;
100 { 136 {
102 extern int optind; 138 extern int optind;
103 int c; 139 int c;
104 fd_set fds; 140 fd_set fds;
105 141
106 baudrate_name = "57600"; /* what C139 firmware uses */ 142 baudrate_name = "57600"; /* what C139 firmware uses */
107 while ((c = getopt(argc, argv, "a:B:l:s:tw:")) != EOF) 143 while ((c = getopt(argc, argv, "a:AB:l:s:w:")) != EOF)
108 switch (c) { 144 switch (c) {
109 case 'a': 145 case 'a':
110 shellcode_load_addr = strtoul(optarg, 0, 16); 146 shellcode_load_addr = strtoul(optarg, 0, 16);
111 continue; 147 continue;
148 case 'A':
149 thumb_entry = 0;
150 continue;
112 case 'B': 151 case 'B':
113 baudrate_name = optarg; 152 baudrate_name = optarg;
114 continue; 153 continue;
115 case 'l': 154 case 'l':
116 logfname = optarg; 155 logfname = optarg;
117 continue; 156 continue;
118 case 's': 157 case 's':
119 stack_smash_addr = strtoul(optarg, 0, 16); 158 stack_smash_addr = strtoul(optarg, 0, 16);
120 continue;
121 case 't':
122 thumb_entry = 1;
123 continue; 159 continue;
124 case 'w': 160 case 'w':
125 wakeup_after_sec = strtoul(optarg, 0, 0); 161 wakeup_after_sec = strtoul(optarg, 0, 0);
126 continue; 162 continue;
127 case '?': 163 case '?':
130 "usage: %s [options] ttyport\n", argv[0]); 166 "usage: %s [options] ttyport\n", argv[0]);
131 exit(1); 167 exit(1);
132 } 168 }
133 if (argc - optind != 1) 169 if (argc - optind != 1)
134 goto usage; 170 goto usage;
171 if (stack_smash_addr && !shellcode_load_addr) {
172 fprintf(stderr, "usage error: -a option required with -s\n");
173 exit(1);
174 }
135 open_target_serial(argv[optind]); 175 open_target_serial(argv[optind]);
136 target_tty_port = argv[optind]; 176 target_tty_port = argv[optind];
137 177
138 set_serial_nonblock(0); 178 set_serial_nonblock(0);
139 setlinebuf(stdout); 179 setlinebuf(stdout);
145 } 185 }
146 setlinebuf(logF); 186 setlinebuf(logF);
147 fprintf(logF, "*** Log of TFC139 break-in session ***\n"); 187 fprintf(logF, "*** Log of TFC139 break-in session ***\n");
148 } 188 }
149 time(&logtime); 189 time(&logtime);
150 output_line("Sending shellcode RAM write"); 190 if (stack_smash_addr)
151 send_compal_memwrite(shellcode_load_addr, shellcode, sizeof shellcode); 191 initiate_breakin();
152 build_stack_smash_payload(); 192 else
193 send_memcheck_query();
153 for (;;) { 194 for (;;) {
154 FD_ZERO(&fds); 195 FD_ZERO(&fds);
155 FD_SET(target_fd, &fds); 196 FD_SET(target_fd, &fds);
156 c = select(target_fd+1, &fds, 0, 0, 0); 197 c = select(target_fd+1, &fds, 0, 0, 0);
157 time(&logtime); 198 time(&logtime);
169 static void 210 static void
170 handle_tm_response() 211 handle_tm_response()
171 { 212 {
172 char msgbuf[80]; 213 char msgbuf[80];
173 214
215 if (!breakin_in_progress) {
216 output_line("TM response unexpected at this time");
217 return;
218 }
174 if (rxpkt_len != 4 || rxpkt[1] != 0x40 || rxpkt[2] || rxpkt[3] != 0x40){ 219 if (rxpkt_len != 4 || rxpkt[1] != 0x40 || rxpkt[2] || rxpkt[3] != 0x40){
175 output_line("TM response differs from expected"); 220 output_line("TM response differs from expected");
176 return; 221 return;
177 } 222 }
178 sprintf(msgbuf, "Sending stack smash write at 0x%x", stack_smash_addr); 223 sprintf(msgbuf, "Sending stack smash write at 0x%x", stack_smash_addr);
179 output_line(msgbuf); 224 output_line(msgbuf);
180 send_compal_memwrite(stack_smash_addr, stack_smash_payload, 4); 225 send_compal_memwrite(stack_smash_addr, stack_smash_payload, 4);
181 stack_smash_addr += 4; 226 stack_smash_addr += 4;
227 }
228
229 static void
230 analyze_gpf_packet()
231 {
232 unsigned stackbase, untouched;
233 static char format[] =
234 "Name:L1 Stat:%*s Count:%*s Prio:%*s Stack:%x Size:%*s Untouched:%u";
235 char msgbuf[80];
236
237 if (rxpkt_len < 17 || rxpkt_len > 128)
238 return;
239 /* it needs to be a trace packet */
240 if ((rxpkt[1] & 0xF0) != 0xA0)
241 return;
242 /* check the length */
243 if (rxpkt[2] + 4 != rxpkt_len)
244 return;
245 if (rxpkt[3])
246 return;
247 /* skip timestamp, check src and dest */
248 if (strncmp(rxpkt + 8, "SYSTPCO ", 8))
249 return;
250 /* terminating NUL for sscanf */
251 rxpkt[rxpkt_len] = '\0';
252 if (sscanf(rxpkt, format, &stackbase, &untouched) != 2)
253 return;
254 /* success! */
255 sprintf(msgbuf,
256 "Parsed L1 stack location: base=0x%x, untouched=%u (0x%x)",
257 stackbase, untouched, untouched);
258 output_line(msgbuf);
259 if (stackbase & 3) {
260 output_line("Error: stack base address is not word-aligned");
261 exit(1);
262 }
263 untouched &= ~3;
264 if (!shellcode_load_addr) {
265 if (untouched < sizeof shellcode) {
266 output_line("Error: not enough room for shellcode");
267 exit(1);
268 }
269 shellcode_load_addr = stackbase;
270 }
271 stack_smash_addr = stackbase + untouched;
272 initiate_breakin();
182 } 273 }
183 274
184 handle_rx_packet() 275 handle_rx_packet()
185 { 276 {
186 if (rxpkt_len == 2 && rxpkt[0] == 'O' && rxpkt[1] == 'K') { 277 if (rxpkt_len == 2 && rxpkt[0] == 'O' && rxpkt[1] == 'K') {
199 case RVT_L1_HEADER: 290 case RVT_L1_HEADER:
200 print_l1_trace(); 291 print_l1_trace();
201 return; 292 return;
202 case RVT_L23_HEADER: 293 case RVT_L23_HEADER:
203 print_g23_trace(); 294 print_g23_trace();
295 if (!breakin_in_progress)
296 analyze_gpf_packet();
204 return; 297 return;
205 case RVT_TM_HEADER: 298 case RVT_TM_HEADER:
206 print_tm_output_raw(); 299 print_tm_output_raw();
207 handle_tm_response(); 300 handle_tm_response();
208 return; 301 return;