# HG changeset patch # User Michael Spacefalcon # Date 1396815639 0 # Node ID 597143ba1c37509cd3fc409cdf9b66a329e3a078 # Parent 03f8a618689eb6f5c032298d457385ca350a77a3 miscellaneous C programs moved out of the top level directory diff -r 03f8a618689e -r 597143ba1c37 .hgignore --- a/.hgignore Sat Apr 05 20:21:55 2014 +0000 +++ b/.hgignore Sun Apr 06 20:20:39 2014 +0000 @@ -2,13 +2,6 @@ \.[oa]$ -^atsc$ -^factdiff$ -^imeibrute$ -^mokosrec2bin$ -^pirimei$ -^rfcap-grep$ - ^arm7dis/armdis$ ^arm7dis/thumbdis$ @@ -17,6 +10,13 @@ ^compal/c156-boot\. ^compal/osmovoodoo +^miscprog/atsc$ +^miscprog/factdiff$ +^miscprog/imeibrute$ +^miscprog/mokosrec2bin$ +^miscprog/pirimei$ +^miscprog/rfcap-grep$ + ^mpffs/mpffs-cat$ ^mpffs/mpffs-dbgls$ ^mpffs/mpffs-ls$ diff -r 03f8a618689e -r 597143ba1c37 Makefile --- a/Makefile Sat Apr 05 20:21:55 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -CC= gcc -CFLAGS= -O2 -STD= atsc factdiff mokosrec2bin rfcap-grep -CRYPTO= imeibrute pirimei -PROGS= ${STD} ${CRYPTO} - -all: ${PROGS} - -${STD}: - ${CC} ${CFLAGS} -o $@ $@.c - -${CRYPTO}: - ${CC} ${CFLAGS} -o $@ $@.c -lcrypto - -atsc: atsc.c -factdiff: factdiff.c -imeibrute: imeibrute.c -mokosrec2bin: mokosrec2bin.c -pirimei: pirimei.c -rfcap-grep: rfcap-grep.c - -clean: - rm -f ${PROGS} *.o *errs *.out diff -r 03f8a618689e -r 597143ba1c37 atsc.c --- a/atsc.c Sat Apr 05 20:21:55 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * It is known that some GSM devices have undocumented AT commands for - * changing the IMEI. There is no standard syntax for such an AT command - * (by the "proper rules" one is not supposed to exist at all), and instead - * there seem to be several different ad hoc syntaxes. This source file, - * found on a Chinese site, implements one of these numerous ad hoc - * IMEI-changing AT commands: - * - * ftp://ftp.ifctf.org/pub/GSM/TI_src/ati_sc.c - * - * Notice that this particular incarnation of the "set IMEI" AT command - * is called AT@SC; there just happens to be an identically-named AT@SC - * command on Openmoko's GSM modems. Might it perchance be the same - * IMEI changing command? - * - * This program constructs what should be a valid input to the decoding - * logic in the ati_sc.c source above, for the purpose of testing whether - * or not such a command would indeed effect an IMEI change on a GTA02 modem. - */ - -#include -#include -#include -#include -#include - -static char hexdigits[] = "0123456789abcdef"; - -main(argc, argv) - char **argv; -{ - char hexout[16]; - unsigned n1, n2, cksum; - int i, c; - - if (argc != 2) { -usage: fprintf(stderr, "usage: %s 15-IMEI-digits\n", argv[0]); - exit(1); - } - if (strlen(argv[1]) != 15) - goto usage; - n1 = n2 = 0; - for (i = 0; i < 15; i++) { - c = argv[1][i]; - if (!isdigit(c)) - goto usage; - c -= '0'; - hexout[i] = hexdigits[c ^ 5]; - if (i < 7) - n1 = n1 * 10 + c; - else - n2 = n2 * 10 + c; - } - hexout[15] = '\0'; - cksum = (n1 + n2) % 1973; - printf("AT@SC=\"%s%04u\"\n", hexout, cksum); - exit(0); -} diff -r 03f8a618689e -r 597143ba1c37 factdiff.c --- a/factdiff.c Sat Apr 05 20:21:55 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* - * The 64 KiB "factory block" at the end of the 2nd flash chip select on - * Pirelli DP-L10 phones is believed to contain juicy info (IMEI and RF - * calibration data), but the format is yet to be cracked. - * - * This program compares Pirelli factory block images that have been read - * out of several phones, seeking to determine which bytes are always the - * same and which bytes change from specimen to specimen. - * - * Written by Spacefalcon the Outlaw. - */ - -#include -#include -#include -#include - -u_char specimen0[65536]; -char is_diff[65536]; - -read_specimen_file(filename, buf) - char *filename; - u_char *buf; -{ - int fd, cc; - - fd = open(filename, O_RDONLY); - if (fd < 0) { - perror(filename); - exit(1); - } - cc = read(fd, buf, 65536); - close(fd); - if (cc != 65536) { - fprintf(stderr, "%s: unable to read 64 KiB\n", filename); - exit(1); - } -} - -process_comp_specimen(filename) - char *filename; -{ - u_char this_spec[65536]; - int i; - - read_specimen_file(filename, this_spec); - for (i = 0; i < 65536; i++) - if (this_spec[i] != specimen0[i]) - is_diff[i] = 1; -} - -output() -{ - int off, state, cstart, num; - - for (off = 0; off < 65536; ) { - state = is_diff[off]; - cstart = off; - while (off < 65536 && is_diff[off] == state) - off++; - printf("%04X-%04X: %s", cstart, off-1, - state ? "varying" : "constant"); - if (state) { - num = off - cstart; - printf(" (%d byte%s)", num, num != 1 ? "s" : ""); - } - putchar('\n'); - } -} - -main(argc, argv) - char **argv; -{ - char **ap; - - if (argc < 3) { - fprintf(stderr, "usage: %s specimen0 specimen1 ...\n", argv[0]); - exit(1); - } - read_specimen_file(argv[1], specimen0); - for (ap = argv + 2; *ap; ap++) - process_comp_specimen(*ap); - output(); - exit(0); -} diff -r 03f8a618689e -r 597143ba1c37 imeibrute.c --- a/imeibrute.c Sat Apr 05 20:21:55 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* - * The IMEI "protection" implemented by TI for Calypso (as opposed to Calypso+ - * or LoCosto) platforms for those device manufs who desired to obfuscate their - * IMEIs (not everyone did - Openmoko opted out, for example), as seen in - * g23m/condat/com/src/comlib/cl_imei.c in the Leonardo semi-src by Sotovik, - * encrypts the IMEI using plain DES, using a key derived from the Calypso die - * ID. However, only 28 effective key bits are used, and the key is then also - * encrypted with itself and stored right after the encrypted IMEI, and is used - * by the decryption & verification routine. Per TI's source, the 16-byte - * encrypted IMEI record is to be stored in FFS in /gsm/imei.enc; the DP-L10 - * phone by Pirelli/Foxconn has been found to use the same scheme, but store - * the 16-byte record in question in their "factory block" instead, at absolute - * address 0x027F0504 as seen by the ARM7 CPU. - * - * The encryption scheme seems so weak to me (28 effective key bits and an easy - * hit detection criterion for a brute force cracker) that I decided to see, - * just for fun, how long it would take to crack that encryption by brute force - * alone, and using a totally non-optimized program to do that. - */ - -#include -#include -#include -#include - -DES_cblock ciphertext[2], dieid_key, decrypted[2]; -DES_key_schedule keysched; - -read_ciphertext(filename, offset_arg) - char *filename, *offset_arg; -{ - FILE *f; - u_long offset_val; - - f = fopen(filename, "r"); - if (!f) { - perror(filename); - exit(1); - } - if (offset_arg) { - offset_val = strtoul(offset_arg, 0, 16); - fseek(f, offset_val, 0); - } - fread(ciphertext, 8, 2, f); - fclose(f); -} - -print_des_cblock(msg, blk) - char *msg; - DES_cblock blk; -{ - printf("%s: %02X %02X %02X %02X %02X %02X %02X %02X\n", msg, - blk[0], blk[1], blk[2], blk[3], blk[4], blk[5], blk[6], blk[7]); -} - -try() -{ - DES_set_key_unchecked(&dieid_key, &keysched); - DES_ecb_encrypt(&ciphertext[1], &decrypted[1], &keysched, DES_DECRYPT); - if (decrypted[1][0] & 0xFE != dieid_key[0]) - return; - if (decrypted[1][1]) - return; - if (decrypted[1][2] & 0xFE != dieid_key[2]) - return; - if (decrypted[1][3]) - return; - if (decrypted[1][4] & 0xFE != dieid_key[4]) - return; - if (decrypted[1][5]) - return; - if (decrypted[1][6] & 0xFE != dieid_key[6]) - return; - if (decrypted[1][7]) - return; - print_des_cblock("Hit", &decrypted[1]); - DES_ecb_encrypt(&ciphertext[0], &decrypted[0], &keysched, DES_DECRYPT); - print_des_cblock("IMEI", &decrypted[0]); -} - -main(argc, argv) - char **argv; -{ - if (argc < 2 || argc > 3) { - fprintf(stderr, "usage: %s binfile [offset]\n", argv[0]); - exit(1); - } - read_ciphertext(argv[1], argv[2]); - dieid_key[1] = 0; - dieid_key[3] = 0; - dieid_key[5] = 0; - dieid_key[7] = 0; - for (dieid_key[0] = 0; dieid_key[0] <= 0xFE; dieid_key[0] += 2) - for (dieid_key[2] = 0; dieid_key[2] <= 0xFE; dieid_key[2] += 2) - for (dieid_key[4] = 0; dieid_key[4] <= 0xFE; dieid_key[4] += 2) - for (dieid_key[6] = 0; dieid_key[6] <= 0xFE; dieid_key[6] += 2) - try(); - exit(0); -} diff -r 03f8a618689e -r 597143ba1c37 miscprog/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/miscprog/Makefile Sun Apr 06 20:20:39 2014 +0000 @@ -0,0 +1,23 @@ +CC= gcc +CFLAGS= -O2 +STD= atsc factdiff mokosrec2bin rfcap-grep +CRYPTO= imeibrute pirimei +PROGS= ${STD} ${CRYPTO} + +all: ${PROGS} + +${STD}: + ${CC} ${CFLAGS} -o $@ $@.c + +${CRYPTO}: + ${CC} ${CFLAGS} -o $@ $@.c -lcrypto + +atsc: atsc.c +factdiff: factdiff.c +imeibrute: imeibrute.c +mokosrec2bin: mokosrec2bin.c +pirimei: pirimei.c +rfcap-grep: rfcap-grep.c + +clean: + rm -f ${PROGS} *.o *errs *.out diff -r 03f8a618689e -r 597143ba1c37 miscprog/atsc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/miscprog/atsc.c Sun Apr 06 20:20:39 2014 +0000 @@ -0,0 +1,58 @@ +/* + * It is known that some GSM devices have undocumented AT commands for + * changing the IMEI. There is no standard syntax for such an AT command + * (by the "proper rules" one is not supposed to exist at all), and instead + * there seem to be several different ad hoc syntaxes. This source file, + * found on a Chinese site, implements one of these numerous ad hoc + * IMEI-changing AT commands: + * + * ftp://ftp.ifctf.org/pub/GSM/TI_src/ati_sc.c + * + * Notice that this particular incarnation of the "set IMEI" AT command + * is called AT@SC; there just happens to be an identically-named AT@SC + * command on Openmoko's GSM modems. Might it perchance be the same + * IMEI changing command? + * + * This program constructs what should be a valid input to the decoding + * logic in the ati_sc.c source above, for the purpose of testing whether + * or not such a command would indeed effect an IMEI change on a GTA02 modem. + */ + +#include +#include +#include +#include +#include + +static char hexdigits[] = "0123456789abcdef"; + +main(argc, argv) + char **argv; +{ + char hexout[16]; + unsigned n1, n2, cksum; + int i, c; + + if (argc != 2) { +usage: fprintf(stderr, "usage: %s 15-IMEI-digits\n", argv[0]); + exit(1); + } + if (strlen(argv[1]) != 15) + goto usage; + n1 = n2 = 0; + for (i = 0; i < 15; i++) { + c = argv[1][i]; + if (!isdigit(c)) + goto usage; + c -= '0'; + hexout[i] = hexdigits[c ^ 5]; + if (i < 7) + n1 = n1 * 10 + c; + else + n2 = n2 * 10 + c; + } + hexout[15] = '\0'; + cksum = (n1 + n2) % 1973; + printf("AT@SC=\"%s%04u\"\n", hexout, cksum); + exit(0); +} diff -r 03f8a618689e -r 597143ba1c37 miscprog/factdiff.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/miscprog/factdiff.c Sun Apr 06 20:20:39 2014 +0000 @@ -0,0 +1,85 @@ +/* + * The 64 KiB "factory block" at the end of the 2nd flash chip select on + * Pirelli DP-L10 phones is believed to contain juicy info (IMEI and RF + * calibration data), but the format is yet to be cracked. + * + * This program compares Pirelli factory block images that have been read + * out of several phones, seeking to determine which bytes are always the + * same and which bytes change from specimen to specimen. + * + * Written by Spacefalcon the Outlaw. + */ + +#include +#include +#include +#include + +u_char specimen0[65536]; +char is_diff[65536]; + +read_specimen_file(filename, buf) + char *filename; + u_char *buf; +{ + int fd, cc; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + perror(filename); + exit(1); + } + cc = read(fd, buf, 65536); + close(fd); + if (cc != 65536) { + fprintf(stderr, "%s: unable to read 64 KiB\n", filename); + exit(1); + } +} + +process_comp_specimen(filename) + char *filename; +{ + u_char this_spec[65536]; + int i; + + read_specimen_file(filename, this_spec); + for (i = 0; i < 65536; i++) + if (this_spec[i] != specimen0[i]) + is_diff[i] = 1; +} + +output() +{ + int off, state, cstart, num; + + for (off = 0; off < 65536; ) { + state = is_diff[off]; + cstart = off; + while (off < 65536 && is_diff[off] == state) + off++; + printf("%04X-%04X: %s", cstart, off-1, + state ? "varying" : "constant"); + if (state) { + num = off - cstart; + printf(" (%d byte%s)", num, num != 1 ? "s" : ""); + } + putchar('\n'); + } +} + +main(argc, argv) + char **argv; +{ + char **ap; + + if (argc < 3) { + fprintf(stderr, "usage: %s specimen0 specimen1 ...\n", argv[0]); + exit(1); + } + read_specimen_file(argv[1], specimen0); + for (ap = argv + 2; *ap; ap++) + process_comp_specimen(*ap); + output(); + exit(0); +} diff -r 03f8a618689e -r 597143ba1c37 miscprog/imeibrute.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/miscprog/imeibrute.c Sun Apr 06 20:20:39 2014 +0000 @@ -0,0 +1,99 @@ +/* + * The IMEI "protection" implemented by TI for Calypso (as opposed to Calypso+ + * or LoCosto) platforms for those device manufs who desired to obfuscate their + * IMEIs (not everyone did - Openmoko opted out, for example), as seen in + * g23m/condat/com/src/comlib/cl_imei.c in the Leonardo semi-src by Sotovik, + * encrypts the IMEI using plain DES, using a key derived from the Calypso die + * ID. However, only 28 effective key bits are used, and the key is then also + * encrypted with itself and stored right after the encrypted IMEI, and is used + * by the decryption & verification routine. Per TI's source, the 16-byte + * encrypted IMEI record is to be stored in FFS in /gsm/imei.enc; the DP-L10 + * phone by Pirelli/Foxconn has been found to use the same scheme, but store + * the 16-byte record in question in their "factory block" instead, at absolute + * address 0x027F0504 as seen by the ARM7 CPU. + * + * The encryption scheme seems so weak to me (28 effective key bits and an easy + * hit detection criterion for a brute force cracker) that I decided to see, + * just for fun, how long it would take to crack that encryption by brute force + * alone, and using a totally non-optimized program to do that. + */ + +#include +#include +#include +#include + +DES_cblock ciphertext[2], dieid_key, decrypted[2]; +DES_key_schedule keysched; + +read_ciphertext(filename, offset_arg) + char *filename, *offset_arg; +{ + FILE *f; + u_long offset_val; + + f = fopen(filename, "r"); + if (!f) { + perror(filename); + exit(1); + } + if (offset_arg) { + offset_val = strtoul(offset_arg, 0, 16); + fseek(f, offset_val, 0); + } + fread(ciphertext, 8, 2, f); + fclose(f); +} + +print_des_cblock(msg, blk) + char *msg; + DES_cblock blk; +{ + printf("%s: %02X %02X %02X %02X %02X %02X %02X %02X\n", msg, + blk[0], blk[1], blk[2], blk[3], blk[4], blk[5], blk[6], blk[7]); +} + +try() +{ + DES_set_key_unchecked(&dieid_key, &keysched); + DES_ecb_encrypt(&ciphertext[1], &decrypted[1], &keysched, DES_DECRYPT); + if (decrypted[1][0] & 0xFE != dieid_key[0]) + return; + if (decrypted[1][1]) + return; + if (decrypted[1][2] & 0xFE != dieid_key[2]) + return; + if (decrypted[1][3]) + return; + if (decrypted[1][4] & 0xFE != dieid_key[4]) + return; + if (decrypted[1][5]) + return; + if (decrypted[1][6] & 0xFE != dieid_key[6]) + return; + if (decrypted[1][7]) + return; + print_des_cblock("Hit", &decrypted[1]); + DES_ecb_encrypt(&ciphertext[0], &decrypted[0], &keysched, DES_DECRYPT); + print_des_cblock("IMEI", &decrypted[0]); +} + +main(argc, argv) + char **argv; +{ + if (argc < 2 || argc > 3) { + fprintf(stderr, "usage: %s binfile [offset]\n", argv[0]); + exit(1); + } + read_ciphertext(argv[1], argv[2]); + dieid_key[1] = 0; + dieid_key[3] = 0; + dieid_key[5] = 0; + dieid_key[7] = 0; + for (dieid_key[0] = 0; dieid_key[0] <= 0xFE; dieid_key[0] += 2) + for (dieid_key[2] = 0; dieid_key[2] <= 0xFE; dieid_key[2] += 2) + for (dieid_key[4] = 0; dieid_key[4] <= 0xFE; dieid_key[4] += 2) + for (dieid_key[6] = 0; dieid_key[6] <= 0xFE; dieid_key[6] += 2) + try(); + exit(0); +} diff -r 03f8a618689e -r 597143ba1c37 miscprog/mokosrec2bin.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/miscprog/mokosrec2bin.c Sun Apr 06 20:20:39 2014 +0000 @@ -0,0 +1,226 @@ +/* + * The *.m0 format in which the Closedmoko firmware images have been + * distributed is a form of SREC, but further examination quickly + * reveals that the data bytes are swapped: the byte order is neither + * the natural little-endian ARM one of the Calypso, nor a word-wise + * ARM BE; instead the upper and lower bytes of each 16-bit shortword + * are swapped relative to the natural byte/word order of the Calypso + * ARM processor. + * + * Before this Closedmoko firmware can be examined with any of the + * standard reverse eng tools (ARM disassemblers or even the good old + * strings), it needs to be converted from the weird byte-swapped SREC + * format to straight binary in the natural byte order. The present + * utility accomplishes that conversion. + * + * Written by Spacefalcon the Outlaw. + */ + +#include +#include +#include +#include + +char *infname; +FILE *inf, *outf; +u_char fillbyte; +char srecbuf[80]; +u_char srecbin[40]; +int lineno, state; +u_long lastaddr; + +u_char header[6] = {0x06, 0x00, 0x00, 'H', 'D', 'R'}; + +decode_hex_byte(s) + char *s; +{ + register int u, l; + + if (!isxdigit(s[0]) || !isxdigit(s[1])) + return(-1); + if (isdigit(s[0])) + u = s[0] - '0'; + else if (isupper(s[0])) + u = s[0] - 'A' + 10; + else + u = s[0] - 'a' + 10; + if (isdigit(s[1])) + l = s[1] - '0'; + else if (isupper(s[1])) + l = s[1] - 'A' + 10; + else + l = s[1] - 'a' + 10; + return((u << 4) | l); +} + +srec2bin() +{ + register int i, l, b; + + l = decode_hex_byte(srecbuf + 2); + if (l < 1) { + fprintf(stderr, "%s line %d: S-record length octet is bad\n", + infname, lineno); + exit(1); + } + srecbin[0] = l; + if (l > 35) { + fprintf(stderr, + "%s line %d: S-record is longer than expected\n", + infname, lineno); + exit(1); + } + for (i = 1; i <= l; i++) { + b = decode_hex_byte(srecbuf + i*2 + 2); + if (b < 0) { + fprintf(stderr, "%s line %d: hex decode error\n", + infname, lineno); + exit(1); + } + srecbin[i] = b; + } + return(0); +} + +srec_cksum() +{ + u_char accum; + register int i, len; + + len = srecbin[0] + 1; + accum = 0; + for (i = 0; i < len; i++) + accum += srecbin[i]; + if (accum != 0xFF) { + fprintf(stderr, "%s line %d: bad checksum\n", infname, lineno); + exit(1); + } + return(0); +} + +main(argc, argv) + char **argv; +{ + register int i; + u_long curaddr; + int datalen; + + if (argc < 3 || argc > 4) { +usage: fprintf(stderr, "usage: %s input.m0 output.bin [fill-byte]\n", + argv[0]); + exit(1); + } + infname = argv[1]; + inf = fopen(infname, "r"); + if (!inf) { + perror(infname); + exit(1); + } + if (argc > 3) { + i = decode_hex_byte(argv[3]); + if (i >= 0) + fillbyte = i; + else + goto usage; + } else + fillbyte = 0; + + state = 0; + for (lineno = 1; ; lineno++) { + if (!fgets(srecbuf, sizeof srecbuf, inf)) { + fprintf(stderr, "%s: premature EOF\n", infname); + exit(1); + } + if (srecbuf[0] != 'S') { + fprintf(stderr, "%s line %d: not an S-record\n", + infname, lineno); + exit(1); + } + switch (srecbuf[1]) { + case '0': + if (state == 0) + break; + else + goto badtype; + case '3': + if (state == 0) + goto badtype; + else + break; + case '7': + if (state == 2) + break; + else + goto badtype; + default: + badtype: + fprintf(stderr, + "%s line %d: S-record type unexpected\n", + infname, lineno); + exit(1); + } + srec2bin(); + srec_cksum(); + if (state == 0) { + if (bcmp(srecbin, header, 6)) { + fprintf(stderr, "%s: expected header missing\n", + infname); + exit(1); + } + state = 1; + continue; + } + switch (srecbuf[1]) { + case '3': + if (srecbin[0] < 6) { + fprintf(stderr, + "%s line %d: S3 record is too short\n", + infname, lineno); + exit(1); + } + curaddr = (srecbin[1] << 24) | (srecbin[2] << 16) | + (srecbin[3] << 8) | srecbin[4]; + if (curaddr & 1) { + fprintf(stderr, "%s line %d: odd address\n", + infname, lineno); + exit(1); + } + datalen = srecbin[0] - 5; + if (datalen & 1) { + fprintf(stderr, "%s line %d: odd data length\n", + infname, lineno); + exit(1); + } + if (state < 2) { + outf = fopen(argv[2], "w"); + if (!outf) { + perror(argv[2]); + exit(1); + } + state = 2; + lastaddr = 0; + } + if (curaddr < lastaddr) { + fprintf(stderr, + "%s line %d: address going backwards\n", + infname, lineno); + exit(1); + } + while (lastaddr < curaddr) { + putc(fillbyte, outf); + lastaddr++; + } + for (i = 0; i < datalen; i += 2) { + putc(srecbin[i + 6], outf); + putc(srecbin[i + 5], outf); + } + lastaddr = curaddr + datalen; + continue; + case '7': + fclose(outf); + exit(0); + default: + abort(); + } + } +} diff -r 03f8a618689e -r 597143ba1c37 miscprog/pirimei.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/miscprog/pirimei.c Sun Apr 06 20:20:39 2014 +0000 @@ -0,0 +1,103 @@ +/* + * This program recovers the IMEI of a Pirelli DP-L10 phone from a dump of + * its factory block (last 64 KiB sector of the 2nd flash chip select) and + * the corresponding dieid file as written by fc-loadtool. + * + * The location of the 16-byte encrypted IMEI record within the factory block + * (at offset 0x504) has been figured out with the help of the factdiff.c + * program, and the magic decryption & verification algorithm has been found in + * g23m/condat/com/src/comlib/cl_imei.c in the Leonardo semi-src by Sotovik. + */ + +#include +#include +#include +#include +#include + +DES_cblock ciphertext[2], dieid_key, decrypted[2]; +DES_key_schedule keysched; + +read_ciphertext(filename) + char *filename; +{ + FILE *f; + + f = fopen(filename, "r"); + if (!f) { + perror(filename); + exit(1); + } + fseek(f, 0x504L, 0); + fread(ciphertext, 8, 2, f); + fclose(f); +} + +decode_hexdigit(ch) +{ + if (isdigit(ch)) + return(ch - '0'); + else if (isalpha(ch)) + return(ch - 'A' + 10); + else + return(ch - 'a' + 10); +} + +read_dieid_file(filename) + char *filename; +{ + FILE *f; + int i; + char lb[64]; + + f = fopen(filename, "r"); + if (!f) { + perror(filename); + exit(1); + } + for (i = 0; i < 4; i++) { + fgets(lb, sizeof lb, f); + if (!isxdigit(lb[0]) || !isxdigit(lb[1]) || !isxdigit(lb[2]) || + !isxdigit(lb[3]) || !isxdigit(lb[4]) || !isxdigit(lb[5]) || + !isxdigit(lb[6]) || !isxdigit(lb[7]) || + lb[8] != ':' || lb[9] != ' ' || + !isxdigit(lb[10]) || !isxdigit(lb[11]) || + !isxdigit(lb[12]) || !isxdigit(lb[13]) || lb[14] != '\n') { + fprintf(stderr, "%s, line %d: differs from expected\n", + filename, i + 1); + exit(1); + } + dieid_key[i*2] = (decode_hexdigit(lb[12]) << 4) | + decode_hexdigit(lb[13]); + dieid_key[i*2+1] = 0; + } + fclose(f); +} + +print_des_cblock(msg, blk) + char *msg; + DES_cblock blk; +{ + printf("%s: %02X %02X %02X %02X %02X %02X %02X %02X\n", msg, + blk[0], blk[1], blk[2], blk[3], blk[4], blk[5], blk[6], blk[7]); +} + +main(argc, argv) + char **argv; +{ + if (argc != 3) { + fprintf(stderr, "usage: %s fact.bin dieid\n", argv[0]); + exit(1); + } + read_ciphertext(argv[1]); + read_dieid_file(argv[2]); + print_des_cblock("Key derived from die ID", &dieid_key); + print_des_cblock("Ciphertext block 1", &ciphertext[0]); + print_des_cblock("Ciphertext block 2", &ciphertext[1]); + DES_set_key_unchecked(&dieid_key, &keysched); + DES_ecb_encrypt(&ciphertext[0], &decrypted[0], &keysched, DES_DECRYPT); + print_des_cblock("1st decrypted block", &decrypted[0]); + DES_ecb_encrypt(&ciphertext[1], &decrypted[1], &keysched, DES_DECRYPT); + print_des_cblock("2nd decrypted block", &decrypted[1]); + exit(0); +} diff -r 03f8a618689e -r 597143ba1c37 miscprog/rfcap-grep.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/miscprog/rfcap-grep.c Sun Apr 06 20:20:39 2014 +0000 @@ -0,0 +1,65 @@ +/* + * This utility performs a memmem() binary "grep", checking to see if a given + * binary file (mokoN firmware image) contains a particular binary "string" + * of 16 bytes: namely, the 16 bytes found in the "standard" /gsm/com/rfcap + * file on GTA0x modems. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +u_char needle[16] = {0x00, 0x1F, 0x41, 0x14, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x00, 0x00, 0xA5, 0x05, 0x00, 0xC0, 0x00}; +u_char *haystack; +size_t haystack_size; + +read_file(filename) + char *filename; +{ + int fd; + struct stat st; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + perror(filename); + exit(1); + } + fstat(fd, &st); + if (!S_ISREG(st.st_mode)) { + fprintf(stderr, "error: %s is not a regular file\n", filename); + exit(1); + } + haystack_size = st.st_size; + haystack = malloc(haystack_size); + if (!haystack) { + fprintf(stderr, "unable to malloc buffer for %s\n", filename); + exit(1); + } + read(fd, haystack, haystack_size); + close(fd); +} + +main(argc, argv) + char **argv; +{ + u_char *result; + + if (argc != 2) { + fprintf(stderr, "usage: %s mokoN.bin\n", argv[0]); + exit(1); + } + read_file(argv[1]); + result = memmem(haystack, haystack_size, needle, sizeof needle); + if (result) + printf("Found the rfcap bytes at offset 0x%x\n", + result - haystack); + else + printf("rfcap bytes not found in this image\n"); + exit(0); +} diff -r 03f8a618689e -r 597143ba1c37 mokosrec2bin.c --- a/mokosrec2bin.c Sat Apr 05 20:21:55 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,226 +0,0 @@ -/* - * The *.m0 format in which the Closedmoko firmware images have been - * distributed is a form of SREC, but further examination quickly - * reveals that the data bytes are swapped: the byte order is neither - * the natural little-endian ARM one of the Calypso, nor a word-wise - * ARM BE; instead the upper and lower bytes of each 16-bit shortword - * are swapped relative to the natural byte/word order of the Calypso - * ARM processor. - * - * Before this Closedmoko firmware can be examined with any of the - * standard reverse eng tools (ARM disassemblers or even the good old - * strings), it needs to be converted from the weird byte-swapped SREC - * format to straight binary in the natural byte order. The present - * utility accomplishes that conversion. - * - * Written by Spacefalcon the Outlaw. - */ - -#include -#include -#include -#include - -char *infname; -FILE *inf, *outf; -u_char fillbyte; -char srecbuf[80]; -u_char srecbin[40]; -int lineno, state; -u_long lastaddr; - -u_char header[6] = {0x06, 0x00, 0x00, 'H', 'D', 'R'}; - -decode_hex_byte(s) - char *s; -{ - register int u, l; - - if (!isxdigit(s[0]) || !isxdigit(s[1])) - return(-1); - if (isdigit(s[0])) - u = s[0] - '0'; - else if (isupper(s[0])) - u = s[0] - 'A' + 10; - else - u = s[0] - 'a' + 10; - if (isdigit(s[1])) - l = s[1] - '0'; - else if (isupper(s[1])) - l = s[1] - 'A' + 10; - else - l = s[1] - 'a' + 10; - return((u << 4) | l); -} - -srec2bin() -{ - register int i, l, b; - - l = decode_hex_byte(srecbuf + 2); - if (l < 1) { - fprintf(stderr, "%s line %d: S-record length octet is bad\n", - infname, lineno); - exit(1); - } - srecbin[0] = l; - if (l > 35) { - fprintf(stderr, - "%s line %d: S-record is longer than expected\n", - infname, lineno); - exit(1); - } - for (i = 1; i <= l; i++) { - b = decode_hex_byte(srecbuf + i*2 + 2); - if (b < 0) { - fprintf(stderr, "%s line %d: hex decode error\n", - infname, lineno); - exit(1); - } - srecbin[i] = b; - } - return(0); -} - -srec_cksum() -{ - u_char accum; - register int i, len; - - len = srecbin[0] + 1; - accum = 0; - for (i = 0; i < len; i++) - accum += srecbin[i]; - if (accum != 0xFF) { - fprintf(stderr, "%s line %d: bad checksum\n", infname, lineno); - exit(1); - } - return(0); -} - -main(argc, argv) - char **argv; -{ - register int i; - u_long curaddr; - int datalen; - - if (argc < 3 || argc > 4) { -usage: fprintf(stderr, "usage: %s input.m0 output.bin [fill-byte]\n", - argv[0]); - exit(1); - } - infname = argv[1]; - inf = fopen(infname, "r"); - if (!inf) { - perror(infname); - exit(1); - } - if (argc > 3) { - i = decode_hex_byte(argv[3]); - if (i >= 0) - fillbyte = i; - else - goto usage; - } else - fillbyte = 0; - - state = 0; - for (lineno = 1; ; lineno++) { - if (!fgets(srecbuf, sizeof srecbuf, inf)) { - fprintf(stderr, "%s: premature EOF\n", infname); - exit(1); - } - if (srecbuf[0] != 'S') { - fprintf(stderr, "%s line %d: not an S-record\n", - infname, lineno); - exit(1); - } - switch (srecbuf[1]) { - case '0': - if (state == 0) - break; - else - goto badtype; - case '3': - if (state == 0) - goto badtype; - else - break; - case '7': - if (state == 2) - break; - else - goto badtype; - default: - badtype: - fprintf(stderr, - "%s line %d: S-record type unexpected\n", - infname, lineno); - exit(1); - } - srec2bin(); - srec_cksum(); - if (state == 0) { - if (bcmp(srecbin, header, 6)) { - fprintf(stderr, "%s: expected header missing\n", - infname); - exit(1); - } - state = 1; - continue; - } - switch (srecbuf[1]) { - case '3': - if (srecbin[0] < 6) { - fprintf(stderr, - "%s line %d: S3 record is too short\n", - infname, lineno); - exit(1); - } - curaddr = (srecbin[1] << 24) | (srecbin[2] << 16) | - (srecbin[3] << 8) | srecbin[4]; - if (curaddr & 1) { - fprintf(stderr, "%s line %d: odd address\n", - infname, lineno); - exit(1); - } - datalen = srecbin[0] - 5; - if (datalen & 1) { - fprintf(stderr, "%s line %d: odd data length\n", - infname, lineno); - exit(1); - } - if (state < 2) { - outf = fopen(argv[2], "w"); - if (!outf) { - perror(argv[2]); - exit(1); - } - state = 2; - lastaddr = 0; - } - if (curaddr < lastaddr) { - fprintf(stderr, - "%s line %d: address going backwards\n", - infname, lineno); - exit(1); - } - while (lastaddr < curaddr) { - putc(fillbyte, outf); - lastaddr++; - } - for (i = 0; i < datalen; i += 2) { - putc(srecbin[i + 6], outf); - putc(srecbin[i + 5], outf); - } - lastaddr = curaddr + datalen; - continue; - case '7': - fclose(outf); - exit(0); - default: - abort(); - } - } -} diff -r 03f8a618689e -r 597143ba1c37 pirimei.c --- a/pirimei.c Sat Apr 05 20:21:55 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -/* - * This program recovers the IMEI of a Pirelli DP-L10 phone from a dump of - * its factory block (last 64 KiB sector of the 2nd flash chip select) and - * the corresponding dieid file as written by fc-loadtool. - * - * The location of the 16-byte encrypted IMEI record within the factory block - * (at offset 0x504) has been figured out with the help of the factdiff.c - * program, and the magic decryption & verification algorithm has been found in - * g23m/condat/com/src/comlib/cl_imei.c in the Leonardo semi-src by Sotovik. - */ - -#include -#include -#include -#include -#include - -DES_cblock ciphertext[2], dieid_key, decrypted[2]; -DES_key_schedule keysched; - -read_ciphertext(filename) - char *filename; -{ - FILE *f; - - f = fopen(filename, "r"); - if (!f) { - perror(filename); - exit(1); - } - fseek(f, 0x504L, 0); - fread(ciphertext, 8, 2, f); - fclose(f); -} - -decode_hexdigit(ch) -{ - if (isdigit(ch)) - return(ch - '0'); - else if (isalpha(ch)) - return(ch - 'A' + 10); - else - return(ch - 'a' + 10); -} - -read_dieid_file(filename) - char *filename; -{ - FILE *f; - int i; - char lb[64]; - - f = fopen(filename, "r"); - if (!f) { - perror(filename); - exit(1); - } - for (i = 0; i < 4; i++) { - fgets(lb, sizeof lb, f); - if (!isxdigit(lb[0]) || !isxdigit(lb[1]) || !isxdigit(lb[2]) || - !isxdigit(lb[3]) || !isxdigit(lb[4]) || !isxdigit(lb[5]) || - !isxdigit(lb[6]) || !isxdigit(lb[7]) || - lb[8] != ':' || lb[9] != ' ' || - !isxdigit(lb[10]) || !isxdigit(lb[11]) || - !isxdigit(lb[12]) || !isxdigit(lb[13]) || lb[14] != '\n') { - fprintf(stderr, "%s, line %d: differs from expected\n", - filename, i + 1); - exit(1); - } - dieid_key[i*2] = (decode_hexdigit(lb[12]) << 4) | - decode_hexdigit(lb[13]); - dieid_key[i*2+1] = 0; - } - fclose(f); -} - -print_des_cblock(msg, blk) - char *msg; - DES_cblock blk; -{ - printf("%s: %02X %02X %02X %02X %02X %02X %02X %02X\n", msg, - blk[0], blk[1], blk[2], blk[3], blk[4], blk[5], blk[6], blk[7]); -} - -main(argc, argv) - char **argv; -{ - if (argc != 3) { - fprintf(stderr, "usage: %s fact.bin dieid\n", argv[0]); - exit(1); - } - read_ciphertext(argv[1]); - read_dieid_file(argv[2]); - print_des_cblock("Key derived from die ID", &dieid_key); - print_des_cblock("Ciphertext block 1", &ciphertext[0]); - print_des_cblock("Ciphertext block 2", &ciphertext[1]); - DES_set_key_unchecked(&dieid_key, &keysched); - DES_ecb_encrypt(&ciphertext[0], &decrypted[0], &keysched, DES_DECRYPT); - print_des_cblock("1st decrypted block", &decrypted[0]); - DES_ecb_encrypt(&ciphertext[1], &decrypted[1], &keysched, DES_DECRYPT); - print_des_cblock("2nd decrypted block", &decrypted[1]); - exit(0); -} diff -r 03f8a618689e -r 597143ba1c37 rfcap-grep.c --- a/rfcap-grep.c Sat Apr 05 20:21:55 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * This utility performs a memmem() binary "grep", checking to see if a given - * binary file (mokoN firmware image) contains a particular binary "string" - * of 16 bytes: namely, the 16 bytes found in the "standard" /gsm/com/rfcap - * file on GTA0x modems. - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include - -u_char needle[16] = {0x00, 0x1F, 0x41, 0x14, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x00, 0x00, 0xA5, 0x05, 0x00, 0xC0, 0x00}; -u_char *haystack; -size_t haystack_size; - -read_file(filename) - char *filename; -{ - int fd; - struct stat st; - - fd = open(filename, O_RDONLY); - if (fd < 0) { - perror(filename); - exit(1); - } - fstat(fd, &st); - if (!S_ISREG(st.st_mode)) { - fprintf(stderr, "error: %s is not a regular file\n", filename); - exit(1); - } - haystack_size = st.st_size; - haystack = malloc(haystack_size); - if (!haystack) { - fprintf(stderr, "unable to malloc buffer for %s\n", filename); - exit(1); - } - read(fd, haystack, haystack_size); - close(fd); -} - -main(argc, argv) - char **argv; -{ - u_char *result; - - if (argc != 2) { - fprintf(stderr, "usage: %s mokoN.bin\n", argv[0]); - exit(1); - } - read_file(argv[1]); - result = memmem(haystack, haystack_size, needle, sizeof needle); - if (result) - printf("Found the rfcap bytes at offset 0x%x\n", - result - haystack); - else - printf("rfcap bytes not found in this image\n"); - exit(0); -}