rockbox/utils/rk27utils/rkboottool/rkboottool.c

361 lines
10 KiB
C

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#define VERSION "v0.3"
/* time field stucture */
struct rktime_t
{
uint16_t year;
uint16_t month;
uint16_t day;
uint16_t hour;
uint16_t minute;
uint16_t second;
};
/* Rock27Boot.bin header structure */
struct rkboot_info_t
{
char sign[32];
uint8_t check_values[16];
struct rktime_t time;
uint32_t ui_master_version;
uint32_t ui_slave_version;
uint32_t s1_offset;
int32_t s1_len;
uint32_t s2_offset;
int32_t s2_len;
uint32_t s3_offset;
int32_t s3_len;
uint32_t s4_offset;
int32_t s4_len;
uint32_t version_flag;
};
/* actions */
enum {
NONE = 0,
INFO = 1,
EXTRACT = 2,
SCRAMBLE = 4
};
/* scramble mode */
enum {
CONTINOUS_ENC, /* scramble whole block at once */
PAGE_ENC /* nand bootloader is scrambled in 0x200 chunks */
};
/* scrambling/descrambling reverse engineered by AleMaxx */
static void encode_page(uint8_t *inpg, uint8_t *outpg, const int size)
{
uint8_t key[] = {
0x7C, 0x4E, 0x03, 0x04,
0x55, 0x05, 0x09, 0x07,
0x2D, 0x2C, 0x7B, 0x38,
0x17, 0x0D, 0x17, 0x11
};
int i, i3, x, val, idx;
uint8_t key1[0x100];
uint8_t key2[0x100];
for (i=0; i<0x100; i++) {
key1[i] = i;
key2[i] = key[i&0xf];
}
i3 = 0;
for (i=0; i<0x100; i++) {
x = key1[i];
i3 = key1[i] + i3;
i3 += key2[i];
i3 &= 0xff;
key1[i] = key1[i3];
key1[i3] = x;
}
idx = 0;
for (i=0; i<size; i++) {
x = key1[(i+1) & 0xff];
val = x;
idx = (x + idx) & 0xff;
key1[(i+1) & 0xff] = key1[idx];
key1[idx] = (x & 0xff);
val = (key1[(i+1)&0xff] + x) & 0xff;
val = key1[val];
outpg[i] = val ^ inpg[i];
}
}
static void *binary_extract(FILE *fp, uint32_t offset, uint32_t len, int descramble, int encode_mode)
{
void *buff, *buff_ptr;
uint32_t ret;
if ((fp == NULL) || len == 0)
return NULL;
/* allocate buff */
if ((buff = malloc(len)) == NULL)
return NULL;
/* seek to the begining of the data */
fseek(fp, offset, SEEK_SET);
/* read into the buffer */
ret = fread(buff, 1, len, fp);
if (ret != len)
{
free(buff);
return NULL;
}
/* descramble */
if ( descramble )
{
buff_ptr = buff;
if (encode_mode == PAGE_ENC)
{
while (len >= 0x200)
{
encode_page((uint8_t *)buff_ptr,
(uint8_t *)buff_ptr,
0x200);
buff_ptr += 0x200;
len -= 0x200;
}
}
encode_page((uint8_t *)buff_ptr, (uint8_t *)buff_ptr, len);
}
return buff;
}
static void usage(void)
{
printf("Usage: rkboottool [options] Rock27Boot.bin\n");
printf("-h|--help This help message\n");
printf("-e|--extract Extract binary images from Rock27Boot.bin file\n");
printf("-d|--descramble Descramble extracted binary images\n");
printf("-i|--info Print info about Rock27Boot.bin file\n");
printf("\n");
printf("Usually you would like to use -d -e together to obtain raw binary\n");
printf("(out files rkboot_s1.bin, rkboot_s2.bin, rkboot_s3.bin, rkboot_s4.bin)\n");
}
int main (int argc, char **argv)
{
struct rkboot_info_t rkboot_info;
FILE *fp_in, *fp_out;
int32_t i = 0, action = NONE;
int32_t ret;
void *buff;
char *in_filename = NULL;
if ( argc < 2 )
{
usage();
return -1;
}
/* print banner */
fprintf(stderr,"rkboottool " VERSION "\n");
fprintf(stderr,"(C) Marcin Bukat 2011\n");
fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n");
fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
/* arguments handling */
while (i < argc)
{
if ((strcmp(argv[i],"-i")==0) || (strcmp(argv[i],"--info")==0))
{
action |= INFO;
}
else if ((strcmp(argv[i],"-e")==0) || (strcmp(argv[i],"--extract")==0))
{
action |= EXTRACT;
}
else if ((strcmp(argv[i],"-d")==0) || (strcmp(argv[i],"--descramble")==0))
{
action |= SCRAMBLE;
}
else if ((strcmp(argv[i],"-h")==0) || (strcmp(argv[i],"--help")==0))
{
usage();
return 0;
}
else if ( argv[i][0] != '-' )
{
/* file argument */
in_filename = argv[i];
}
i++;
}
if ( (fp_in = fopen(in_filename, "rb")) == NULL )
{
fprintf(stderr, "error: can't open %s file for reading\n", in_filename);
return -1;
}
ret = fread(&rkboot_info, 1, sizeof(rkboot_info), fp_in);
if (ret != sizeof(rkboot_info))
{
fclose(fp_in);
fprintf(stderr, "error: can't read %s file header\n", in_filename);
fprintf(stderr, "read %d, expected %d\n", ret, sizeof(rkboot_info));
return -2;
}
if (action & INFO)
{
printf("file: %s\n", in_filename);
printf("signature: %s\n", rkboot_info.sign);
printf("check bytes: ");
for (i = 0; i < 16; i++)
printf("0x%0x ", rkboot_info.check_values[i]);
printf("\n");
printf("timestamp %d.%d.%d %d:%d:%d\n", rkboot_info.time.day,
rkboot_info.time.month,
rkboot_info.time.year,
rkboot_info.time.hour,
rkboot_info.time.minute,
rkboot_info.time.second);
printf("UI master version: 0x%0x\n", rkboot_info.ui_master_version);
printf("UI slave version: 0x%0x\n", rkboot_info.ui_slave_version);
printf("s1 data offset: 0x%0x\n", rkboot_info.s1_offset);
printf("s1 data len: 0x%0x\n", rkboot_info.s1_len);
printf("s2 offset: 0x%0x\n", rkboot_info.s2_offset);
printf("s2 len: 0x%0x\n", rkboot_info.s2_len);
printf("s3 offset: 0x%0x\n", rkboot_info.s3_offset);
printf("s3 len: 0x%0x\n", rkboot_info.s3_len);
printf("s4 offset: 0x%0x\n", rkboot_info.s4_offset);
printf("s4 len: 0x%0x\n", rkboot_info.s4_len);
printf("UI version flag: 0x%0x\n", rkboot_info.version_flag);
}
if (action & EXTRACT)
{
/* first stage */
buff = binary_extract(fp_in, rkboot_info.s1_offset,
rkboot_info.s1_len,
action & SCRAMBLE,
CONTINOUS_ENC);
if ( buff == NULL )
{
fclose(fp_in);
fprintf(stderr, "error: can't extract image\n");
return -2;
}
/* output */
if ((fp_out = fopen("rkboot_s1.bin", "wb")) == NULL)
{
free(buff);
fclose(fp_in);
fprintf(stderr, "[error]: can't open rkboot_s1.bin for writing\n");
return -3;
}
fwrite(buff, 1, rkboot_info.s1_len, fp_out);
fprintf(stderr, "[info]: extracted rkboot_s1.bin file\n");
free(buff);
fclose(fp_out);
/* second stage */
buff = binary_extract(fp_in, rkboot_info.s2_offset,
rkboot_info.s2_len,
action & SCRAMBLE,
CONTINOUS_ENC);
if ( buff == NULL )
{
fclose(fp_in);
fprintf(stderr, "error: can't extract image\n");
return -2;
}
if ((fp_out = fopen("rkboot_s2.bin", "wb")) == NULL)
{
free(buff);
fclose(fp_in);
fprintf(stderr, "[error]: can't open rkboot_s2.bin for writing\n");
return -4;
}
fwrite(buff, 1, rkboot_info.s2_len, fp_out);
fprintf(stderr, "[info]: extracted rkboot_s2.bin file\n");
free(buff);
fclose(fp_out);
/* third stage */
buff = binary_extract(fp_in, rkboot_info.s3_offset,
rkboot_info.s3_len,
action & SCRAMBLE,
PAGE_ENC);
if ( buff == NULL )
{
fclose(fp_in);
fprintf(stderr, "[error]: can't extract image.\n");
return -2;
}
if ((fp_out = fopen("rkboot_s3.bin", "wb")) == NULL)
{
free(buff);
fclose(fp_in);
fprintf(stderr, "[error]: can't open rkboot_s3.bin for writing\n");
return -4;
}
fwrite(buff, 1, rkboot_info.s3_len, fp_out);
fprintf(stderr, "[info]: extracted rkboot_s3.bin file\n");
free(buff);
fclose(fp_out);
/* forth stage */
buff = binary_extract(fp_in, rkboot_info.s4_offset,
rkboot_info.s4_len,
action & SCRAMBLE,
CONTINOUS_ENC);
if ( buff == NULL )
{
fclose(fp_in);
fprintf(stderr, "[error]: can't extract image\n");
return -2;
}
if ((fp_out = fopen("rkboot_s4.bin", "wb")) == NULL)
{
free(buff);
fclose(fp_in);
fprintf(stderr, "[error]: can't open rkboot_s4.bin for writing\n");
return -4;
}
fwrite(buff, 1, rkboot_info.s4_len, fp_out);
fprintf(stderr, "[info]: extracted rkboot_s4.bin file\n");
free(buff);
fclose(fp_out);
}
fclose(fp_in);
return 0;
}