]>
Commit | Line | Data |
---|---|---|
1 | //----------------------------------------------------------------------------- | |
2 | // Copyright (C) 2015 iceman <iceman at iuse.se> | |
3 | // | |
4 | // This code is licensed to you under the terms of the GNU GPL, version 2 or, | |
5 | // at your option, any later version. See the LICENSE.txt file for the text of | |
6 | // the license. | |
7 | //----------------------------------------------------------------------------- | |
8 | // CRC Calculations from the software reveng commands | |
9 | //----------------------------------------------------------------------------- | |
10 | ||
11 | #ifdef _WIN32 | |
12 | # include <io.h> | |
13 | # include <fcntl.h> | |
14 | # ifndef STDIN_FILENO | |
15 | # define STDIN_FILENO 0 | |
16 | # endif /* STDIN_FILENO */ | |
17 | #endif /* _WIN32 */ | |
18 | ||
19 | #include <stdio.h> | |
20 | #include <string.h> | |
21 | #include <stdlib.h> | |
22 | #include <ctype.h> | |
23 | #include "cmdmain.h" | |
24 | #include "cmdcrc.h" | |
25 | #include "reveng/reveng.h" | |
26 | #include "ui.h" | |
27 | #include "util.h" | |
28 | ||
29 | #define MAX_ARGS 20 | |
30 | ||
31 | int uerr(char *msg){ | |
32 | PrintAndLog("%s",msg); | |
33 | return 0; | |
34 | } | |
35 | ||
36 | int split(char *str, char *arr[MAX_ARGS]){ | |
37 | int beginIndex = 0; | |
38 | int endIndex; | |
39 | int maxWords = MAX_ARGS; | |
40 | int wordCnt = 0; | |
41 | ||
42 | while(1){ | |
43 | while(isspace(str[beginIndex])){ | |
44 | ++beginIndex; | |
45 | } | |
46 | if(str[beginIndex] == '\0') { | |
47 | break; | |
48 | } | |
49 | endIndex = beginIndex; | |
50 | while (str[endIndex] && !isspace(str[endIndex])){ | |
51 | ++endIndex; | |
52 | } | |
53 | int len = endIndex - beginIndex; | |
54 | char *tmp = calloc(len + 1, sizeof(char)); | |
55 | memcpy(tmp, &str[beginIndex], len); | |
56 | arr[wordCnt++] = tmp; | |
57 | //PrintAndLog("DEBUG cnt: %d, %s",wordCnt-1, arr[wordCnt-1]); | |
58 | beginIndex = endIndex; | |
59 | if (wordCnt == maxWords) | |
60 | break; | |
61 | } | |
62 | return wordCnt; | |
63 | } | |
64 | ||
65 | int CmdCrc(const char *Cmd) | |
66 | { | |
67 | char name[] = {"reveng "}; | |
68 | char Cmd2[50 + 7]; | |
69 | memcpy(Cmd2, name, 7); | |
70 | memcpy(Cmd2 + 7, Cmd, 50); | |
71 | char *argv[MAX_ARGS]; | |
72 | int argc = split(Cmd2, argv); | |
73 | ||
74 | if (argc == 3 && memcmp(argv[1],"-g",2)==0) { | |
75 | CmdrevengSearch(argv[2]); | |
76 | } else { | |
77 | reveng_main(argc, argv); | |
78 | } | |
79 | //PrintAndLog("DEBUG argc: %d, %s %s Cmd: %s",argc, argv[0], Cmd2, Cmd); | |
80 | for(int i = 0; i < argc; ++i){ | |
81 | free(argv[i]); | |
82 | } | |
83 | ||
84 | return 0; | |
85 | } | |
86 | ||
87 | //returns array of model names and the count of models returning | |
88 | // as well as a width array for the width of each model | |
89 | int GetModels(char *Models[], int *count, uint8_t *width){ | |
90 | /* default values */ | |
91 | static model_t model = { | |
92 | PZERO, /* no CRC polynomial, user must specify */ | |
93 | PZERO, /* Init = 0 */ | |
94 | P_BE, /* RefIn = false, RefOut = false, plus P_RTJUST setting in reveng.h */ | |
95 | PZERO, /* XorOut = 0 */ | |
96 | PZERO, /* check value unused */ | |
97 | NULL /* no model name */ | |
98 | }; | |
99 | ||
100 | int ibperhx = 8;//, obperhx = 8; | |
101 | int rflags = 0, uflags = 0; /* search and UI flags */ | |
102 | poly_t apoly, crc, qpoly = PZERO, *apolys = NULL, *pptr = NULL, *qptr = NULL; | |
103 | model_t pset = model, *candmods, *mptr; | |
104 | ||
105 | /* stdin must be binary */ | |
106 | #ifdef _WIN32 | |
107 | _setmode(STDIN_FILENO, _O_BINARY); | |
108 | #endif /* _WIN32 */ | |
109 | ||
110 | SETBMP(); | |
111 | ||
112 | int args = 0, psets, pass; | |
113 | int Cnt = 0; | |
114 | if (width[0] == 0) { //reveng -D | |
115 | *count = mcount(); | |
116 | if(!*count) | |
117 | return uerr("no preset models available"); | |
118 | ||
119 | for(int mode = 0; mode < *count; ++mode) { | |
120 | mbynum(&model, mode); | |
121 | mcanon(&model); | |
122 | size_t size = (model.name && *model.name) ? strlen(model.name) : 6; | |
123 | char *tmp = calloc(size+1, sizeof(char)); | |
124 | if (tmp==NULL) | |
125 | return uerr("out of memory?"); | |
126 | ||
127 | memcpy(tmp, model.name, size); | |
128 | Models[mode] = tmp; | |
129 | width[mode] = plen(model.spoly); | |
130 | } | |
131 | mfree(&model); | |
132 | } else { //reveng -s | |
133 | ||
134 | if(~model.flags & P_MULXN) | |
135 | return uerr("cannot search for non-Williams compliant models"); | |
136 | ||
137 | praloc(&model.spoly, (unsigned long)width[0]); | |
138 | praloc(&model.init, (unsigned long)width[0]); | |
139 | praloc(&model.xorout, (unsigned long)width[0]); | |
140 | if(!plen(model.spoly)) | |
141 | palloc(&model.spoly, (unsigned long)width[0]); | |
142 | else | |
143 | width[0] = (uint8_t)plen(model.spoly); | |
144 | ||
145 | /* special case if qpoly is zero, search to end of range */ | |
146 | if(!ptst(qpoly)) | |
147 | rflags &= ~R_HAVEQ; | |
148 | ||
149 | ||
150 | /* not going to be sending additional args at this time (maybe future?) | |
151 | ||
152 | // allocate argument array | |
153 | args = argc - optind; | |
154 | if(!(apolys = malloc(args * sizeof(poly_t)))) | |
155 | return uerr("cannot allocate memory for argument list"); | |
156 | ||
157 | for(pptr = apolys; optind < argc; ++optind) { | |
158 | if(uflags & C_INFILE) | |
159 | *pptr++ = rdpoly(argv[optind], model.flags, ibperhx); | |
160 | else | |
161 | *pptr++ = strtop(argv[optind], model.flags, ibperhx); | |
162 | } | |
163 | // exit value of pptr is used hereafter! | |
164 | ||
165 | */ | |
166 | ||
167 | /* if endianness not specified, try | |
168 | * little-endian then big-endian. | |
169 | * NB: crossed-endian algorithms will not be | |
170 | * searched. | |
171 | */ | |
172 | /* scan against preset models */ | |
173 | if(~uflags & C_FORCE) { | |
174 | pass = 0; | |
175 | Cnt = 0; | |
176 | do { | |
177 | psets = mcount(); | |
178 | //PrintAndLog("psets: %d",psets); | |
179 | while(psets) { | |
180 | mbynum(&pset, --psets); | |
181 | ||
182 | /* skip if different width, or refin or refout don't match */ | |
183 | if(plen(pset.spoly) != width[0] || (model.flags ^ pset.flags) & (P_REFIN | P_REFOUT)) | |
184 | continue; | |
185 | /* skip if the preset doesn't match specified parameters */ | |
186 | if(rflags & R_HAVEP && pcmp(&model.spoly, &pset.spoly)) | |
187 | continue; | |
188 | if(rflags & R_HAVEI && psncmp(&model.init, &pset.init)) | |
189 | continue; | |
190 | if(rflags & R_HAVEX && psncmp(&model.xorout, &pset.xorout)) | |
191 | continue; | |
192 | ||
193 | //for additional args (not used yet, maybe future?) | |
194 | apoly = pclone(pset.xorout); | |
195 | if(pset.flags & P_REFOUT) | |
196 | prev(&apoly); | |
197 | ||
198 | for(qptr = apolys; qptr < pptr; ++qptr) { | |
199 | crc = pcrc(*qptr, pset.spoly, pset.init, apoly, 0); | |
200 | if(ptst(crc)) { | |
201 | pfree(&crc); | |
202 | break; | |
203 | } else | |
204 | pfree(&crc); | |
205 | } | |
206 | pfree(&apoly); | |
207 | if(qptr == pptr) { | |
208 | ||
209 | /* the selected model solved all arguments */ | |
210 | ||
211 | mcanon(&pset); | |
212 | ||
213 | size_t size = (pset.name && *pset.name) ? strlen(pset.name) : 6; | |
214 | //PrintAndLog("Size: %d, %s, count: %d",size,pset.name, Cnt); | |
215 | char *tmp = calloc(size+1, sizeof(char)); | |
216 | if (tmp==NULL){ | |
217 | PrintAndLog("out of memory?"); | |
218 | return 0; | |
219 | } | |
220 | width[Cnt] = width[0]; | |
221 | memcpy(tmp, pset.name, size); | |
222 | Models[Cnt++] = tmp; | |
223 | *count = Cnt; | |
224 | uflags |= C_RESULT; | |
225 | } | |
226 | } | |
227 | mfree(&pset); | |
228 | ||
229 | /* toggle refIn/refOut and reflect arguments */ | |
230 | if(~rflags & R_HAVERI) { | |
231 | model.flags ^= P_REFIN | P_REFOUT; | |
232 | for(qptr = apolys; qptr < pptr; ++qptr) | |
233 | prevch(qptr, ibperhx); | |
234 | } | |
235 | } while(~rflags & R_HAVERI && ++pass < 2); | |
236 | } | |
237 | //got everything now free the memory... | |
238 | ||
239 | if(uflags & C_RESULT) { | |
240 | for(qptr = apolys; qptr < pptr; ++qptr) | |
241 | pfree(qptr); | |
242 | } | |
243 | if(!(model.flags & P_REFIN) != !(model.flags & P_REFOUT)) | |
244 | return uerr("cannot search for crossed-endian models"); | |
245 | ||
246 | pass = 0; | |
247 | do { | |
248 | mptr = candmods = reveng(&model, qpoly, rflags, args, apolys); | |
249 | if(mptr && plen(mptr->spoly)) | |
250 | uflags |= C_RESULT; | |
251 | while(mptr && plen(mptr->spoly)) { | |
252 | mfree(mptr++); | |
253 | } | |
254 | free(candmods); | |
255 | if(~rflags & R_HAVERI) { | |
256 | model.flags ^= P_REFIN | P_REFOUT; | |
257 | for(qptr = apolys; qptr < pptr; ++qptr) | |
258 | prevch(qptr, ibperhx); | |
259 | } | |
260 | } while(~rflags & R_HAVERI && ++pass < 2); | |
261 | for(qptr = apolys; qptr < pptr; ++qptr) | |
262 | pfree(qptr); | |
263 | free(apolys); | |
264 | if(~uflags & C_RESULT) | |
265 | return uerr("no models found"); | |
266 | mfree(&model); | |
267 | } | |
268 | return 1; | |
269 | } | |
270 | ||
271 | //test call to GetModels | |
272 | int CmdrevengTest(const char *Cmd){ | |
273 | char *Models[80]; | |
274 | int count = 0; | |
275 | uint8_t widtharr[80] = {0}; | |
276 | uint8_t width = 0; | |
277 | width = param_get8(Cmd, 0); | |
278 | //PrintAndLog("width: %d",width); | |
279 | if (width > 89) | |
280 | return uerr("Width cannot exceed 89"); | |
281 | ||
282 | widtharr[0] = width; | |
283 | int ans = GetModels(Models, &count, widtharr); | |
284 | if (!ans) return 0; | |
285 | ||
286 | PrintAndLog("Count: %d",count); | |
287 | for (int i = 0; i < count; i++){ | |
288 | PrintAndLog("Model %d: %s, width: %d",i,Models[i], widtharr[i]); | |
289 | free(Models[i]); | |
290 | } | |
291 | return 1; | |
292 | } | |
293 | ||
294 | //-c || -v | |
295 | //inModel = valid model name string - CRC-8 | |
296 | //inHexStr = input hex string to calculate crc on | |
297 | //reverse = reverse calc option if true | |
298 | //endian = {0 = calc default endian input and output, b = big endian input and output, B = big endian output, r = right justified | |
299 | // l = little endian input and output, L = little endian output only, t = left justified} | |
300 | //result = calculated crc hex string | |
301 | int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *result){ | |
302 | /* default values */ | |
303 | static model_t model = { | |
304 | PZERO, // no CRC polynomial, user must specify | |
305 | PZERO, // Init = 0 | |
306 | P_BE, // RefIn = false, RefOut = false, plus P_RTJUST setting in reveng.h | |
307 | PZERO, // XorOut = 0 | |
308 | PZERO, // check value unused | |
309 | NULL // no model name | |
310 | }; | |
311 | int ibperhx = 8, obperhx = 8; | |
312 | int rflags = 0; // search flags | |
313 | int c; | |
314 | //unsigned long width; | |
315 | poly_t apoly, crc; | |
316 | ||
317 | char *string; | |
318 | ||
319 | // stdin must be binary | |
320 | #ifdef _WIN32 | |
321 | _setmode(STDIN_FILENO, _O_BINARY); | |
322 | #endif /* _WIN32 */ | |
323 | ||
324 | SETBMP(); | |
325 | //set model | |
326 | if(!(c = mbynam(&model, inModel))) { | |
327 | fprintf(stderr,"error: preset model '%s' not found. Use reveng -D to list presets.\n", inModel); | |
328 | return 0; | |
329 | } | |
330 | if(c < 0) | |
331 | return uerr("no preset models available"); | |
332 | ||
333 | // must set width so that parameter to -ipx is not zeroed | |
334 | //width = plen(model.spoly); | |
335 | rflags |= R_HAVEP | R_HAVEI | R_HAVERI | R_HAVERO | R_HAVEX; | |
336 | ||
337 | //set flags | |
338 | switch (endian) { | |
339 | case 'b': /* b big-endian (RefIn = false, RefOut = false ) */ | |
340 | model.flags &= ~P_REFIN; | |
341 | rflags |= R_HAVERI; | |
342 | /* fall through: */ | |
343 | case 'B': /* B big-endian output (RefOut = false) */ | |
344 | model.flags &= ~P_REFOUT; | |
345 | rflags |= R_HAVERO; | |
346 | mnovel(&model); | |
347 | /* fall through: */ | |
348 | case 'r': /* r right-justified */ | |
349 | model.flags |= P_RTJUST; | |
350 | break; | |
351 | case 'l': /* l little-endian input and output */ | |
352 | model.flags |= P_REFIN; | |
353 | rflags |= R_HAVERI; | |
354 | /* fall through: */ | |
355 | case 'L': /* L little-endian output */ | |
356 | model.flags |= P_REFOUT; | |
357 | rflags |= R_HAVERO; | |
358 | mnovel(&model); | |
359 | /* fall through: */ | |
360 | case 't': /* t left-justified */ | |
361 | model.flags &= ~P_RTJUST; | |
362 | break; | |
363 | } | |
364 | ||
365 | mcanon(&model); | |
366 | ||
367 | if (reverse) { | |
368 | // v calculate reversed CRC | |
369 | /* Distinct from the -V switch as this causes | |
370 | * the arguments and output to be reversed as well. | |
371 | */ | |
372 | // reciprocate Poly | |
373 | prcp(&model.spoly); | |
374 | ||
375 | /* mrev() does: | |
376 | * if(refout) prev(init); else prev(xorout); | |
377 | * but here the entire argument polynomial is | |
378 | * reflected, not just the characters, so RefIn | |
379 | * and RefOut are not inverted as with -V. | |
380 | * Consequently Init is the mirror image of the | |
381 | * one resulting from -V, and so we have: | |
382 | */ | |
383 | if(~model.flags & P_REFOUT) { | |
384 | prev(&model.init); | |
385 | prev(&model.xorout); | |
386 | } | |
387 | ||
388 | // swap init and xorout | |
389 | apoly = model.init; | |
390 | model.init = model.xorout; | |
391 | model.xorout = apoly; | |
392 | } | |
393 | // c calculate CRC | |
394 | ||
395 | // validate inputs | |
396 | /* if(plen(model.spoly) == 0) { | |
397 | * fprintf(stderr,"%s: no polynomial specified for -%c (add -w WIDTH -p POLY)\n", myname, mode); | |
398 | * exit(EXIT_FAILURE); | |
399 | * } | |
400 | */ | |
401 | ||
402 | /* in the Williams model, xorout is applied after the refout stage. | |
403 | * as refout is part of ptostr(), we reverse xorout here. | |
404 | */ | |
405 | if(model.flags & P_REFOUT) | |
406 | prev(&model.xorout); | |
407 | ||
408 | apoly = strtop(inHexStr, model.flags, ibperhx); | |
409 | ||
410 | if(reverse) | |
411 | prev(&apoly); | |
412 | ||
413 | crc = pcrc(apoly, model.spoly, model.init, model.xorout, model.flags); | |
414 | ||
415 | if(reverse) | |
416 | prev(&crc); | |
417 | ||
418 | string = ptostr(crc, model.flags, obperhx); | |
419 | for (int i = 0; i < 50; i++){ | |
420 | result[i] = string[i]; | |
421 | if (result[i]==0) break; | |
422 | } | |
423 | free(string); | |
424 | pfree(&crc); | |
425 | pfree(&apoly); | |
426 | return 1; | |
427 | } | |
428 | ||
429 | //test call to RunModel | |
430 | int CmdrevengTestC(const char *Cmd){ | |
431 | int cmdp = 0; | |
432 | char inModel[30] = {0x00}; | |
433 | char inHexStr[30] = {0x00}; | |
434 | char result[30]; | |
435 | int dataLen; | |
436 | char endian = 0; | |
437 | dataLen = param_getstr(Cmd, cmdp++, inModel, sizeof(inModel)); | |
438 | if (dataLen < 4) return 0; | |
439 | dataLen = param_getstr(Cmd, cmdp++, inHexStr, sizeof(inHexStr)); | |
440 | if (dataLen < 4) return 0; | |
441 | bool reverse = (param_get8(Cmd, cmdp++)) ? true : false; | |
442 | endian = param_getchar(Cmd, cmdp++); | |
443 | ||
444 | //PrintAndLog("mod: %s, hex: %s, rev %d", inModel, inHexStr, reverse); | |
445 | int ans = RunModel(inModel, inHexStr, reverse, endian, result); | |
446 | if (!ans) return 0; | |
447 | ||
448 | PrintAndLog("Result: %s",result); | |
449 | return 1; | |
450 | } | |
451 | ||
452 | //returns a calloced string (needs to be freed) | |
453 | char *SwapEndianStr(const char *inStr, const size_t len, const uint8_t blockSize){ | |
454 | char *tmp = calloc(len+1, sizeof(char)); | |
455 | for (uint8_t block=0; block < (uint8_t)(len/blockSize); block++){ | |
456 | for (size_t i = 0; i < blockSize; i+=2){ | |
457 | tmp[i+(blockSize*block)] = inStr[(blockSize-1-i-1)+(blockSize*block)]; | |
458 | tmp[i+(blockSize*block)+1] = inStr[(blockSize-1-i)+(blockSize*block)]; | |
459 | } | |
460 | } | |
461 | return tmp; | |
462 | } | |
463 | ||
464 | // takes hex string in and searches for a matching result (hex string must include checksum) | |
465 | int CmdrevengSearch(const char *Cmd){ | |
466 | char inHexStr[50] = {0x00}; | |
467 | int dataLen = param_getstr(Cmd, 0, inHexStr, sizeof(inHexStr)); | |
468 | if (dataLen < 4) return 0; | |
469 | ||
470 | char *Models[80]; | |
471 | int count = 0; | |
472 | uint8_t width[80]; | |
473 | width[0] = 0; | |
474 | uint8_t crcChars = 0; | |
475 | char result[30]; | |
476 | char revResult[30]; | |
477 | int ans = GetModels(Models, &count, width); | |
478 | bool found = false; | |
479 | if (!ans) return 0; | |
480 | ||
481 | // try each model and get result | |
482 | for (int i = 0; i < count; i++){ | |
483 | /*if (found) { | |
484 | free(Models[i]); | |
485 | continue; | |
486 | }*/ | |
487 | // round up to # of characters in this model's crc | |
488 | crcChars = ((width[i]+7)/8)*2; | |
489 | // can't test a model that has more crc digits than our data | |
490 | if (crcChars >= dataLen) | |
491 | continue; | |
492 | memset(result, 0, 30); | |
493 | char *inCRC = calloc(crcChars+1, sizeof(char)); | |
494 | memcpy(inCRC, inHexStr+(dataLen-crcChars), crcChars); | |
495 | ||
496 | char *outHex = calloc(dataLen-crcChars+1, sizeof(char)); | |
497 | memcpy(outHex, inHexStr, dataLen-crcChars); | |
498 | ||
499 | //PrintAndLog("DEBUG: dataLen: %d, crcChars: %d, Model: %s, CRC: %s, width: %d, outHex: %s",dataLen, crcChars, Models[i], inCRC, width[i], outHex); | |
500 | ans = RunModel(Models[i], outHex, false, 0, result); | |
501 | if (ans) { | |
502 | //test for match | |
503 | if (memcmp(result, inCRC, crcChars)==0){ | |
504 | PrintAndLog("\nFound a possible match!\nModel: %s\nValue: %s\n",Models[i], result); | |
505 | //optional - stop searching if found... | |
506 | found = true; | |
507 | } else { | |
508 | if (crcChars > 2){ | |
509 | char *swapEndian = SwapEndianStr(result, crcChars, crcChars); | |
510 | if (memcmp(swapEndian, inCRC, crcChars)==0){ | |
511 | PrintAndLog("\nFound a possible match!\nModel: %s\nValue EndianSwapped: %s\n",Models[i], swapEndian); | |
512 | //optional - stop searching if found... | |
513 | found = true; | |
514 | } | |
515 | free(swapEndian); | |
516 | } | |
517 | } | |
518 | } | |
519 | ||
520 | //if (!found){ | |
521 | ans = RunModel(Models[i], outHex, true, 0, revResult); | |
522 | if (ans) { | |
523 | //test for match | |
524 | if (memcmp(revResult, inCRC, crcChars)==0){ | |
525 | PrintAndLog("\nFound a possible match!\nModel Reversed: %s\nValue: %s\n",Models[i], revResult); | |
526 | //optional - stop searching if found... | |
527 | found = true; | |
528 | } else { | |
529 | if (crcChars > 2){ | |
530 | char *swapEndian = SwapEndianStr(revResult, crcChars, crcChars); | |
531 | if (memcmp(swapEndian, inCRC, crcChars)==0){ | |
532 | PrintAndLog("\nFound a possible match!\nModel Reversed: %s\nValue EndianSwapped: %s\n",Models[i], swapEndian); | |
533 | //optional - stop searching if found... | |
534 | found = true; | |
535 | } | |
536 | free(swapEndian); | |
537 | } | |
538 | } | |
539 | } | |
540 | //} | |
541 | free(inCRC); | |
542 | free(outHex); | |
543 | free(Models[i]); | |
544 | } | |
545 | if (!found) PrintAndLog("\nNo matches found\n"); | |
546 | return 1; | |
547 | } |