summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBertrik Sikken <bertrik@sikken.nl>2010-11-28 10:53:01 +0000
committerBertrik Sikken <bertrik@sikken.nl>2010-11-28 10:53:01 +0000
commitc412c2dcad160de6d2efbd531fc71fe61ce1f1f7 (patch)
tree621185394f1512f68ed731da2db6e6b6e4293ffe
parent10e0279afcd10ec8ed3bac88e942e8c431947354 (diff)
Initial version of sbinfo, a utility to analyse .sb files (used for the fuze+ for example)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28691 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--utils/sbinfo/Makefile9
-rw-r--r--utils/sbinfo/sbinfo.c257
2 files changed, 266 insertions, 0 deletions
diff --git a/utils/sbinfo/Makefile b/utils/sbinfo/Makefile
new file mode 100644
index 0000000000..811249e924
--- /dev/null
+++ b/utils/sbinfo/Makefile
@@ -0,0 +1,9 @@
+TGT = sbinfo
+
+all: $(TGT)
+
+$(TGT): sbinfo.c
+ $(CC) -ansi -o $(TGT) -W -Wall sbinfo.c
+
+clean:
+ rm -fr $(TGT)
diff --git a/utils/sbinfo/sbinfo.c b/utils/sbinfo/sbinfo.c
new file mode 100644
index 0000000000..aa001d4023
--- /dev/null
+++ b/utils/sbinfo/sbinfo.c
@@ -0,0 +1,257 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Bertrik Sikken
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+/*
+ * .sb file parser and chunk extractor
+ *
+ * Based on amsinfo, which is
+ * Copyright © 2008 Rafaël Carré <rafael.carre@gmail.com>
+ */
+
+#define _ISOC99_SOURCE /* snprintf() */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+
+#if 1 /* ANSI colors */
+
+# define color(a) printf("%s",a)
+char OFF[] = { 0x1b, 0x5b, 0x31, 0x3b, '0', '0', 0x6d, '\0' };
+
+char GREY[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '0', 0x6d, '\0' };
+char RED[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '1', 0x6d, '\0' };
+char GREEN[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '2', 0x6d, '\0' };
+char YELLOW[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '3', 0x6d, '\0' };
+char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' };
+
+#else
+ /* disable colors */
+# define color(a)
+#endif
+
+#define bug(...) do { fprintf(stderr,"ERROR: "__VA_ARGS__); exit(1); } while(0)
+#define bugp(a) do { perror("ERROR: "a); exit(1); } while(0)
+
+/* byte swapping */
+#define get32le(a) ((uint32_t) \
+ ( buf[a+3] << 24 | buf[a+2] << 16 | buf[a+1] << 8 | buf[a] ))
+#define get16le(a) ((uint16_t)( buf[a+1] << 8 | buf[a] ))
+
+/* all blocks are sized as a multiple of 0x1ff */
+#define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff)
+
+/* If you find a firmware that breaks the known format ^^ */
+#define assert(a) do { if(!(a)) { fprintf(stderr,"Assertion \"%s\" failed in %s() line %d!\n\nPlease send us your firmware!\n",#a,__func__,__LINE__); exit(1); } } while(0)
+
+/* globals */
+
+size_t sz; /* file size */
+uint8_t *buf; /* file content */
+
+
+/* 1st block description */
+uint32_t idx,checksum,bs_multiplier,firmware_sz;
+uint32_t unknown_4_1; uint16_t unknown_1, unknown_2;
+uint32_t unknown_4_2,unknown_4_3;
+
+static void *xmalloc(size_t s) /* malloc helper */
+{
+ void * r = malloc(s);
+ if(!r) bugp("malloc");
+ return r;
+}
+
+static char getchr(int offset)
+{
+ char c;
+ c = buf[offset];
+ return isprint(c) ? c : '_';
+}
+
+static void getstrle(char string[], int offset)
+{
+ int i;
+ for (i = 0; i < 4; i++) {
+ string[i] = getchr(offset + 3 - i);
+ }
+ string[4] = 0;
+}
+
+static void getstrbe(char string[], int offset)
+{
+ int i;
+ for (i = 0; i < 4; i++) {
+ string[i] = getchr(offset + i);
+ }
+ string[4] = 0;
+}
+
+static void printhex(int offset, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ printf("%02X ", buf[offset + i]);
+ }
+ printf("\n");
+}
+
+/* verify the firmware header */
+static void check(unsigned long filesize)
+{
+ /* check STMP marker */
+ char stmp[5];
+ getstrbe(stmp, 0x14);
+ assert(strcmp(stmp, "STMP") == 0);
+ color(GREEN);
+
+ /* get total size */
+ unsigned long totalsize = 16 * get32le(0x1C);
+ color(GREEN);
+ assert(filesize == totalsize);
+}
+
+static void extract(unsigned long filesize)
+{
+ /* Basic header info */
+ color(BLUE);
+ printf("Basic info:\n");
+ color(GREEN);
+ printf("\tHeader SHA-1: ");
+ printhex(0, 20);
+ printf("\tFlags: ");
+ printhex(0x18, 4);
+ printf("\tTotal file size : %ld\n", filesize);
+
+ /* Sizes and offsets */
+ color(BLUE);
+ printf("Sizes and offsets:\n");
+ color(GREEN);
+ int num_enc = get16le(0x28);
+ printf("\t# of encryption info = %d\n", num_enc);
+ int num_chunks = get16le(0x2E);
+ printf("\t# of chunk headers = %d\n", num_chunks);
+
+ /* Versions */
+ color(BLUE);
+ printf("Versions\n");
+ color(GREEN);
+
+ printf("\tRandom 1: ");
+ printhex(0x32, 6);
+ printf("\tRandom 2: ");
+ printhex(0x5A, 6);
+
+ uint64_t micros_l = get32le(0x38);
+ uint64_t micros_h = get32le(0x3c);
+ uint64_t micros = ((uint64_t)micros_h << 32) | micros_l;
+ time_t seconds = (micros / (uint64_t)1000000L);
+ seconds += 946684800; /* 2000/1/1 0:00:00 */
+ struct tm *time = gmtime(&seconds);
+ color(GREEN);
+ printf("\tCreation date/time = %s", asctime(time));
+
+ int p_maj = get32le(0x40);
+ int p_min = get32le(0x44);
+ int p_sub = get32le(0x48);
+ int c_maj = get32le(0x4C);
+ int c_min = get32le(0x50);
+ int c_sub = get32le(0x54);
+ color(GREEN);
+ printf("\tProduct version = %X.%X.%X\n", p_maj, p_min, p_sub);
+ printf("\tComponent version = %X.%X.%X\n", c_maj, c_min, c_sub);
+
+ /* chunks */
+ color(BLUE);
+ printf("Chunks\n");
+
+ int i;
+ for (i = 0; i < num_chunks; i++) {
+ uint32_t ofs = 0x60 + (i * 16);
+
+ char name[5];
+ getstrle(name, ofs + 0);
+ int pos = 16 * get32le(ofs + 4);
+ int size = 16 * get32le(ofs + 8);
+ int flags = get32le(ofs + 12);
+
+ color(GREEN);
+ printf("\tChunk '%s'\n", name);
+ printf("\t\tpos = %8x - %8x\n", pos, pos+size);
+ printf("\t\tlen = %8x\n", size);
+ printf("\t\tflags = %8x\n", flags);
+
+ /* save it */
+ char filename[16];
+ strcpy(filename, name);
+ strcat(filename, ".bin");
+ FILE *file = fopen(filename, "wb");
+ if (file != NULL) {
+ fwrite(buf + pos, size, 1, file);
+ fclose(file);
+ }
+ }
+
+ /* final signature */
+ color(BLUE);
+ printf("Final signature:\n\t");
+ color(GREEN);
+ printhex(filesize - 32, 16);
+ printf("\t");
+ printhex(filesize - 16, 16);
+}
+
+int main(int argc, const char **argv)
+{
+ int fd;
+ struct stat st;
+ if(argc != 2)
+ bug("Usage: %s <firmware>\n",*argv);
+
+ if( (fd = open(argv[1],O_RDONLY)) == -1 )
+ bugp("opening firmware failed");
+
+ if(fstat(fd,&st) == -1)
+ bugp("firmware stat() failed");
+ sz = st.st_size;
+
+ buf=xmalloc(sz);
+ if(read(fd,buf,sz)!=(ssize_t)sz) /* load the whole file into memory */
+ bugp("reading firmware");
+
+ close(fd);
+
+ check(st.st_size); /* verify header and checksums */
+ extract(st.st_size); /* split in blocks */
+
+ color(OFF);
+
+ free(buf);
+ return 0;
+}