sbtools: add support for the stmp36xx format
The STMP36xx series also uses .sb files but with a different format. The main differences are the encryption and the lack of sections, making it basically a list of commands: fill, load, call, jump, switch mode, set sdram settings. Currently only the sbtoelf has support for the sb1 and can only dump the list of commands. Actual support for elf creation will come later. Change-Id: I1f2e0230c91ac64efd0e8430e0c5212098c599fd
This commit is contained in:
parent
33b7ade67f
commit
4e95b72ecb
6 changed files with 565 additions and 30 deletions
|
@ -10,7 +10,7 @@ all: $(BINS)
|
|||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
sbtoelf: sbtoelf.o crc.o crypto.o aes128.o sha1.o elf.o misc.o sb.o
|
||||
sbtoelf: sbtoelf.o crc.o crypto.o aes128.o sha1.o xorcrypt.o elf.o misc.o sb.o sb1.o
|
||||
$(LD) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
elftosb: elftosb.o crc.o crypto.o aes128.o sha1.o elf.o dbparser.o misc.o sb.o
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
static enum crypto_method_t cur_method = CRYPTO_NONE;
|
||||
static byte key[16];
|
||||
static union xorcrypt_key_t xor_key[2];
|
||||
static uint16_t usb_vid, usb_pid;
|
||||
|
||||
void crypto_setup(enum crypto_method_t method, void *param)
|
||||
|
|
|
@ -47,6 +47,7 @@ enum crypto_method_t
|
|||
{
|
||||
CRYPTO_NONE, /* disable */
|
||||
CRYPTO_KEY, /* key */
|
||||
CRYPTO_XOR_KEY, /* XOR key */
|
||||
CRYPTO_USBOTP, /* use usbotp device */
|
||||
};
|
||||
|
||||
|
@ -73,6 +74,12 @@ int crypto_apply(
|
|||
byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
|
||||
int encrypt);
|
||||
|
||||
union xorcrypt_key_t
|
||||
{
|
||||
uint8_t key[64];
|
||||
uint32_t k[16];
|
||||
};
|
||||
|
||||
/* all-in-one function */
|
||||
struct crypto_key_t
|
||||
{
|
||||
|
@ -80,6 +87,7 @@ struct crypto_key_t
|
|||
union
|
||||
{
|
||||
byte key[16];
|
||||
union xorcrypt_key_t xor_key[2];
|
||||
uint32_t vid_pid;
|
||||
byte param[0];
|
||||
}u;
|
||||
|
@ -112,4 +120,10 @@ void sha_1_update(struct sha_1_params_t *params, byte *buffer, int size);
|
|||
void sha_1_finish(struct sha_1_params_t *params);
|
||||
void sha_1_output(struct sha_1_params_t *params, byte *out);
|
||||
|
||||
/* xorcrypt.c */
|
||||
|
||||
// WARNING those functions modifies the keys !!
|
||||
uint32_t xor_encrypt(union xorcrypt_key_t keys[2], void *data, int size);
|
||||
uint32_t xor_decrypt(union xorcrypt_key_t keys[2], void *data, int size);
|
||||
|
||||
#endif /* __CRYPTO_H__ */
|
||||
|
|
288
utils/imxtools/sbtools/sb1.c
Normal file
288
utils/imxtools/sbtools/sb1.c
Normal file
|
@ -0,0 +1,288 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2012 Amaury Pouly
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include "misc.h"
|
||||
#include "crypto.h"
|
||||
#include "sb1.h"
|
||||
|
||||
static uint16_t swap16(uint16_t t)
|
||||
{
|
||||
return (t << 8) | (t >> 8);
|
||||
}
|
||||
|
||||
static void fix_version(struct sb1_version_t *ver)
|
||||
{
|
||||
ver->major = swap16(ver->major);
|
||||
ver->minor = swap16(ver->minor);
|
||||
ver->revision = swap16(ver->revision);
|
||||
}
|
||||
|
||||
enum sb1_error_t sb1_write_file(struct sb1_file_t *sb, const char *filename)
|
||||
{
|
||||
return SB1_ERROR;
|
||||
}
|
||||
|
||||
struct sb1_file_t *sb1_read_file(const char *filename, void *u,
|
||||
sb1_color_printf cprintf, enum sb1_error_t *err)
|
||||
{
|
||||
return sb1_read_file_ex(filename, 0, -1, u, cprintf, err);
|
||||
}
|
||||
|
||||
struct sb1_file_t *sb1_read_file_ex(const char *filename, size_t offset, size_t size, void *u,
|
||||
sb1_color_printf cprintf, enum sb1_error_t *err)
|
||||
{
|
||||
#define fatal(e, ...) \
|
||||
do { if(err) *err = e; \
|
||||
cprintf(u, true, GREY, __VA_ARGS__); \
|
||||
free(buf); \
|
||||
return NULL; } while(0)
|
||||
|
||||
FILE *f = fopen(filename, "rb");
|
||||
void *buf = NULL;
|
||||
if(f == NULL)
|
||||
fatal(SB1_OPEN_ERROR, "Cannot open file for reading\n");
|
||||
fseek(f, 0, SEEK_END);
|
||||
size_t read_size = ftell(f);
|
||||
fseek(f, offset, SEEK_SET);
|
||||
if(size != (size_t)-1)
|
||||
read_size = size;
|
||||
buf = xmalloc(read_size);
|
||||
if(fread(buf, read_size, 1, f) != 1)
|
||||
{
|
||||
fclose(f);
|
||||
fatal(SB1_READ_ERROR, "Cannot read file\n");
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
struct sb1_file_t *ret = sb1_read_memory(buf, read_size, u, cprintf, err);
|
||||
free(buf);
|
||||
return ret;
|
||||
|
||||
#undef fatal
|
||||
}
|
||||
|
||||
static const char *sb1_cmd_name(int cmd)
|
||||
{
|
||||
switch(cmd)
|
||||
{
|
||||
case SB1_INST_LOAD: return "load";
|
||||
case SB1_INST_FILL: return "fill";
|
||||
case SB1_INST_JUMP: return "jump";
|
||||
case SB1_INST_CALL: return "call";
|
||||
case SB1_INST_MODE: return "mode";
|
||||
case SB1_INST_SDRAM: return "sdram";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
struct sb1_file_t *sb1_read_memory(void *_buf, size_t filesize, void *u,
|
||||
sb1_color_printf cprintf, enum sb1_error_t *err)
|
||||
{
|
||||
struct sb1_file_t *sb1_file = NULL;
|
||||
uint8_t *buf = _buf;
|
||||
|
||||
#define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
|
||||
#define fatal(e, ...) \
|
||||
do { if(err) *err = e; \
|
||||
cprintf(u, true, GREY, __VA_ARGS__); \
|
||||
sb1_free(sb1_file); \
|
||||
return NULL; } while(0)
|
||||
#define print_hex(c, p, len, nl) \
|
||||
do { printf(c, ""); print_hex(p, len, nl); } while(0)
|
||||
|
||||
sb1_file = xmalloc(sizeof(struct sb1_file_t));
|
||||
memset(sb1_file, 0, sizeof(struct sb1_file_t));
|
||||
struct sb1_header_t *header = (struct sb1_header_t *)buf;
|
||||
|
||||
if(memcmp(header->signature, "STMP", 4) != 0)
|
||||
fatal(SB1_FORMAT_ERROR, "Bad signature\n");
|
||||
if(header->image_size > filesize)
|
||||
fatal(SB1_FORMAT_ERROR, "File too small (should be at least %d bytes)\n",
|
||||
header->image_size);
|
||||
if(header->header_size != sizeof(struct sb1_header_t))
|
||||
fatal(SB1_FORMAT_ERROR, "Bad header size\n");
|
||||
|
||||
printf(BLUE, "Basic info:\n");
|
||||
printf(GREEN, " ROM version: ");
|
||||
printf(YELLOW, "%x\n", header->rom_version);
|
||||
printf(GREEN, " Userdata offset: ");
|
||||
printf(YELLOW, "%x\n", header->userdata_offset);
|
||||
printf(GREEN, " Pad: ");
|
||||
printf(YELLOW, "%x\n", header->pad2);
|
||||
|
||||
struct sb1_version_t product_ver = header->product_ver;
|
||||
fix_version(&product_ver);
|
||||
struct sb1_version_t component_ver = header->component_ver;
|
||||
fix_version(&component_ver);
|
||||
|
||||
memcpy(&sb1_file->product_ver, &product_ver, sizeof(product_ver));
|
||||
memcpy(&sb1_file->component_ver, &component_ver, sizeof(component_ver));
|
||||
|
||||
printf(GREEN, " Product version: ");
|
||||
printf(YELLOW, "%X.%X.%X\n", product_ver.major, product_ver.minor, product_ver.revision);
|
||||
printf(GREEN, " Component version: ");
|
||||
printf(YELLOW, "%X.%X.%X\n", component_ver.major, component_ver.minor, component_ver.revision);
|
||||
|
||||
printf(GREEN, " Drive tag: ");
|
||||
printf(YELLOW, "%x\n", header->drive_tag);
|
||||
|
||||
/* reduce size w.r.t to userdata part */
|
||||
uint32_t userdata_size = 0;
|
||||
if(header->userdata_offset != 0)
|
||||
{
|
||||
userdata_size = header->image_size - header->userdata_offset;
|
||||
header->image_size -= userdata_size;
|
||||
}
|
||||
|
||||
if(header->image_size % SECTOR_SIZE)
|
||||
{
|
||||
if(g_force)
|
||||
printf(GREY, "Image size is not a multiple of sector size\n");
|
||||
else
|
||||
fatal(SB1_FORMAT_ERROR, "Image size is not a multiple of sector size\n");
|
||||
}
|
||||
|
||||
/* find key */
|
||||
union xorcrypt_key_t key[2];
|
||||
bool valid_key = false;
|
||||
uint8_t sector[SECTOR_SIZE];
|
||||
|
||||
for(int i = 0; i < g_nr_keys; i++)
|
||||
{
|
||||
if(!g_key_array[i].method == CRYPTO_XOR_KEY)
|
||||
continue;
|
||||
/* copy key and data because it's modified by the crypto code */
|
||||
memcpy(key, g_key_array[i].u.xor_key, sizeof(key));
|
||||
memcpy(sector, header + 1, SECTOR_SIZE - header->header_size);
|
||||
/* try to decrypt the first sector */
|
||||
uint32_t mark = xor_decrypt(key, sector, SECTOR_SIZE - 4 - header->header_size);
|
||||
if(mark != *(uint32_t *)§or[SECTOR_SIZE - 4 - header->header_size])
|
||||
continue;
|
||||
/* found ! */
|
||||
valid_key = true;
|
||||
/* copy key again it's modified by the crypto code */
|
||||
memcpy(key, g_key_array[i].u.xor_key, sizeof(key));
|
||||
break;
|
||||
}
|
||||
|
||||
printf(BLUE, "Crypto\n");
|
||||
for(int i = 0; i < 2; i++)
|
||||
{
|
||||
printf(RED, " Key %d\n", i);
|
||||
printf(OFF, " ");
|
||||
for(int j = 0; j < 64; j++)
|
||||
{
|
||||
printf(YELLOW, "%02x ", key[i].key[j]);
|
||||
if((j + 1) % 16 == 0)
|
||||
{
|
||||
printf(OFF, "\n");
|
||||
if(j + 1 != 64)
|
||||
printf(OFF, " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!valid_key)
|
||||
fatal(SB1_NO_VALID_KEY, "No valid key found\n");
|
||||
|
||||
/* decrypt image in-place (and removing crypto markers) */
|
||||
void *ptr = header + 1;
|
||||
void *copy_ptr = header + 1;
|
||||
int offset = header->header_size;
|
||||
for(unsigned i = 0; i < header->image_size / SECTOR_SIZE; i++)
|
||||
{
|
||||
int size = SECTOR_SIZE - 4 - offset;
|
||||
uint32_t mark = xor_decrypt(key, ptr, size);
|
||||
if(mark != *(uint32_t *)(ptr + size))
|
||||
fatal(SB1_CHECKSUM_ERROR, "Crypto mark mismatch\n");
|
||||
memmove(copy_ptr, ptr, size);
|
||||
ptr += size + 4;
|
||||
copy_ptr += size;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
/* reduce image size given the removed marks */
|
||||
header->image_size -= header->image_size / SECTOR_SIZE;
|
||||
|
||||
printf(BLUE, "Commands\n");
|
||||
struct sb1_cmd_header_t *cmd = (void *)(header + 1);
|
||||
while((void *)cmd < (void *)header + header->image_size)
|
||||
{
|
||||
printf(GREEN, " Command");
|
||||
printf(YELLOW, " %#x\n", cmd->cmd);
|
||||
printf(YELLOW, " Size:");
|
||||
printf(RED, " %#x\n", SB1_CMD_SIZE(cmd->cmd));
|
||||
printf(YELLOW, " Critical:");
|
||||
printf(RED, " %d\n", SB1_CMD_CRITICAL(cmd->cmd));
|
||||
printf(YELLOW, " Data Type:");
|
||||
printf(RED, " %#x\n", SB1_CMD_DATATYPE(cmd->cmd));
|
||||
printf(YELLOW, " Bytes:");
|
||||
printf(RED, " %#x\n", SB1_CMD_BYTES(cmd->cmd));
|
||||
printf(YELLOW, " Boot:");
|
||||
printf(RED, " %#x (%s)\n", SB1_CMD_BOOT(cmd->cmd), sb1_cmd_name(SB1_CMD_BOOT(cmd->cmd)));
|
||||
printf(YELLOW, " Addr:");
|
||||
printf(RED, " %#x\n", cmd->addr);
|
||||
|
||||
/* last instruction ? */
|
||||
if(SB1_CMD_BOOT(cmd->cmd) == SB1_INST_JUMP ||
|
||||
SB1_CMD_BOOT(cmd->cmd) == SB1_INST_MODE)
|
||||
break;
|
||||
|
||||
cmd = (void *)cmd + 4 + 4 * SB1_CMD_SIZE(cmd->cmd);
|
||||
}
|
||||
|
||||
sb1_file->data_size = header->image_size - header->header_size;
|
||||
sb1_file->data = malloc(sb1_file->data_size);
|
||||
memcpy(sb1_file->data, header + 1, sb1_file->data_size);
|
||||
|
||||
return sb1_file;
|
||||
#undef printf
|
||||
#undef fatal
|
||||
#undef print_hex
|
||||
}
|
||||
|
||||
void sb1_free(struct sb1_file_t *file)
|
||||
{
|
||||
if(!file) return;
|
||||
|
||||
free(file->data);
|
||||
free(file);
|
||||
}
|
||||
|
||||
void sb1_dump(struct sb1_file_t *file, void *u, sb1_color_printf cprintf)
|
||||
{
|
||||
#define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
|
||||
#define print_hex(c, p, len, nl) \
|
||||
do { printf(c, ""); print_hex(p, len, nl); } while(0)
|
||||
|
||||
#define TREE RED
|
||||
#define HEADER GREEN
|
||||
#define TEXT YELLOW
|
||||
#define TEXT2 BLUE
|
||||
#define SEP OFF
|
||||
|
||||
#undef printf
|
||||
#undef print_hex
|
||||
}
|
||||
|
111
utils/imxtools/sbtools/sb1.h
Normal file
111
utils/imxtools/sbtools/sb1.h
Normal file
|
@ -0,0 +1,111 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2012 Amaury Pouly
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef __SB1_H__
|
||||
#define __SB1_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "misc.h"
|
||||
|
||||
#define SECTOR_SIZE 512
|
||||
|
||||
/* All fields are in big-endian BCD */
|
||||
struct sb1_version_t
|
||||
{
|
||||
uint16_t major;
|
||||
uint16_t pad0;
|
||||
uint16_t minor;
|
||||
uint16_t pad1;
|
||||
uint16_t revision;
|
||||
uint16_t pad2;
|
||||
};
|
||||
|
||||
struct sb1_header_t
|
||||
{
|
||||
uint32_t rom_version;
|
||||
uint32_t image_size;
|
||||
uint32_t header_size;
|
||||
uint32_t userdata_offset;
|
||||
uint32_t pad2;
|
||||
uint8_t signature[4]; /* Signature "STMP" */
|
||||
struct sb1_version_t product_ver;
|
||||
struct sb1_version_t component_ver;
|
||||
uint32_t drive_tag;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct sb1_cmd_header_t
|
||||
{
|
||||
uint32_t cmd; // 31:21=cmd size, 20=critical, 19:6=size 5:4=datatype, 3:0=boot cmd
|
||||
uint32_t addr;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define SB1_CMD_SIZE(cmd) ((cmd) >> 21)
|
||||
#define SB1_CMD_CRITICAL(cmd) !!(cmd & (1 << 20))
|
||||
#define SB1_CMD_BYTES(cmd) (((cmd) >> 6) & 0x3fff)
|
||||
#define SB1_CMD_DATATYPE(cmd) (((cmd) >> 4) & 0x3)
|
||||
#define SB1_CMD_BOOT(cmd) ((cmd) & 0xf)
|
||||
|
||||
#define SB1_INST_LOAD 0x1
|
||||
#define SB1_INST_FILL 0x2
|
||||
#define SB1_INST_JUMP 0x3
|
||||
#define SB1_INST_CALL 0x4
|
||||
#define SB1_INST_MODE 0x5
|
||||
#define SB1_INST_SDRAM 0x6
|
||||
|
||||
struct sb1_file_t
|
||||
{
|
||||
struct sb1_version_t product_ver;
|
||||
struct sb1_version_t component_ver;
|
||||
void *data;
|
||||
int data_size;
|
||||
};
|
||||
|
||||
enum sb1_error_t
|
||||
{
|
||||
SB1_SUCCESS = 0,
|
||||
SB1_ERROR = -1,
|
||||
SB1_OPEN_ERROR = -2,
|
||||
SB1_READ_ERROR = -3,
|
||||
SB1_WRITE_ERROR = -4,
|
||||
SB1_FORMAT_ERROR = -5,
|
||||
SB1_CHECKSUM_ERROR = -6,
|
||||
SB1_NO_VALID_KEY = -7,
|
||||
SB1_FIRST_CRYPTO_ERROR = -8,
|
||||
SB1_LAST_CRYPTO_ERROR = SB1_FIRST_CRYPTO_ERROR - CRYPTO_NUM_ERRORS,
|
||||
};
|
||||
|
||||
enum sb1_error_t sb1_write_file(struct sb1_file_t *sb, const char *filename);
|
||||
|
||||
typedef void (*sb1_color_printf)(void *u, bool err, color_t c, const char *f, ...);
|
||||
struct sb1_file_t *sb1_read_file(const char *filename, void *u,
|
||||
sb1_color_printf printf, enum sb1_error_t *err);
|
||||
/* use size_t(-1) to use maximum size */
|
||||
struct sb1_file_t *sb1_read_file_ex(const char *filename, size_t offset, size_t size,
|
||||
void *u, sb1_color_printf printf, enum sb1_error_t *err);
|
||||
struct sb1_file_t *sb1_read_memory(void *buffer, size_t size, void *u,
|
||||
sb1_color_printf printf, enum sb1_error_t *err);
|
||||
|
||||
void sb1_dump(struct sb1_file_t *file, void *u, sb1_color_printf printf);
|
||||
void sb1_free(struct sb1_file_t *file);
|
||||
|
||||
#endif /* __SB1_H__ */
|
||||
|
|
@ -40,6 +40,7 @@
|
|||
#include "crypto.h"
|
||||
#include "elf.h"
|
||||
#include "sb.h"
|
||||
#include "sb1.h"
|
||||
#include "misc.h"
|
||||
|
||||
/* all blocks are sized as a multiple of 0x1ff */
|
||||
|
@ -156,6 +157,15 @@ static void extract_sb_file(struct sb_file_t *file)
|
|||
extract_sb_section(&file->sections[i]);
|
||||
}
|
||||
|
||||
static void extract_sb1_file(struct sb1_file_t *file)
|
||||
{
|
||||
FILE *f = fopen(g_out_prefix, "wb");
|
||||
if(f == NULL)
|
||||
bugp("Cannot open %s for writing\n", g_out_prefix);
|
||||
fwrite(file->data, file->data_size, 1, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("Usage: sbtoelf [options] sb-file\n");
|
||||
|
@ -170,6 +180,8 @@ static void usage(void)
|
|||
printf(" -n/--no-color\tDisable output colors\n");
|
||||
printf(" -l/--loopback <file>\tProduce sb file out of extracted description*\n");
|
||||
printf(" -f/--force\tForce reading even without a key*\n");
|
||||
printf(" -1/--v1\tForce to read file as a version 1 file\n");
|
||||
printf(" -2/--v2\tForce to read file as a version 2 file\n");
|
||||
printf("Options marked with a * are for debug purpose only\n");
|
||||
exit(1);
|
||||
}
|
||||
|
@ -191,11 +203,72 @@ static struct crypto_key_t g_zero_key =
|
|||
.u.key = {0}
|
||||
};
|
||||
|
||||
static struct crypto_key_t g_default_xor_key =
|
||||
{
|
||||
.method = CRYPTO_XOR_KEY,
|
||||
.u.xor_key =
|
||||
{
|
||||
{.k = {0x67ECAEF6, 0xB31FB961, 0x118A9F4C, 0xA32A97DA,
|
||||
0x6CC39617, 0x5BC00314, 0x9D430685, 0x4D7DB502,
|
||||
0xA347685E, 0x3C87E86C, 0x8987AAA0, 0x24B78EF1,
|
||||
0x893B9605, 0x9BB8C2BE, 0x6D9544E2, 0x375B525C}},
|
||||
{.k = {0x3F424704, 0x53B5A331, 0x6AD345A5, 0x20DCEC51,
|
||||
0x743C8D3B, 0x444B3792, 0x0AF429569, 0xB7EE1111,
|
||||
0x583BF768, 0x9683BF9A, 0x0B032D799, 0xFE4E78ED,
|
||||
0xF20D08C2, 0xFA0BE4A2, 0x4D89C317, 0x887B2D6F}}
|
||||
}
|
||||
};
|
||||
|
||||
enum sb_version_guess_t
|
||||
{
|
||||
SB_VERSION_1,
|
||||
SB_VERSION_2,
|
||||
SB_VERSION_UNK,
|
||||
};
|
||||
|
||||
enum sb_version_guess_t guess_sb_version(const char *filename)
|
||||
{
|
||||
FILE *f = fopen(filename, "rb");
|
||||
if(f == NULL)
|
||||
bugp("Cannot open file for reading\n");
|
||||
// check signature
|
||||
uint8_t sig[4];
|
||||
if(fseek(f, 20, SEEK_SET))
|
||||
return SB_VERSION_UNK;
|
||||
if(fread(sig, 4, 1, f) != 1)
|
||||
return SB_VERSION_UNK;
|
||||
if(memcmp(sig, "STMP", 4) != 0)
|
||||
return SB_VERSION_UNK;
|
||||
// check header size (v1)
|
||||
uint32_t hdr_size;
|
||||
if(fseek(f, 8, SEEK_SET))
|
||||
return SB_VERSION_UNK;
|
||||
if(fread(&hdr_size, 4, 1, f) != 1)
|
||||
return SB_VERSION_UNK;
|
||||
if(hdr_size == 0x34)
|
||||
return SB_VERSION_1;
|
||||
// check header size (v2)
|
||||
if(fseek(f, 32, SEEK_SET))
|
||||
return SB_VERSION_UNK;
|
||||
if(fread(&hdr_size, 4, 1, f) != 1)
|
||||
return SB_VERSION_UNK;
|
||||
if(hdr_size == 0xc)
|
||||
return SB_VERSION_2;
|
||||
return SB_VERSION_UNK;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
bool raw_mode = false;
|
||||
const char *loopback = NULL;
|
||||
|
||||
bool force_sb1 = false;
|
||||
bool force_sb2 = false;
|
||||
|
||||
/* decrypt the xor key which is xor'ed */
|
||||
for(int i = 0; i < 2; i++)
|
||||
for(int j = 0; j < 16; j++)
|
||||
g_default_xor_key.u.xor_key[i].k[j] ^= 0xaa55aa55;
|
||||
|
||||
while(1)
|
||||
{
|
||||
static struct option long_options[] =
|
||||
|
@ -205,11 +278,13 @@ int main(int argc, char **argv)
|
|||
{"add-key", required_argument, 0, 'a'},
|
||||
{"no-color", no_argument, 0, 'n'},
|
||||
{"loopback", required_argument, 0, 'l'},
|
||||
{"force", no_argument, 0, 'f' },
|
||||
{"force", no_argument, 0, 'f'},
|
||||
{"v1", no_argument, 0, '1'},
|
||||
{"v2", no_argument, 0, '2'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
int c = getopt_long(argc, argv, "?do:k:zra:nl:f", long_options, NULL);
|
||||
int c = getopt_long(argc, argv, "?do:k:zra:nl:f12x", long_options, NULL);
|
||||
if(c == -1)
|
||||
break;
|
||||
switch(c)
|
||||
|
@ -243,10 +318,11 @@ int main(int argc, char **argv)
|
|||
break;
|
||||
}
|
||||
case 'z':
|
||||
{
|
||||
add_keys(&g_zero_key, 1);
|
||||
break;
|
||||
}
|
||||
case 'x':
|
||||
add_keys(&g_default_xor_key, 1);
|
||||
break;
|
||||
case 'r':
|
||||
raw_mode = true;
|
||||
break;
|
||||
|
@ -261,11 +337,20 @@ int main(int argc, char **argv)
|
|||
add_keys(&key, 1);
|
||||
break;
|
||||
}
|
||||
case '1':
|
||||
force_sb1 = true;
|
||||
break;
|
||||
case '2':
|
||||
force_sb2 = true;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if(force_sb1 && force_sb2)
|
||||
bug("You cannot force both version 1 and 2\n");
|
||||
|
||||
if(argc - optind != 1)
|
||||
{
|
||||
usage();
|
||||
|
@ -274,34 +359,70 @@ int main(int argc, char **argv)
|
|||
|
||||
const char *sb_filename = argv[optind];
|
||||
|
||||
enum sb_error_t err;
|
||||
struct sb_file_t *file = sb_read_file(sb_filename, raw_mode, NULL, sb_printf, &err);
|
||||
if(file == NULL)
|
||||
enum sb_version_guess_t ver = guess_sb_version(sb_filename);
|
||||
|
||||
if(force_sb2 || ver == SB_VERSION_2)
|
||||
{
|
||||
enum sb_error_t err;
|
||||
struct sb_file_t *file = sb_read_file(sb_filename, raw_mode, NULL, sb_printf, &err);
|
||||
if(file == NULL)
|
||||
{
|
||||
color(OFF);
|
||||
printf("SB read failed: %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
color(OFF);
|
||||
if(g_out_prefix)
|
||||
extract_sb_file(file);
|
||||
if(g_debug)
|
||||
{
|
||||
color(GREY);
|
||||
printf("[Debug output]\n");
|
||||
sb_dump(file, NULL, sb_printf);
|
||||
}
|
||||
if(loopback)
|
||||
{
|
||||
/* sb_read_file will fill real key and IV but we don't want to override
|
||||
* them when looping back otherwise the output will be inconsistent and
|
||||
* garbage */
|
||||
file->override_real_key = false;
|
||||
file->override_crypto_iv = false;
|
||||
sb_write_file(file, loopback);
|
||||
}
|
||||
sb_free(file);
|
||||
}
|
||||
else if(force_sb1 || ver == SB_VERSION_1)
|
||||
{
|
||||
enum sb1_error_t err;
|
||||
struct sb1_file_t *file = sb1_read_file(sb_filename, NULL, sb_printf, &err);
|
||||
if(file == NULL)
|
||||
{
|
||||
color(OFF);
|
||||
printf("SB read failed: %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
color(OFF);
|
||||
if(g_out_prefix)
|
||||
extract_sb1_file(file);
|
||||
if(g_debug)
|
||||
{
|
||||
color(GREY);
|
||||
printf("[Debug output]\n");
|
||||
sb1_dump(file, NULL, sb_printf);
|
||||
}
|
||||
if(loopback)
|
||||
sb1_write_file(file, loopback);
|
||||
|
||||
sb1_free(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
color(OFF);
|
||||
printf("SB read failed: %d\n", err);
|
||||
printf("Cannot guess file type, are you sure it's a valid image ?\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
color(OFF);
|
||||
if(g_out_prefix)
|
||||
extract_sb_file(file);
|
||||
if(g_debug)
|
||||
{
|
||||
color(GREY);
|
||||
printf("[Debug output]\n");
|
||||
sb_dump(file, NULL, sb_printf);
|
||||
}
|
||||
if(loopback)
|
||||
{
|
||||
/* sb_read_file will fill real key and IV but we don't want to override
|
||||
* them when looping back otherwise the output will be inconsistent and
|
||||
* garbage */
|
||||
file->override_real_key = false;
|
||||
file->override_crypto_iv = false;
|
||||
sb_write_file(file, loopback);
|
||||
}
|
||||
sb_free(file);
|
||||
clear_keys();
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in a new issue