FreeCalypso > hg > freecalypso-tools
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 } |