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