├── readme.txt ├── dec_sdata.c ├── pixma_decrypt.c └── pixma_unpack.c /readme.txt: -------------------------------------------------------------------------------- 1 | What is this? 2 | ------------- 3 | Some little tools to unpack firmware of Canon PIXMA series for analysis. 4 | 5 | Motivation 6 | ---------- 7 | Some Pixma printer is unable to reset the Waste Ink counter and refuses to print now, 8 | even though waste ink container has been swapped out. 9 | So I was curious about the inner workings of the firmware to find a clue on how to 10 | reset the counter. 11 | But I soon gave up on it. Nevertheless, it has been interesting and maybe this is 12 | useful for other researchers? Basically, I just implemented what has been described at 13 | https://www.contextis.com/en/blog/hacking-canon-pixma-printers-doomed-encryption 14 | 15 | How to use? 16 | ----------- 17 | 1) Download firmware 18 | Check the USB device ID of the Pixma printer, i.e. 04a9:1769 19 | Then downlod the firmware by placing the device ID instead of 1769 in the following command: 20 | 21 | wget `wget -O - -o /dev/null http://gdlp01.c-wss.com/rmds/ij/ijd/ijdupdate/1769.xml | sed -n 's:.*\(.*\).*:\1:p'` 22 | 23 | 2) Now decrypt firmware, and decode SREC file to binary 24 | You need srec_cat from srecord tools for this, i.e. srecord-1.64: http://srecord.sourceforge.net/ 25 | 26 | ./pixma_decrypt 1769V1100AN.bin decoded.asc 27 | grep -v -e '^SF' decoded.asc | srec_cat -o decoded.bin -binary 28 | 29 | 3) Now you can try to unpack the payload: 30 | ./pixma_unpack decoded.bin firmware.bin 31 | 32 | 33 | Decrypt sdata.bin 34 | ----------------- 35 | If you want to decrypt certificate data (for whatever reason you want to do this... 36 | It's just a certificate list for trusted CAs, so no idea why this even has been "crypted"): 37 | 38 | wget http://dtv-p.c-ij.com/sdata/struct01/sdata.bin 39 | ./dec_sdata sdata.bin sdata.dec 40 | 41 | -------------------------------------------------------------------------------- /dec_sdata.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "dec_sdata.h" 4 | 5 | #define TBL_SZ 0x10000 6 | 7 | /* Decrypts the public certificate list at http://dtv-p.c-ij.com/sdata/struct01/sdata.bin 8 | * (versioned by http://dtv-p.c-ij.com/sdata/struct01/version.bin ) 9 | */ 10 | 11 | void decode_sdata(unsigned char *in) 12 | { 13 | int j, k; 14 | 15 | for (j=0, k=0; j \n", argv[0]); 31 | return 1; 32 | } 33 | 34 | int main(int argc, char **argv) 35 | { 36 | FILE *fp, *fpout; 37 | int i=1, offset=0; 38 | unsigned char *buf; 39 | 40 | printf ("Canon PIXMA sdata decrypter V1.00\nleecher@dose.0wnz.at 10/2019\n\n"); 41 | if (argc<3) return usage(argv); 42 | 43 | if (!strcmp(argv[1], "-o")) 44 | { 45 | if (argc<5) return usage(argv); 46 | if (!sscanf(argv[++i], "%x", &offset)) 47 | { 48 | fprintf(stderr, "Cannot parse offset %s as hex\n", argv[i]); 49 | return 1; 50 | } 51 | i++; 52 | } 53 | if (!(fp=fopen(argv[i], "rb"))) 54 | { 55 | perror("Cannot open input file"); 56 | return 1; 57 | } 58 | if (!(fpout=fopen(argv[++i], "wb"))) 59 | { 60 | fclose(fp); 61 | perror("Cannot open output file"); 62 | return 1; 63 | } 64 | if (buf=malloc(TBL_SZ)) 65 | { 66 | if (offset) fseek(fp, offset, SEEK_SET); 67 | fread(buf, TBL_SZ, 1, fp); 68 | fclose(fp); 69 | decode_sdata(buf); 70 | fwrite(buf, TBL_SZ, 1, fpout); 71 | fclose(fpout); 72 | free(buf); 73 | } else { 74 | perror("malloc"); 75 | return 1; 76 | } 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /pixma_decrypt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* Quick and dirty, known plaintext... */ 5 | void get_key_simple(unsigned char *in, unsigned char *key) 6 | { 7 | char assume_1[6]={'S','F','0','9','0','0'}; 8 | char assume_2[10] = {0x0D,0x0A,'S','F','0','5','0','0','0','0'}; 9 | int i, j; 10 | 11 | for (i=0; i \n", argv[0]); 49 | return 1; 50 | } 51 | 52 | int main(int argc, char **argv) 53 | { 54 | FILE *fp, *fpout; 55 | unsigned char buf[32], key[16]={0}; 56 | 57 | printf ("Canon PIXMA Firmware decrypter V1.00\nleecher@dose.0wnz.at 10/2019\n\n"); 58 | if (argc<3) return usage(argv); 59 | 60 | if (!(fp=fopen(argv[1], "rb"))) 61 | { 62 | perror("Cannot open input file"); 63 | return 1; 64 | } 65 | if (!(fpout=fopen(argv[2], "wb"))) 66 | { 67 | fclose(fp); 68 | perror("Cannot open output file"); 69 | return 1; 70 | } 71 | 72 | fread(buf, 32, 1, fp); 73 | get_key_simple(buf, key); 74 | print_key(key); 75 | decrypt(fp, fpout, key); 76 | 77 | fclose(fpout); 78 | fclose(fp); 79 | return 0; 80 | } 81 | -------------------------------------------------------------------------------- /pixma_unpack.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static unsigned char sig[] = 5 | { 6 | 0x70, 0xB5, 0x05, 0x4C, 0x05, 0x48, 0x06, 0x49, 7 | 0x45, 0x1A, 0x0E, 0x46, 0x2A, 0x46, 0x31, 0x46, 8 | 0x20, 0x46, 0xFF 9 | }; 10 | 11 | 12 | // Some sort of compression, was unable to identify the algorithm, LZ4 or something..? 13 | void decompress(unsigned char *src, unsigned char *dest, unsigned int size) 14 | { 15 | unsigned int i, l, x; 16 | unsigned char c, d, e, f, *pdst; 17 | 18 | for (x=0; x> 4; 24 | if (!d) d = *src++; 25 | for (i = l - 1; i; i--) *dest++ = *src++; 26 | if (d) 27 | { 28 | e = *src++; 29 | f = c << 4 >> 6; 30 | if (f == 3) f = *src++; 31 | pdst = dest-e-256*f; 32 | for (l=d+1; l>=0; l--) *dest++ = *pdst++; 33 | } 34 | } 35 | } 36 | 37 | // Same as above, but with file pointer so that file doesn't need to be mapped to memory 38 | void decompress_fp(FILE *fpIn, FILE *fpOut, unsigned int size) 39 | { 40 | int c, e, l, d; 41 | unsigned int f; 42 | unsigned char buf[260]; 43 | 44 | while((c = fgetc(fpIn))!=EOF && ftell(fpOut)> 4; 49 | if (!d) d = fgetc(fpIn); 50 | fread(buf, l-1, 1, fpIn); 51 | fwrite(buf, l-1, 1, fpOut); 52 | if (d) 53 | { 54 | e = fgetc(fpIn); 55 | f = (unsigned int)(c << 28) >> 30; 56 | if (f == 3) f = (unsigned char)fgetc(fpIn); 57 | fseek(fpOut, 0-e-256*f, SEEK_CUR); 58 | fread(buf, d+2, 1, fpOut); 59 | fseek(fpOut, 0, SEEK_END); 60 | fwrite(buf, d+2, 1, fpOut); 61 | } 62 | } 63 | } 64 | 65 | int usage(char **argv) 66 | { 67 | printf ("%s \n", argv[0]); 68 | return 1; 69 | } 70 | 71 | int search_data(FILE *fp, unsigned char *needle, int len) 72 | { 73 | unsigned char buf[4096], *p; 74 | int r; 75 | 76 | for (r=sizeof(buf); r==sizeof(buf) && (r=fread(buf, 1, sizeof(buf), fp));) 77 | { 78 | // memmem is so broken that we have to do this manually... 79 | if ((p=(unsigned char*)memchr(buf, *needle, r)) && p-buf+len<=r && memcmp(p, needle, len)==0) 80 | { 81 | fseek(fp, (r*-1)+(p-buf)+len+5, SEEK_CUR); 82 | return 1; 83 | } 84 | fseek(fp, -len+1, SEEK_CUR); 85 | } 86 | return 0; 87 | } 88 | 89 | int main(int argc, char **argv) 90 | { 91 | FILE *fp, *fpout; 92 | long offset=0, size=0; 93 | int ret=1; 94 | 95 | printf ("Canon PIXMA Firmware unpacker V1.00\nleecher@dose.0wnz.at 10/2019\n\n"); 96 | if (argc<3) return usage(argv); 97 | 98 | if (!(fp=fopen(argv[1], "rb"))) 99 | { 100 | perror("Cannot open input file"); 101 | return 1; 102 | } 103 | if (!(fpout=fopen(argv[2], "w+b"))) 104 | { 105 | fclose(fp); 106 | perror("Cannot open output file"); 107 | return 1; 108 | } 109 | 110 | if (!offset || !size) 111 | { 112 | unsigned int end, start; 113 | 114 | if (!search_data(fp, sig, sizeof(sig))) 115 | { 116 | fprintf(stderr, "Signature for decompression function not found.\n"); 117 | goto done; 118 | } 119 | fread(&offset, 4, 1, fp); 120 | fread(&end, 4, 1, fp); 121 | fread(&start, 4, 1, fp); 122 | size=end-start; 123 | printf ("Data offset: %08lX\nStart address %08X\nEnd address %08X\nSize: %ld bytes\n\n", offset, start, end, size); 124 | offset &= 0xFFFFFF; 125 | } 126 | 127 | fseek(fp, offset, SEEK_SET); 128 | printf ("Decompressing..."); 129 | fflush(stdout); 130 | decompress_fp(fp, fpout, size); 131 | printf ("Done.\n"); 132 | ret = 0; 133 | 134 | done: 135 | fclose(fpout); 136 | fclose(fp); 137 | return ret; 138 | } 139 | --------------------------------------------------------------------------------