fwupgrade.c

00001 
00013 #include "common.h"
00014 #include <sys/stat.h>
00015 #include <sys/types.h>
00016 #include <fcntl.h>
00017 #include <string.h>
00018 /* To handle .exe files, this must exist */
00019 #if HAVE_ZLIB_H
00020 #include <zlib.h>
00021 #endif
00022 /* You need this 10 MB buffer for this operation... */
00023 #define BUFFERSIZE 10*1024*1024
00024 
00025 static int progress (u_int64_t sent, u_int64_t total, const char* buf, unsigned len, void *data)
00026 {
00027   int percent = (sent*100)/total;
00028 #ifdef __WIN32__
00029   printf("Progress: %I64u of %I64u (%d%%)\r", sent, total, percent);
00030 #else
00031   printf("Progress: %llu of %llu (%d%%)\r", sent, total, percent);
00032 #endif
00033   fflush(stdout);
00034   return 0;
00035 }
00036 
00037 static void usage (void)
00038 {
00039   fprintf(stderr, "usage: fwupgrade [ -D<debuglvl> ] <path>\n");
00040   exit(1);
00041 }
00042 
00046 static int read_in_fw(char *path, unsigned char *buffer) {
00047   /* File descriptor and pointer */
00048   int fd;
00049   size_t bread;
00050 
00051   /* Read in the firmware file */
00052 #ifdef __WIN32__
00053   if ( (fd = open(path, O_RDONLY|O_BINARY)) == -1 ) {
00054 #else
00055   if ( (fd = open(path, O_RDONLY)) == -1 ) {
00056 #endif
00057     printf("Could not open firmware file descriptor.\n");
00058     return -1;
00059   }
00060   bread = read(fd, buffer, BUFFERSIZE);
00061   if (bread < 0) {
00062     printf("Error while reading firmware file.\n");
00063     close(fd);
00064     return -1;
00065   }
00066   
00067   if (bread == BUFFERSIZE) {
00068     printf("Warning: this firmware file is very large.\n");
00069     printf("It probably cannot be properly decoded.\n");
00070   }
00071   close(fd);
00072   printf("Read in a firmware file of size 0x%x.\n", bread);
00073   if (bread < 1024) {
00074     printf("Ridiculously small firmware file. Aborting.\n");
00075     return -1;
00076   }
00077   return bread;
00078 }
00079 
00083 static void ucs2_printf(unsigned char *str) {
00084   while (!str[0] == 0x00 || !str[1] == 0x00) {
00085     printf("%c", str[1]);
00086     str += 2;
00087   }
00088 }
00089 
00094 static void analyze_firmware(unsigned char *buffer) {
00095   if (buffer[0] == 'C' && buffer[1] == 'I' &&
00096       buffer[2] == 'F' && buffer[3] == 'F') {
00097     u_int32_t cifflen;
00098     u_int32_t offset = 0;
00099 
00100     cifflen = (buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
00101     printf("Firmware CIFF image, %08x bytes:\n", cifflen);
00102     
00103     /* Wind past header */
00104     offset = 8;
00105 
00106     printf("   Offset:   Type:  Size:\n");
00107     while (offset < cifflen) {
00108       char secname[5];
00109       u_int32_t seclen;
00110 
00111       secname[0] = buffer[offset];
00112       secname[1] = buffer[offset+1];
00113       secname[2] = buffer[offset+2];
00114       secname[3] = buffer[offset+3];
00115       secname[4] = '\0';
00116 
00117       seclen = (buffer[offset+4] << 24) | (buffer[offset+5] << 16) | 
00118         (buffer[offset+6] << 8) | buffer[offset+7];
00119       
00120       printf("   %08x  %s   %08x bytes", offset, secname, seclen);
00121       
00122       if (!strcmp(secname, "CINF") || !strcmp(secname, "DATA")) {
00123         printf(" \"");
00124         ucs2_printf(&buffer[offset+8]);
00125         printf("\"");
00126       }
00127       printf("\n");
00128 
00129       offset += 8;
00130       offset += seclen;
00131     }
00132   } else {
00133     printf("Unknown firmware image type.\n");
00134   }
00135 }
00136 
00137 #if HAVE_ZLIB_H
00138 static void dexor_fw_image(unsigned char *buffer, 
00139                            size_t zimglen, 
00140                            unsigned char *key, 
00141                            u_int8_t keylen) {
00142   register u_int8_t j = 0;
00143   register u_int32_t i;
00144   register unsigned char c;
00145 
00146   printf("Dexor with key: ");
00147   for (i = 0; i < keylen; i++) {
00148     printf("%02x ", key[i]);
00149   }
00150   printf("\n");
00151   for (i = 0; i < zimglen; i++) {
00152     c = key[j] | 0x80;
00153     buffer[i] = buffer[i] ^ c;
00154     j = (i+1) % keylen;
00155   }
00156 }
00157 
00161 static void decompress_fw_image(unsigned char *compressed, size_t compressed_len, 
00162                          unsigned char **decompressed, size_t *rawlen) {
00163   /* Allocate another big buffer */
00164   *decompressed = (unsigned char *) malloc(BUFFERSIZE);
00165   if (*decompressed == NULL) {
00166     *rawlen = 0;
00167     return;
00168   }
00169   *rawlen = BUFFERSIZE;
00170   if (uncompress(*decompressed, (uLongf*) rawlen, compressed, compressed_len) != Z_OK) {
00171     *rawlen = 0;
00172     return;
00173   }
00174 }
00175 
00179 static int write_fw_file(char *path, 
00180                   unsigned char *decompressed,
00181                   size_t rawlen) {
00182   int fd = -1;
00183 
00184 #ifdef __WIN32__
00185    if ( (fd = open(path, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0664)) == -1 ) {
00186 #else
00187    if ( (fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0664)) == -1 ) {
00188 #endif
00189      printf("Could not open uncompressed file.\n");
00190      return -1;
00191    }
00192    if (write(fd, decompressed, rawlen) == -1) {
00193      printf("Error while writing uncompressed file.\n");
00194      close(fd);
00195      unlink(path);
00196      return -1;
00197    }
00198    close(fd);
00199    return 0;
00200 }
00201 #endif
00202 
00206 static int prompt()
00207 {
00208   char buff[2];
00209   
00210   while (1) {
00211     fprintf(stdout, "> ");
00212     if ( fgets(buff, sizeof(buff), stdin) == NULL ) {
00213       if (ferror(stdin)) {
00214         fprintf(stderr, "File error on stdin\n");
00215       } else {
00216         fprintf(stderr, "EOF on stdin\n");
00217       }
00218       return 1;
00219     }
00220     if (buff[0] == 'y') {
00221       return 0;
00222     } else if (buff[0] == 'n') {
00223       return 1;
00224     }
00225   }
00226 }
00227 
00228 int main(int argc, char **argv)
00229 {
00230   njb_t njbs[NJB_MAX_DEVICES], *njb;
00231   int n, opt, debug;
00232   extern int optind;
00233   extern char *optarg;
00234   char *path;
00235   char *sendpath;
00236   char *lang;
00237   unsigned char *buffer;
00238   size_t bread;
00239   
00240   debug = 0;
00241   while ( (opt = getopt(argc, argv, "D:")) != -1 ) {
00242     switch (opt) {
00243     case 'D':
00244       debug = atoi(optarg);
00245       break;
00246     default:
00247       usage();
00248       break;
00249     }
00250   }
00251   argc -= optind;
00252   argv += optind;
00253   
00254   if ( argc != 1 ) usage();
00255   
00256   if ( debug ) NJB_Set_Debug(debug);
00257   
00258   /*
00259    * Check environment variables $LANG and $LC_CTYPE
00260    * to see if we want to support UTF-8 unicode
00261    * $LANG = "xx_XX.UTF-8" or $LC_CTYPE = "?"
00262    * trigger unicode support.
00263    */
00264   lang = getenv("LANG");
00265   if (lang != NULL) {
00266     if (strlen(lang) > 5) {
00267       if (!strcmp(&lang[strlen(lang)-5], "UTF-8")) {
00268         NJB_Set_Unicode(NJB_UC_UTF8);
00269       }
00270     }
00271   }
00272   
00273   path = argv[0];
00274   
00275   printf("Analyzing firmware file %s...\n", path);
00276 
00277   /* Allocate a buffer */
00278   buffer = (unsigned char *) malloc(BUFFERSIZE);
00279   if (buffer == NULL) {
00280     printf("Could not allocate a firmware scanning buffer.\n");
00281     return 1;
00282   }
00283 
00284   /* Read in to buffer */
00285   bread = read_in_fw(path, buffer);
00286   if (bread == -1) {
00287     return 1;
00288   }
00289 
00290   /*
00291    * See if this is a RAW (dexored) firmware image, all
00292    * firmware images starts with the string "CIFF"
00293    */
00294   if (buffer[0] == 'C' && buffer[1] == 'I' && 
00295       buffer[2] == 'F' && buffer[3] == 'F') {
00296     printf("This seems to be a raw (dexored) firmware image.\n");
00297     sendpath = path;
00298   } else {
00299 #if HAVE_ZLIB_H
00300     char known_key[] = "SamBanDam";
00301     char uncompressed_file[] = "tempimage.bin";
00302     /* Length of the zlib compressed image */
00303     unsigned int zimglen;
00304     /* Pointer into file buffer */
00305     unsigned int offset = 0;
00306     unsigned char *decompressed;
00307     size_t rawlen;
00308     size_t i;
00309 
00310     printf("This could be a zlib compressed windows executable.\n");
00311 
00312     /* Scanning for zlib header */
00313     printf("Scanning for zlib header...\n");
00314     for (i = 0; i < bread-3; i++) {
00315       if (
00316           // Old Key
00317           (buffer[i] == 0xAB && buffer[i+1] == 0x3B && buffer[i+2] == 0x01) ||
00318           // New Key
00319           (buffer[i] == 0xCA && buffer[i+1] == 0x69 && buffer[i+2] == 0x0F)
00320           )
00321         {
00322           offset = i-4;
00323           break;
00324         }
00325     }
00326     if (offset == 0) {
00327       printf("Could not locate a zlib header in this firmware file.\n");
00328       return 1;
00329     } else {
00330       printf("Found zlib header at file position 0x%x.\n", offset);
00331     }
00332     
00333     zimglen = buffer[offset+3] << 24 | buffer[offset+2] << 16 
00334       | buffer[offset+1] << 8 | buffer[offset];
00335     printf("Zlib compressed image length: 0x%x\n", zimglen);
00336     if (zimglen > bread-offset) {
00337       printf("Inconsistent length of zlib compressed image, aborting.\n");
00338       return 1;
00339     }
00340     
00341     /* Decompress zlib image using Zlib */
00342     printf("Calling zlib uncompress() on raw chunks...\n");
00343     decompress_fw_image(&buffer[offset+4], zimglen, &decompressed, &rawlen);
00344     if (rawlen == 0) {
00345       printf("Failed.\n");
00346 
00347       /* "Dexor" the firmware image */
00348       printf("\"Dexoring\" firmware zlib image with a known key...\n");
00349       dexor_fw_image(&buffer[offset+4], zimglen, known_key, strlen(known_key));
00350 
00351       /* Decompress zlib image using Zlib */
00352       printf("Calling zlib uncompress()...\n");
00353       decompress_fw_image(&buffer[offset+4], zimglen, &decompressed, &rawlen);
00354       if (rawlen == 0) {
00355         printf("Could not dexor the firmware :(\nAborting.\n");
00356         exit(1);
00357       }
00358     }
00359     printf("Decompressed image size: 0x%x\n", rawlen);
00360     if (decompressed[0] == 'C' && decompressed[1] == 'I' &&
00361         decompressed[2] == 'F' && decompressed[3] == 'F') {
00362       printf("The extracted image looks like a firmware file.\n");
00363     } else {
00364       printf("The extracted image does not look like a firmware file.\n");
00365       printf("Aborting.\n");
00366       return 1;
00367     }
00368 
00369     /* Write out decompressed file */
00370     printf("Writing out the extracted image to disk as \"%s\".\n", uncompressed_file);
00371     if (write_fw_file(uncompressed_file, decompressed, rawlen) == -1) {
00372       printf("Failed to write uncompressed file. Aborting.\n");
00373       return 1;
00374     }
00375     
00376     sendpath = uncompressed_file;
00377 
00378     /* Exchange buffer for the decompressed image */
00379     free(buffer);
00380     buffer = decompressed;
00381 
00382 #else
00383     printf("This may be an zlib compressed .exe file firmware.\n");
00384     printf("You must compile the \"fwupgrade\" program on a system\n");
00385     printf("which has the zlib library and headers properly installed\n");
00386     printf("to enable the compression of zlib compressed firmware images.\n");
00387 #endif    
00388   }
00389   
00390   /* Make some more information available on this firmware */
00391   analyze_firmware(buffer);
00392 
00393   /* Free firmware read buffer */
00394   free(buffer);
00395     
00396   printf("Sending firmware file to jukebox\n");
00397   if (NJB_Discover(njbs, 0, &n) == -1) {
00398     fprintf(stderr, "could not locate any jukeboxes\n");
00399     return 1;
00400   }
00401   
00402   if ( n == 0 ) {
00403     fprintf(stderr, "no NJB devices found\n");
00404     return 0;
00405   } 
00406   
00407   njb = njbs;
00408   
00409   if ( NJB_Open(njb) == -1 ) {
00410     NJB_Error_Dump(njb,stderr);
00411     return 1;
00412   }
00413   
00414   NJB_Capture(njb);
00415 
00416   printf("I will now send the firmware to your device.\n");
00417   printf("Continue? (y/n)\n");
00418   if (prompt() == 0) {
00419     if ( NJB_Send_Firmware(njb, sendpath, progress, NULL) == -1 ) {
00420       NJB_Error_Dump(njb,stderr);
00421     } else {
00422       printf("\nFirmware upload complete.");
00423     }
00424     printf("\n");
00425   } else {
00426     printf("Aborted.\n");
00427   }
00428   
00429   NJB_Release(njb);
00430   
00431   NJB_Close(njb);
00432   
00433   return 0;
00434 }

Generated on Mon Sep 11 00:52:12 2006 for libnjb by  doxygen 1.4.7