#include "common.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#if HAVE_ZLIB_H
#include <zlib.h>
#endif
#define BUFFERSIZE 10*1024*1024
static int progress (u_int64_t sent, u_int64_t total, const char* buf, unsigned len, void *data)
{
int percent = (sent*100)/total;
#ifdef __WIN32__
printf("Progress: %I64u of %I64u (%d%%)\r", sent, total, percent);
#else
printf("Progress: %llu of %llu (%d%%)\r", sent, total, percent);
#endif
fflush(stdout);
return 0;
}
static void usage (void)
{
fprintf(stderr, "usage: fwupgrade [ -D<debuglvl> ] <path>\n");
exit(1);
}
static int read_in_fw(char *path, unsigned char *buffer) {
int fd;
size_t bread;
#ifdef __WIN32__
if ( (fd = open(path, O_RDONLY|O_BINARY)) == -1 ) {
#else
if ( (fd = open(path, O_RDONLY)) == -1 ) {
#endif
printf("Could not open firmware file descriptor.\n");
return -1;
}
bread = read(fd, buffer, BUFFERSIZE);
if (bread < 0) {
printf("Error while reading firmware file.\n");
close(fd);
return -1;
}
if (bread == BUFFERSIZE) {
printf("Warning: this firmware file is very large.\n");
printf("It probably cannot be properly decoded.\n");
}
close(fd);
printf("Read in a firmware file of size 0x%x.\n", bread);
if (bread < 1024) {
printf("Ridiculously small firmware file. Aborting.\n");
return -1;
}
return bread;
}
#if HAVE_ZLIB_H
static void dexor_fw_image(unsigned char *buffer, size_t zimglen) {
register int t = 0;
register int i;
register unsigned char c;
char key[] = "SamBanDam";
printf("\"Dexoring\" firmware zlib image...\n");
for (i = 0; i < zimglen; i++) {
c = key[t] | 0x80;
buffer[i] = buffer[i] ^ c;
t = (i+1) % 9;
}
}
static void decompress_fw_image(unsigned char *compressed, size_t compressed_len,
unsigned char **decompressed, size_t *rawlen) {
*decompressed = (unsigned char *) malloc(BUFFERSIZE);
if (*decompressed == NULL) {
*rawlen = 0;
return;
}
printf("Calling zlib uncompress()...\n");
*rawlen = BUFFERSIZE;
if (uncompress(*decompressed, (uLongf*) rawlen, compressed, compressed_len) != Z_OK) {
printf("There was an uncompress error.\n");
*rawlen = 0;
return;
}
}
static int write_fw_file(char *path,
unsigned char *decompressed,
size_t rawlen) {
int fd = -1;
#ifdef __WIN32__
if ( (fd = open(path, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0664)) == -1 ) {
#else
if ( (fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0664)) == -1 ) {
#endif
printf("Could not open uncompressed file.\n");
return -1;
}
if (write(fd, decompressed, rawlen) == -1) {
printf("Error while writing uncompressed file.\n");
close(fd);
unlink(path);
return -1;
}
close(fd);
return 0;
}
#endif
static int prompt()
{
char buff[2];
while (1) {
fprintf(stdout, "> ");
if ( fgets(buff, sizeof(buff), stdin) == NULL ) {
if (ferror(stdin)) {
fprintf(stderr, "File error on stdin\n");
} else {
fprintf(stderr, "EOF on stdin\n");
}
return 1;
}
if (buff[0] == 'y') {
return 0;
} else if (buff[0] == 'n') {
return 1;
}
}
}
int main(int argc, char **argv)
{
njb_t njbs[NJB_MAX_DEVICES], *njb;
int n, opt, debug;
extern int optind;
extern char *optarg;
char *path;
char *sendpath;
char *lang;
unsigned char *buffer;
size_t bread;
debug = 0;
while ( (opt = getopt(argc, argv, "D:")) != -1 ) {
switch (opt) {
case 'D':
debug = atoi(optarg);
break;
default:
usage();
break;
}
}
argc -= optind;
argv += optind;
if ( argc != 1 ) usage();
if ( debug ) NJB_Set_Debug(debug);
lang = getenv("LANG");
if (lang != NULL) {
if (strlen(lang) > 5) {
if (!strcmp(&lang[strlen(lang)-5], "UTF-8")) {
NJB_Set_Unicode(NJB_UC_UTF8);
}
}
}
path = argv[0];
printf("Analyzing firmware file %s...\n", path);
buffer = (unsigned char *) malloc(BUFFERSIZE);
if (buffer == NULL) {
printf("Could not allocate a firmware scanning buffer.\n");
return 1;
}
bread = read_in_fw(path, buffer);
if (bread == -1) {
return 1;
}
if (buffer[0] == 'C' && buffer[1] == 'I' &&
buffer[2] == 'F' && buffer[3] == 'F') {
printf("This seems to be a raw (dexored) firmware image.\n");
sendpath = path;
} else {
#if HAVE_ZLIB_H
char uncompressed_file[] = "tempimage.bin";
unsigned int zimglen;
unsigned int offset = 0;
unsigned char *decompressed;
size_t rawlen;
int i;
printf("This seems to be a zlib compressed windows executable.\n");
printf("Scanning for zlib header...\n");
for (i = 0; i < bread; i++) {
if (buffer[i] == 0xAB && buffer[i+1] == 0x3B && buffer[i+2] == 0x01) {
offset = i-4;
}
}
if (offset == 0) {
printf("Could not locate a zlib header in this firmware file.\n");
return 1;
} else {
printf("Found zlib header at file position 0x%x.\n", offset);
}
zimglen = buffer[offset+3] << 24 | buffer[offset+2] << 16
| buffer[offset+1] << 8 | buffer[offset];
printf("Zlib compressed image length: 0x%x\n", zimglen);
if (zimglen > bread-offset) {
printf("Inconsistent length of zlib compressed image, aborting.\n");
return 1;
}
dexor_fw_image(&buffer[offset+4], zimglen);
decompress_fw_image(&buffer[offset+4], zimglen, &decompressed, &rawlen);
if (rawlen == 0) {
printf("Decompression failed. Aborting.\n");
return 1;
}
printf("Decompressed image size: 0x%x\n", rawlen);
if (decompressed[0] == 'C' && decompressed[1] == 'I' &&
decompressed[2] == 'F' && decompressed[3] == 'F') {
printf("The extracted image looks like a firmware file.\n");
} else {
printf("The extracted image does not look like a firmware file.\n");
printf("Aborting.\n");
return 1;
}
printf("Writing out the extracted image to disk as \"%s\".\n", uncompressed_file);
if (write_fw_file(uncompressed_file, decompressed, rawlen) == -1) {
printf("Failed to write uncompressed file. Aborting.\n");
return 1;
}
sendpath = uncompressed_file;
free(decompressed);
#else
printf("This may be an zlib compressed .exe file firmware.\n");
printf("You must compile the \"fwupgrade\" program on a system\n");
printf("which has the zlib library and headers properly installed\n");
printf("to enable the compression of zlib compressed firmware images.\n");
#endif
}
free(buffer);
printf("Sending firmware file to jukebox\n");
if (NJB_Discover(njbs, 0, &n) == -1) {
fprintf(stderr, "could not locate any jukeboxes\n");
return 1;
}
if ( n == 0 ) {
fprintf(stderr, "no NJB devices found\n");
return 0;
}
njb = njbs;
if ( NJB_Open(njb) == -1 ) {
NJB_Error_Dump(njb,stderr);
return 1;
}
NJB_Capture(njb);
printf("I will now send the firmware to your device.\n");
printf("Continue? (y/n)\n");
if (prompt() == 0) {
if ( NJB_Send_Firmware(njb, sendpath, progress, NULL) == -1 ) {
NJB_Error_Dump(njb,stderr);
} else {
printf("\nFirmware upload complete.");
}
printf("\n");
} else {
printf("Aborted.\n");
}
NJB_Release(njb);
NJB_Close(njb);
return 0;
}