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
00080 #if HAVE_ZLIB_H
00081 static void dexor_fw_image(unsigned char *buffer, size_t zimglen) {
00082 register int t = 0;
00083 register int i;
00084 register unsigned char c;
00085 char key[] = "SamBanDam";
00086
00087 printf("\"Dexoring\" firmware zlib image...\n");
00088 for (i = 0; i < zimglen; i++) {
00089 c = key[t] | 0x80;
00090 buffer[i] = buffer[i] ^ c;
00091 t = (i+1) % 9;
00092 }
00093 }
00094
00098 static void decompress_fw_image(unsigned char *compressed, size_t compressed_len,
00099 unsigned char **decompressed, size_t *rawlen) {
00100
00101 *decompressed = (unsigned char *) malloc(BUFFERSIZE);
00102 if (*decompressed == NULL) {
00103 *rawlen = 0;
00104 return;
00105 }
00106 printf("Calling zlib uncompress()...\n");
00107 *rawlen = BUFFERSIZE;
00108 if (uncompress(*decompressed, (uLongf*) rawlen, compressed, compressed_len) != Z_OK) {
00109 printf("There was an uncompress error.\n");
00110 *rawlen = 0;
00111 return;
00112 }
00113 }
00114
00118 static int write_fw_file(char *path,
00119 unsigned char *decompressed,
00120 size_t rawlen) {
00121 int fd = -1;
00122
00123 #ifdef __WIN32__
00124 if ( (fd = open(path, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0664)) == -1 ) {
00125 #else
00126 if ( (fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0664)) == -1 ) {
00127 #endif
00128 printf("Could not open uncompressed file.\n");
00129 return -1;
00130 }
00131 if (write(fd, decompressed, rawlen) == -1) {
00132 printf("Error while writing uncompressed file.\n");
00133 close(fd);
00134 unlink(path);
00135 return -1;
00136 }
00137 close(fd);
00138 return 0;
00139 }
00140 #endif
00141
00145 static int prompt()
00146 {
00147 char buff[2];
00148
00149 while (1) {
00150 fprintf(stdout, "> ");
00151 if ( fgets(buff, sizeof(buff), stdin) == NULL ) {
00152 if (ferror(stdin)) {
00153 fprintf(stderr, "File error on stdin\n");
00154 } else {
00155 fprintf(stderr, "EOF on stdin\n");
00156 }
00157 return 1;
00158 }
00159 if (buff[0] == 'y') {
00160 return 0;
00161 } else if (buff[0] == 'n') {
00162 return 1;
00163 }
00164 }
00165 }
00166
00167 int main(int argc, char **argv)
00168 {
00169 njb_t njbs[NJB_MAX_DEVICES], *njb;
00170 int n, opt, debug;
00171 extern int optind;
00172 extern char *optarg;
00173 char *path;
00174 char *sendpath;
00175 char *lang;
00176 unsigned char *buffer;
00177 size_t bread;
00178
00179 debug = 0;
00180 while ( (opt = getopt(argc, argv, "D:")) != -1 ) {
00181 switch (opt) {
00182 case 'D':
00183 debug = atoi(optarg);
00184 break;
00185 default:
00186 usage();
00187 break;
00188 }
00189 }
00190 argc -= optind;
00191 argv += optind;
00192
00193 if ( argc != 1 ) usage();
00194
00195 if ( debug ) NJB_Set_Debug(debug);
00196
00197
00198
00199
00200
00201
00202
00203 lang = getenv("LANG");
00204 if (lang != NULL) {
00205 if (strlen(lang) > 5) {
00206 if (!strcmp(&lang[strlen(lang)-5], "UTF-8")) {
00207 NJB_Set_Unicode(NJB_UC_UTF8);
00208 }
00209 }
00210 }
00211
00212 path = argv[0];
00213
00214 printf("Analyzing firmware file %s...\n", path);
00215
00216
00217 buffer = (unsigned char *) malloc(BUFFERSIZE);
00218 if (buffer == NULL) {
00219 printf("Could not allocate a firmware scanning buffer.\n");
00220 return 1;
00221 }
00222
00223
00224 bread = read_in_fw(path, buffer);
00225 if (bread == -1) {
00226 return 1;
00227 }
00228
00229
00230
00231
00232
00233 if (buffer[0] == 'C' && buffer[1] == 'I' &&
00234 buffer[2] == 'F' && buffer[3] == 'F') {
00235 printf("This seems to be a raw (dexored) firmware image.\n");
00236 sendpath = path;
00237 } else {
00238 #if HAVE_ZLIB_H
00239 char uncompressed_file[] = "tempimage.bin";
00240
00241 unsigned int zimglen;
00242
00243 unsigned int offset = 0;
00244 unsigned char *decompressed;
00245 size_t rawlen;
00246 int i;
00247
00248 printf("This seems to be a zlib compressed windows executable.\n");
00249
00250 printf("Scanning for zlib header...\n");
00251 for (i = 0; i < bread; i++) {
00252 if (buffer[i] == 0xAB && buffer[i+1] == 0x3B && buffer[i+2] == 0x01) {
00253 offset = i-4;
00254 }
00255 }
00256 if (offset == 0) {
00257 printf("Could not locate a zlib header in this firmware file.\n");
00258 return 1;
00259 } else {
00260 printf("Found zlib header at file position 0x%x.\n", offset);
00261 }
00262
00263 zimglen = buffer[offset+3] << 24 | buffer[offset+2] << 16
00264 | buffer[offset+1] << 8 | buffer[offset];
00265 printf("Zlib compressed image length: 0x%x\n", zimglen);
00266 if (zimglen > bread-offset) {
00267 printf("Inconsistent length of zlib compressed image, aborting.\n");
00268 return 1;
00269 }
00270
00271
00272 dexor_fw_image(&buffer[offset+4], zimglen);
00273
00274
00275 decompress_fw_image(&buffer[offset+4], zimglen, &decompressed, &rawlen);
00276 if (rawlen == 0) {
00277 printf("Decompression failed. Aborting.\n");
00278 return 1;
00279 }
00280 printf("Decompressed image size: 0x%x\n", rawlen);
00281 if (decompressed[0] == 'C' && decompressed[1] == 'I' &&
00282 decompressed[2] == 'F' && decompressed[3] == 'F') {
00283 printf("The extracted image looks like a firmware file.\n");
00284 } else {
00285 printf("The extracted image does not look like a firmware file.\n");
00286 printf("Aborting.\n");
00287 return 1;
00288 }
00289
00290
00291 printf("Writing out the extracted image to disk as \"%s\".\n", uncompressed_file);
00292 if (write_fw_file(uncompressed_file, decompressed, rawlen) == -1) {
00293 printf("Failed to write uncompressed file. Aborting.\n");
00294 return 1;
00295 }
00296
00297 sendpath = uncompressed_file;
00298
00299 free(decompressed);
00300
00301 #else
00302 printf("This may be an zlib compressed .exe file firmware.\n");
00303 printf("You must compile the \"fwupgrade\" program on a system\n");
00304 printf("which has the zlib library and headers properly installed\n");
00305 printf("to enable the compression of zlib compressed firmware images.\n");
00306 #endif
00307 }
00308 free(buffer);
00309
00310 printf("Sending firmware file to jukebox\n");
00311 if (NJB_Discover(njbs, 0, &n) == -1) {
00312 fprintf(stderr, "could not locate any jukeboxes\n");
00313 return 1;
00314 }
00315
00316 if ( n == 0 ) {
00317 fprintf(stderr, "no NJB devices found\n");
00318 return 0;
00319 }
00320
00321 njb = njbs;
00322
00323 if ( NJB_Open(njb) == -1 ) {
00324 NJB_Error_Dump(njb,stderr);
00325 return 1;
00326 }
00327
00328 NJB_Capture(njb);
00329
00330 printf("I will now send the firmware to your device.\n");
00331 printf("Continue? (y/n)\n");
00332 if (prompt() == 0) {
00333 if ( NJB_Send_Firmware(njb, sendpath, progress, NULL) == -1 ) {
00334 NJB_Error_Dump(njb,stderr);
00335 } else {
00336 printf("\nFirmware upload complete.");
00337 }
00338 printf("\n");
00339 } else {
00340 printf("Aborted.\n");
00341 }
00342
00343 NJB_Release(njb);
00344
00345 NJB_Close(njb);
00346
00347 return 0;
00348 }