]> cvs.zerfleddert.de Git - proxmark3-svn/blame - client/prox.c
cleaning up endless copy-paste of trace functionality
[proxmark3-svn] / client / prox.c
CommitLineData
6658905f 1#include <windows.h>\r
2#include <setupapi.h>\r
3#include <stdio.h>\r
4#include <ctype.h>\r
5#include <stdlib.h>\r
a99c6a19 6//extern "C" {\r
7#include "include/hidusage.h"\r
6658905f 8#include "include/hidpi.h"\r
a99c6a19 9#include "include/hidsdi.h"\r
10//}\r
6658905f 11\r
12#include "prox.h"\r
13\r
14#define OUR_VID 0x9ac4\r
15#define OUR_PID 0x4b8f\r
3cc63bdf 16#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)\r
6658905f 17\r
9760414b 18int offline = 0;\r
6658905f 19HANDLE UsbHandle;\r
9b255608 20extern unsigned int current_command;\r
6658905f 21\r
22static void ShowError(void)\r
23{\r
24 char buf[1024];\r
25 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,\r
26 buf, sizeof(buf), NULL);\r
27 printf("ERROR: %s", buf);\r
28}\r
29\r
30static BOOL UsbConnect(void)\r
31{\r
32 typedef void (__stdcall *GetGuidProc)(GUID *);\r
33 typedef BOOLEAN (__stdcall *GetAttrProc)(HANDLE, HIDD_ATTRIBUTES *);\r
34 typedef BOOLEAN (__stdcall *GetPreparsedProc)(HANDLE,\r
35 PHIDP_PREPARSED_DATA *);\r
36 typedef NTSTATUS (__stdcall *GetCapsProc)(PHIDP_PREPARSED_DATA, PHIDP_CAPS);\r
37 GetGuidProc getGuid;\r
38 GetAttrProc getAttr;\r
39 GetPreparsedProc getPreparsed;\r
40 GetCapsProc getCaps;\r
41\r
42 HMODULE h = LoadLibrary("hid.dll");\r
43 getGuid = (GetGuidProc)GetProcAddress(h, "HidD_GetHidGuid");\r
44 getAttr = (GetAttrProc)GetProcAddress(h, "HidD_GetAttributes");\r
45 getPreparsed = (GetPreparsedProc)GetProcAddress(h, "HidD_GetPreparsedData");\r
46 getCaps = (GetCapsProc)GetProcAddress(h, "HidP_GetCaps");\r
47\r
48 GUID hidGuid;\r
49 getGuid(&hidGuid);\r
50\r
51 HDEVINFO devInfo;\r
52 devInfo = SetupDiGetClassDevs(&hidGuid, NULL, NULL,\r
53 DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);\r
54\r
55 SP_DEVICE_INTERFACE_DATA devInfoData;\r
56 devInfoData.cbSize = sizeof(devInfoData);\r
57\r
58 int i;\r
59 for(i = 0;; i++) {\r
60 if(!SetupDiEnumDeviceInterfaces(devInfo, 0, &hidGuid, i, &devInfoData))\r
61 {\r
62 if(GetLastError() != ERROR_NO_MORE_ITEMS) {\r
63// printf("SetupDiEnumDeviceInterfaces failed\n");\r
64 }\r
65// printf("done list\n");\r
66 SetupDiDestroyDeviceInfoList(devInfo);\r
67 return FALSE;\r
68 }\r
69\r
70// printf("item %d:\n", i);\r
71\r
72 DWORD sizeReqd = 0;\r
73 if(!SetupDiGetDeviceInterfaceDetail(devInfo, &devInfoData,\r
74 NULL, 0, &sizeReqd, NULL))\r
75 {\r
76 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) {\r
77// printf("SetupDiGetDeviceInterfaceDetail (0) failed\n");\r
78 continue;\r
79 }\r
80 }\r
81\r
82 SP_DEVICE_INTERFACE_DETAIL_DATA *devInfoDetailData =\r
83 (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(sizeReqd);\r
84 devInfoDetailData->cbSize = sizeof(*devInfoDetailData);\r
85\r
86 if(!SetupDiGetDeviceInterfaceDetail(devInfo, &devInfoData,\r
87 devInfoDetailData, 87, NULL, NULL))\r
88 {\r
89// printf("SetupDiGetDeviceInterfaceDetail (1) failed\n");\r
90 continue;\r
91 }\r
92\r
93 char *path = devInfoDetailData->DevicePath;\r
94\r
95 UsbHandle = CreateFile(path, /*GENERIC_READ |*/ GENERIC_WRITE,\r
96 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,\r
97 FILE_FLAG_OVERLAPPED, NULL);\r
98\r
99 if(UsbHandle == INVALID_HANDLE_VALUE) {\r
100 ShowError();\r
101// printf("CreateFile failed: for '%s'\n", path);\r
102 continue;\r
103 }\r
104\r
105 HIDD_ATTRIBUTES attr;\r
106 attr.Size = sizeof(attr);\r
107 if(!getAttr(UsbHandle, &attr)) {\r
108 ShowError();\r
109// printf("HidD_GetAttributes failed\n");\r
110 continue;\r
111 }\r
112\r
113// printf("VID: %04x PID %04x\n", attr.VendorID, attr.ProductID);\r
114\r
115 if(attr.VendorID != OUR_VID || attr.ProductID != OUR_PID) {\r
116 CloseHandle(UsbHandle);\r
117// printf(" nope, not us\n");\r
118 continue;\r
119 }\r
120\r
121// printf ("got it!\n");\r
122 CloseHandle(UsbHandle);\r
123\r
124 UsbHandle = CreateFile(path, GENERIC_READ | GENERIC_WRITE,\r
125 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,\r
126 FILE_FLAG_OVERLAPPED, NULL);\r
127\r
128 if(UsbHandle == INVALID_HANDLE_VALUE) {\r
129 ShowError();\r
130// printf("Error, couldn't open our own handle as desired.\n");\r
131 return FALSE;\r
132 }\r
133\r
134 PHIDP_PREPARSED_DATA pp;\r
135 getPreparsed(UsbHandle, &pp);\r
136 HIDP_CAPS caps;\r
137\r
138 if(getCaps(pp, &caps) != HIDP_STATUS_SUCCESS) {\r
139// printf("getcaps failed\n");\r
140 return FALSE;\r
141 }\r
142\r
143// printf("input/out report %d/%d\n", caps.InputReportByteLength,\r
144// caps.OutputReportByteLength);\r
145\r
146\r
147 return TRUE;\r
148 }\r
149 return FALSE;\r
150}\r
151\r
a99c6a19 152bool ReceiveCommandPoll(UsbCommand *c)\r
6658905f 153{\r
154 static BOOL ReadInProgress = FALSE;\r
155 static OVERLAPPED Ov;\r
156 static BYTE Buf[65];\r
157 static DWORD HaveRead;\r
158\r
159 if(!ReadInProgress) {\r
160 memset(&Ov, 0, sizeof(Ov));\r
161 ReadFile(UsbHandle, Buf, 65, &HaveRead, &Ov);\r
162 if(GetLastError() != ERROR_IO_PENDING) {\r
163 ShowError();\r
164 exit(-1);\r
165 }\r
166 ReadInProgress = TRUE;\r
167 }\r
168\r
169 if(HasOverlappedIoCompleted(&Ov)) {\r
170 ReadInProgress = FALSE;\r
171\r
172 if(!GetOverlappedResult(UsbHandle, &Ov, &HaveRead, FALSE)) {\r
173 ShowError();\r
174 exit(-1);\r
175 }\r
176\r
177 memcpy(c, Buf+1, 64);\r
178\r
179 return TRUE;\r
180 } else {\r
181 return FALSE;\r
182 }\r
183}\r
184\r
185void ReceiveCommand(UsbCommand *c)\r
186{\r
187 while(!ReceiveCommandPoll(c)) {\r
188 Sleep(0);\r
189 }\r
190}\r
191\r
9b255608 192void SendCommand(UsbCommand *c)\r
6658905f 193{\r
194 BYTE buf[65];\r
195 buf[0] = 0;\r
196 memcpy(buf+1, c, 64);\r
197\r
198 DWORD written;\r
199 OVERLAPPED ov;\r
0422e2a4 200\r
6658905f 201 memset(&ov, 0, sizeof(ov));\r
202 WriteFile(UsbHandle, buf, 65, &written, &ov);\r
203 if(GetLastError() != ERROR_IO_PENDING) {\r
204 ShowError();\r
205 exit(-1);\r
206 }\r
207\r
208 while(!HasOverlappedIoCompleted(&ov)) {\r
209 Sleep(0);\r
210 }\r
211\r
212 if(!GetOverlappedResult(UsbHandle, &ov, &written, FALSE)) {\r
213 ShowError();\r
214 exit(-1);\r
215 }\r
9b255608 216 current_command = c->cmd;\r
217}\r
6658905f 218\r
9b255608 219void WaitForAck(void) {\r
220 UsbCommand ack;\r
221 ReceiveCommand(&ack);\r
222 if(ack.cmd != CMD_ACK) {\r
223 printf("bad ACK\n");\r
224 exit(-1);\r
6658905f 225 }\r
226}\r
227\r
228static DWORD ExpectedAddr;\r
229static BYTE QueuedToSend[256];\r
230static BOOL AllWritten;\r
3cc63bdf 231#define PHYSICAL_FLASH_START 0x100000\r
232\r
233struct partition {\r
234 int start;\r
235 int end;\r
236 int precious;\r
237 const char *name;\r
238};\r
239struct partition partitions[] = {\r
240 {0x100000, 0x102000, 1, "bootrom"},\r
241 {0x102000, 0x110000, 0, "fpga"},\r
242 {0x110000, 0x140000, 0, "os"},\r
243};\r
244\r
245/* If translate is set, subtract PHYSICAL_FLASH_START to translate for old\r
246 * bootroms.\r
247 */\r
248static void FlushPrevious(int translate)\r
6658905f 249{\r
250 UsbCommand c;\r
251 memset(&c, 0, sizeof(c));\r
252\r
3cc63bdf 253// printf("expected = %08x flush, ", ExpectedAddr);\r
254\r
6658905f 255 int i;\r
256 for(i = 0; i < 240; i += 48) {\r
257 c.cmd = CMD_SETUP_WRITE;\r
258 memcpy(c.d.asBytes, QueuedToSend+i, 48);\r
3a8464f0 259 c.arg[0] = (i/4);\r
9b255608 260 SendCommand(&c);\r
261 WaitForAck();\r
6658905f 262 }\r
263\r
264 c.cmd = CMD_FINISH_WRITE;\r
3a8464f0 265 c.arg[0] = (ExpectedAddr-1) & (~255);\r
3cc63bdf 266 if(translate) {\r
3a8464f0 267 c.arg[0] -= PHYSICAL_FLASH_START;\r
3cc63bdf 268 }\r
3a8464f0 269 printf("Flashing address: %08x\r", c.arg[0]);\r
6658905f 270 memcpy(c.d.asBytes, QueuedToSend+240, 16);\r
9b255608 271 SendCommand(&c);\r
272 WaitForAck();\r
273 \r
6658905f 274 AllWritten = TRUE;\r
275}\r
276\r
3cc63bdf 277/* Where must be between start_addr (inclusive) and end_addr (exclusive).\r
278 */\r
279static void GotByte(int where, BYTE which, int start_addr, int end_addr, int translate)\r
6658905f 280{\r
281 AllWritten = FALSE;\r
282\r
3cc63bdf 283 if(where < start_addr || where >= end_addr) {\r
284 printf("bad: got byte at %08x, outside of range %08x-%08x\n", where, start_addr, end_addr);\r
285 exit(-1);\r
286 }\r
287\r
6658905f 288 if(where != ExpectedAddr) {\r
289 printf("bad: got at %08x, expected at %08x\n", where, ExpectedAddr);\r
290 exit(-1);\r
291 }\r
292 QueuedToSend[where & 255] = which;\r
293 ExpectedAddr++;\r
294\r
295 if((where & 255) == 255) {\r
296 // we have completed a full page\r
3cc63bdf 297 FlushPrevious(translate);\r
6658905f 298 }\r
299}\r
300\r
301static int HexVal(int c)\r
302{\r
303 c = tolower(c);\r
304 if(c >= '0' && c <= '9') {\r
305 return c - '0';\r
306 } else if(c >= 'a' && c <= 'f') {\r
307 return (c - 'a') + 10;\r
308 } else {\r
309 printf("bad hex digit '%c'\n", c);\r
310 exit(-1);\r
311 }\r
312}\r
313\r
314static BYTE HexByte(char *s)\r
315{\r
316 return (HexVal(s[0]) << 4) | HexVal(s[1]);\r
317}\r
318\r
3cc63bdf 319static void LoadFlashFromSRecords(const char *file, int start_addr, int end_addr, int translate)\r
6658905f 320{\r
3cc63bdf 321 ExpectedAddr = start_addr;\r
6658905f 322\r
323 FILE *f = fopen(file, "r");\r
324 if(!f) {\r
325 printf("couldn't open file\n");\r
326 exit(-1);\r
327 }\r
328\r
329 char line[512];\r
330 while(fgets(line, sizeof(line), f)) {\r
331 if(memcmp(line, "S3", 2)==0) {\r
332 char *s = line + 2;\r
333 int len = HexByte(s) - 5;\r
334 s += 2;\r
335\r
336 char addrStr[9];\r
337 memcpy(addrStr, s, 8);\r
338 addrStr[8] = '\0';\r
339 DWORD addr;\r
340 sscanf(addrStr, "%x", &addr);\r
341 s += 8;\r
342\r
3cc63bdf 343 /* Accept files that are located at PHYSICAL_FLASH_START, and files that are located at 0 */\r
344 if(addr < PHYSICAL_FLASH_START)\r
345 addr += PHYSICAL_FLASH_START;\r
346\r
6658905f 347 int i;\r
348 for(i = 0; i < len; i++) {\r
349 while((addr+i) > ExpectedAddr) {\r
3cc63bdf 350 GotByte(ExpectedAddr, 0xff, start_addr, end_addr, translate);\r
6658905f 351 }\r
3cc63bdf 352 GotByte(addr+i, HexByte(s), start_addr, end_addr, translate);\r
6658905f 353 s += 2;\r
354 }\r
355 }\r
356 }\r
357\r
3cc63bdf 358 if(!AllWritten) FlushPrevious(translate);\r
6658905f 359\r
360 fclose(f);\r
361 printf("\ndone.\n");\r
362}\r
363\r
3cc63bdf 364static int PrepareFlash(struct partition *p, const char *filename, unsigned int state)\r
365{\r
366 int translate = 0;\r
367 if(state & DEVICE_INFO_FLAG_UNDERSTANDS_START_FLASH) {\r
368 UsbCommand c;\r
369 c.cmd = CMD_START_FLASH;\r
3a8464f0 370 c.arg[0] = p->start;\r
371 c.arg[1] = p->end;\r
3cc63bdf 372\r
373 /* Only send magic when flashing bootrom */\r
374 if(p->precious) {\r
3a8464f0 375 c.arg[2] = START_FLASH_MAGIC;\r
3cc63bdf 376 } else {\r
3a8464f0 377 c.arg[2] = 0;\r
3cc63bdf 378 }\r
9b255608 379 SendCommand(&c);\r
380 WaitForAck();\r
3cc63bdf 381 translate = 0;\r
382 } else {\r
383 fprintf(stderr, "Warning: Your bootloader does not understand the new START_FLASH command\n");\r
384 fprintf(stderr, " It is recommended that you update your bootloader\n\n");\r
385 translate = 1;\r
386 }\r
387\r
388 LoadFlashFromSRecords(filename, p->start, p->end, translate);\r
389 return 1;\r
390}\r
391\r
392static unsigned int GetProxmarkState(void)\r
393{\r
394 unsigned int state = 0;\r
395\r
396 UsbCommand c;\r
397 c.cmd = CMD_DEVICE_INFO;\r
9b255608 398 SendCommand(&c);\r
3cc63bdf 399\r
400 UsbCommand resp;\r
401 ReceiveCommand(&resp);\r
402 /* Three cases:\r
403 * 1. The old bootrom code will ignore CMD_DEVICE_INFO, but respond with an ACK\r
404 * 2. The old os code will respond with CMD_DEBUG_PRINT_STRING and "unknown command"\r
405 * 3. The new bootrom and os codes will respond with CMD_DEVICE_INFO and flags\r
406 */\r
407\r
408 switch(resp.cmd) {\r
409 case CMD_ACK:\r
410 state = DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM;\r
411 break;\r
412 case CMD_DEBUG_PRINT_STRING:\r
413 state = DEVICE_INFO_FLAG_CURRENT_MODE_OS;\r
414 break;\r
415 case CMD_DEVICE_INFO:\r
3a8464f0 416 state = resp.arg[0];\r
3cc63bdf 417 break;\r
418 default:\r
419 fprintf(stderr, "Couldn't get proxmark state, bad response type: 0x%04X\n", resp.cmd);\r
420 exit(-1);\r
421 break;\r
422 }\r
423\r
424#if 0\r
425 if(state & DEVICE_INFO_FLAG_BOOTROM_PRESENT) printf("New bootrom present\n");\r
426 if(state & DEVICE_INFO_FLAG_OSIMAGE_PRESENT) printf("New osimage present\n");\r
427 if(state & DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM) printf("Currently in bootrom\n");\r
428 if(state & DEVICE_INFO_FLAG_CURRENT_MODE_OS) printf("Currently in OS\n");\r
429#endif\r
430\r
431 return state;\r
432}\r
433\r
434static unsigned int EnterFlashState(void)\r
435{\r
436 unsigned int state = GetProxmarkState();\r
437\r
438 if(state & DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM) {\r
439 /* Already in flash state, we're done. */\r
440 return state;\r
441 }\r
442\r
443 if(state & DEVICE_INFO_FLAG_CURRENT_MODE_OS) {\r
444 fprintf(stderr,"Entering flash-mode...\n");\r
445 UsbCommand c;\r
446 bzero(&c, sizeof(c));\r
447\r
448 if( (state & DEVICE_INFO_FLAG_BOOTROM_PRESENT) && (state & DEVICE_INFO_FLAG_OSIMAGE_PRESENT) ) {\r
449 /* New style handover: Send CMD_START_FLASH, which will reset the board and\r
450 * enter the bootrom on the next boot.\r
451 */\r
452 c.cmd = CMD_START_FLASH;\r
9b255608 453 SendCommand(&c);\r
3cc63bdf 454 fprintf(stderr,"(You don't have to do anything. Press and release the button only if you want to abort)\n");\r
455 fprintf(stderr,"Waiting for Proxmark to reappear on USB... ");\r
456 } else {\r
457 /* Old style handover: Ask the user to press the button, then reset the board */\r
458 c.cmd = CMD_HARDWARE_RESET;\r
9b255608 459 SendCommand(&c);\r
3cc63bdf 460 fprintf(stderr,"(Press and hold down button NOW if your bootloader requires it)\n");\r
461 fprintf(stderr,"Waiting for Proxmark to reappear on USB... ");\r
462 }\r
463\r
464\r
465 Sleep(1000);\r
466\r
467 while(!UsbConnect()) { Sleep(1000); }\r
468 fprintf(stderr,"Found.\n");\r
469\r
470 return GetProxmarkState();\r
471 }\r
472\r
473 return 0;\r
474}\r
475\r
476static void usage(char **argv)\r
477{\r
478 int i;\r
479 printf("Usage: %s gui\n", argv[0]);\r
480 printf(" %s offline\n", argv[0]);\r
481 printf(" %s areas file.s19\n", argv[0]);\r
482 printf(" Known areas are:");\r
483 for(i=0; i<(sizeof(partitions)/sizeof(partitions[0])); i++) {\r
484 fprintf(stderr, " %s", partitions[i].name);\r
485 }\r
486\r
487 printf("\n");\r
488}\r
489\r
490/* On first call, have *offset = -1, *length = 0; */\r
491static int find_next_area(char *str, int *offset, int *length)\r
492{\r
493 if(*str == '\0') return 0;\r
494 if((*offset >= 0) && str[*offset + *length] == '\0') return 0;\r
495 *offset += 1 + *length;\r
496\r
497 char *next_comma = strchr(str + *offset, ',');\r
498 if(next_comma == NULL) {\r
499 *length = strlen(str) - *offset;\r
500 } else {\r
501 *length = next_comma-(str+*offset);\r
502 }\r
503 return 1;\r
504}\r
505\r
6658905f 506int main(int argc, char **argv)\r
507{\r
508 int i = 0;\r
3cc63bdf 509\r
6658905f 510 if(argc < 2) {\r
3cc63bdf 511 usage(argv);\r
512 exit(-1);\r
6658905f 513 }\r
3cc63bdf 514\r
9760414b 515 // Only do this if NOT in offline mode\r
516 if (strcmp(argv[1], "offline"))\r
517 {\r
518 for(;;) {\r
519 if(UsbConnect()) {\r
520 break;\r
521 }\r
522 if(i == 0) {\r
523 printf("...no device connected, polling for it now\n");\r
524 }\r
525 if(i > 50000) {\r
526 printf("Could not connect to USB device; exiting.\n");\r
527 return -1;\r
528 }\r
529 i++;\r
530 Sleep(5);\r
6658905f 531 }\r
6658905f 532 }\r
3cc63bdf 533\r
534 if(strcmp(argv[1], "gui")==0) {\r
6658905f 535 ShowGui();\r
9760414b 536 } else if(strcmp(argv[1], "offline")==0) {\r
537 offline = 1;\r
538 ShowGui();\r
3cc63bdf 539 }\r
540\r
541 /* Count area arguments */\r
542 int areas = 0, offset=-1, length=0;\r
543 while(find_next_area(argv[1], &offset, &length)) areas++;\r
544\r
545 if(areas != argc - 2) {\r
546 usage(argv);\r
547 exit(-1);\r
548 }\r
549\r
550 unsigned int state = EnterFlashState();\r
551\r
552 if( !(state & DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM) ) {\r
553 fprintf(stderr, "Proxmark would not enter flash state, abort\n");\r
554 exit(-1);\r
555 }\r
556\r
557 offset=-1; length=0;\r
558 int current_area = 0;\r
559 while(find_next_area(argv[1], &offset, &length)) {\r
560 int i;\r
561 struct partition *p = NULL;\r
562 for(i=0; i<sizeof(partitions)/sizeof(partitions[0]); i++) {\r
563 if(strncmp(partitions[i].name, argv[1] + offset, length) == 0) {\r
564 /* Check if the name matches the bootrom partition, and if so, require "bootrom" to\r
565 * be written in full. The other names may be abbreviated.\r
566 */\r
567 if(!partitions[i].precious || (strlen(partitions[i].name) == length)) {\r
568 p = &partitions[i];\r
569 }\r
570 break;\r
571 }\r
6658905f 572 }\r
3cc63bdf 573\r
574 if(p == NULL) {\r
575 fprintf(stderr, "Warning: area name '");\r
576 fwrite(argv[1]+offset, length, 1, stderr);\r
577 fprintf(stderr, "' unknown, ignored\n");\r
578 } else {\r
579 fprintf(stderr, "Flashing %s from %s\n", p->name, argv[2+current_area]);\r
580 PrepareFlash(p, argv[2+current_area], state);\r
581 }\r
582 current_area++;\r
6658905f 583 }\r
584\r
585 return 0;\r
586}\r
Impressum, Datenschutz