00001
00013 #include "common.h"
00014 #include <sys/stat.h>
00015 #include <sys/types.h>
00016 #include <fcntl.h>
00017 #include <string.h>
00018
00019 #if HAVE_ZLIB_H
00020 #include <zlib.h>
00021 #endif
00022
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
00048 int fd;
00049 size_t bread;
00050
00051
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
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
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
00260
00261
00262
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
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
00285 bread = read_in_fw(path, buffer);
00286 if (bread == -1) {
00287 return 1;
00288 }
00289
00290
00291
00292
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
00303 unsigned int zimglen;
00304
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
00313 printf("Scanning for zlib header...\n");
00314 for (i = 0; i < bread-3; i++) {
00315 if (
00316
00317 (buffer[i] == 0xAB && buffer[i+1] == 0x3B && buffer[i+2] == 0x01) ||
00318
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
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
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
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
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
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
00391 analyze_firmware(buffer);
00392
00393
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 }