Marcin Bukat | 8f4202d | 2011-05-30 21:10:43 +0000 | [diff] [blame] | 1 | #include <stdio.h> |
| 2 | #include <stdint.h> |
| 3 | #include <stdbool.h> |
| 4 | #include <stdlib.h> |
| 5 | #include <string.h> |
| 6 | |
| 7 | #define VERSION "v0.3" |
| 8 | |
| 9 | /* time field stucture */ |
| 10 | struct rktime_t |
| 11 | { |
| 12 | uint16_t year; |
| 13 | uint16_t month; |
| 14 | uint16_t day; |
| 15 | uint16_t hour; |
| 16 | uint16_t minute; |
| 17 | uint16_t second; |
| 18 | }; |
| 19 | |
| 20 | /* Rock27Boot.bin header structure */ |
| 21 | struct rkboot_info_t |
| 22 | { |
| 23 | char sign[32]; |
| 24 | uint8_t check_values[16]; |
| 25 | struct rktime_t time; |
| 26 | uint32_t ui_master_version; |
| 27 | uint32_t ui_slave_version; |
| 28 | uint32_t s1_offset; |
| 29 | int32_t s1_len; |
| 30 | uint32_t s2_offset; |
| 31 | int32_t s2_len; |
| 32 | uint32_t s3_offset; |
| 33 | int32_t s3_len; |
| 34 | uint32_t s4_offset; |
| 35 | int32_t s4_len; |
| 36 | uint32_t version_flag; |
| 37 | }; |
| 38 | |
| 39 | /* actions */ |
| 40 | enum { |
| 41 | NONE = 0, |
| 42 | INFO = 1, |
| 43 | EXTRACT = 2, |
| 44 | SCRAMBLE = 4 |
| 45 | }; |
| 46 | |
| 47 | /* scramble mode */ |
| 48 | enum { |
| 49 | CONTINOUS_ENC, /* scramble whole block at once */ |
| 50 | PAGE_ENC /* nand bootloader is scrambled in 0x200 chunks */ |
| 51 | }; |
| 52 | |
| 53 | /* scrambling/descrambling reverse engineered by AleMaxx */ |
| 54 | static void encode_page(uint8_t *inpg, uint8_t *outpg, const int size) |
| 55 | { |
| 56 | |
| 57 | uint8_t key[] = { |
| 58 | 0x7C, 0x4E, 0x03, 0x04, |
| 59 | 0x55, 0x05, 0x09, 0x07, |
| 60 | 0x2D, 0x2C, 0x7B, 0x38, |
| 61 | 0x17, 0x0D, 0x17, 0x11 |
| 62 | }; |
| 63 | int i, i3, x, val, idx; |
| 64 | |
| 65 | uint8_t key1[0x100]; |
| 66 | uint8_t key2[0x100]; |
| 67 | |
| 68 | for (i=0; i<0x100; i++) { |
| 69 | key1[i] = i; |
| 70 | key2[i] = key[i&0xf]; |
| 71 | } |
| 72 | |
| 73 | i3 = 0; |
| 74 | for (i=0; i<0x100; i++) { |
| 75 | x = key1[i]; |
| 76 | i3 = key1[i] + i3; |
| 77 | i3 += key2[i]; |
| 78 | i3 &= 0xff; |
| 79 | key1[i] = key1[i3]; |
| 80 | key1[i3] = x; |
| 81 | } |
| 82 | |
| 83 | idx = 0; |
| 84 | for (i=0; i<size; i++) { |
| 85 | x = key1[(i+1) & 0xff]; |
| 86 | val = x; |
| 87 | idx = (x + idx) & 0xff; |
| 88 | key1[(i+1) & 0xff] = key1[idx]; |
| 89 | key1[idx] = (x & 0xff); |
| 90 | val = (key1[(i+1)&0xff] + x) & 0xff; |
| 91 | val = key1[val]; |
| 92 | outpg[i] = val ^ inpg[i]; |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | static void *binary_extract(FILE *fp, uint32_t offset, uint32_t len, int descramble, int encode_mode) |
| 97 | { |
| 98 | void *buff, *buff_ptr; |
| 99 | uint32_t ret; |
| 100 | |
| 101 | if ((fp == NULL) || len == 0) |
| 102 | return NULL; |
| 103 | |
| 104 | /* allocate buff */ |
| 105 | if ((buff = malloc(len)) == NULL) |
| 106 | return NULL; |
| 107 | |
| 108 | /* seek to the begining of the data */ |
| 109 | fseek(fp, offset, SEEK_SET); |
| 110 | |
| 111 | /* read into the buffer */ |
| 112 | ret = fread(buff, 1, len, fp); |
| 113 | |
| 114 | if (ret != len) |
| 115 | { |
| 116 | free(buff); |
| 117 | return NULL; |
| 118 | } |
| 119 | |
| 120 | /* descramble */ |
| 121 | if ( descramble ) |
| 122 | { |
| 123 | buff_ptr = buff; |
| 124 | if (encode_mode == PAGE_ENC) |
| 125 | { |
| 126 | while (len >= 0x200) |
| 127 | { |
| 128 | encode_page((uint8_t *)buff_ptr, |
| 129 | (uint8_t *)buff_ptr, |
| 130 | 0x200); |
| 131 | |
| 132 | buff_ptr += 0x200; |
| 133 | len -= 0x200; |
| 134 | } |
| 135 | } |
| 136 | encode_page((uint8_t *)buff_ptr, (uint8_t *)buff_ptr, len); |
| 137 | } |
| 138 | |
| 139 | return buff; |
| 140 | } |
| 141 | |
| 142 | static void usage(void) |
| 143 | { |
| 144 | printf("Usage: rkboottool [options] Rock27Boot.bin\n"); |
| 145 | printf("-h|--help This help message\n"); |
| 146 | printf("-e|--extract Extract binary images from Rock27Boot.bin file\n"); |
| 147 | printf("-d|--descramble Descramble extracted binary images\n"); |
| 148 | printf("-i|--info Print info about Rock27Boot.bin file\n"); |
| 149 | printf("\n"); |
| 150 | printf("Usually you would like to use -d -e together to obtain raw binary\n"); |
| 151 | printf("(out files rkboot_s1.bin, rkboot_s2.bin, rkboot_s3.bin, rkboot_s4.bin)\n"); |
| 152 | } |
| 153 | |
| 154 | int main (int argc, char **argv) |
| 155 | { |
| 156 | struct rkboot_info_t rkboot_info; |
| 157 | FILE *fp_in, *fp_out; |
| 158 | int32_t i = 0, action = NONE; |
| 159 | int32_t ret; |
| 160 | void *buff; |
| 161 | char *in_filename = NULL; |
| 162 | |
| 163 | if ( argc < 2 ) |
| 164 | { |
| 165 | usage(); |
| 166 | return -1; |
| 167 | } |
| 168 | |
| 169 | /* print banner */ |
| 170 | fprintf(stderr,"rkboottool " VERSION "\n"); |
| 171 | fprintf(stderr,"(C) Marcin Bukat 2011\n"); |
| 172 | fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n"); |
| 173 | fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"); |
| 174 | |
| 175 | /* arguments handling */ |
| 176 | while (i < argc) |
| 177 | { |
| 178 | if ((strcmp(argv[i],"-i")==0) || (strcmp(argv[i],"--info")==0)) |
| 179 | { |
| 180 | action |= INFO; |
| 181 | } |
| 182 | else if ((strcmp(argv[i],"-e")==0) || (strcmp(argv[i],"--extract")==0)) |
| 183 | { |
| 184 | action |= EXTRACT; |
| 185 | } |
| 186 | else if ((strcmp(argv[i],"-d")==0) || (strcmp(argv[i],"--descramble")==0)) |
| 187 | { |
| 188 | action |= SCRAMBLE; |
| 189 | } |
| 190 | else if ((strcmp(argv[i],"-h")==0) || (strcmp(argv[i],"--help")==0)) |
| 191 | { |
| 192 | usage(); |
| 193 | return 0; |
| 194 | } |
| 195 | else if ( argv[i][0] != '-' ) |
| 196 | { |
| 197 | /* file argument */ |
| 198 | in_filename = argv[i]; |
| 199 | } |
| 200 | i++; |
| 201 | } |
| 202 | |
| 203 | if ( (fp_in = fopen(in_filename, "rb")) == NULL ) |
| 204 | { |
| 205 | fprintf(stderr, "error: can't open %s file for reading\n", in_filename); |
| 206 | return -1; |
| 207 | } |
| 208 | |
| 209 | ret = fread(&rkboot_info, 1, sizeof(rkboot_info), fp_in); |
| 210 | |
| 211 | if (ret != sizeof(rkboot_info)) |
| 212 | { |
| 213 | fclose(fp_in); |
| 214 | fprintf(stderr, "error: can't read %s file header\n", in_filename); |
| 215 | fprintf(stderr, "read %d, expected %d\n", ret, sizeof(rkboot_info)); |
| 216 | return -2; |
| 217 | } |
| 218 | |
| 219 | if (action & INFO) |
| 220 | { |
| 221 | printf("file: %s\n", in_filename); |
| 222 | printf("signature: %s\n", rkboot_info.sign); |
| 223 | printf("check bytes: "); |
| 224 | for (i = 0; i < 16; i++) |
| 225 | printf("0x%0x ", rkboot_info.check_values[i]); |
| 226 | |
| 227 | printf("\n"); |
| 228 | printf("timestamp %d.%d.%d %d:%d:%d\n", rkboot_info.time.day, |
| 229 | rkboot_info.time.month, |
| 230 | rkboot_info.time.year, |
| 231 | rkboot_info.time.hour, |
| 232 | rkboot_info.time.minute, |
| 233 | rkboot_info.time.second); |
| 234 | printf("UI master version: 0x%0x\n", rkboot_info.ui_master_version); |
| 235 | printf("UI slave version: 0x%0x\n", rkboot_info.ui_slave_version); |
| 236 | printf("s1 data offset: 0x%0x\n", rkboot_info.s1_offset); |
| 237 | printf("s1 data len: 0x%0x\n", rkboot_info.s1_len); |
| 238 | printf("s2 offset: 0x%0x\n", rkboot_info.s2_offset); |
| 239 | printf("s2 len: 0x%0x\n", rkboot_info.s2_len); |
| 240 | printf("s3 offset: 0x%0x\n", rkboot_info.s3_offset); |
| 241 | printf("s3 len: 0x%0x\n", rkboot_info.s3_len); |
| 242 | printf("s4 offset: 0x%0x\n", rkboot_info.s4_offset); |
| 243 | printf("s4 len: 0x%0x\n", rkboot_info.s4_len); |
| 244 | printf("UI version flag: 0x%0x\n", rkboot_info.version_flag); |
| 245 | } |
| 246 | |
| 247 | if (action & EXTRACT) |
| 248 | { |
| 249 | /* first stage */ |
| 250 | buff = binary_extract(fp_in, rkboot_info.s1_offset, |
| 251 | rkboot_info.s1_len, |
| 252 | action & SCRAMBLE, |
| 253 | CONTINOUS_ENC); |
| 254 | |
| 255 | if ( buff == NULL ) |
| 256 | { |
| 257 | fclose(fp_in); |
| 258 | fprintf(stderr, "error: can't extract image\n"); |
| 259 | return -2; |
| 260 | } |
| 261 | |
| 262 | /* output */ |
| 263 | if ((fp_out = fopen("rkboot_s1.bin", "wb")) == NULL) |
| 264 | { |
| 265 | free(buff); |
| 266 | fclose(fp_in); |
| 267 | fprintf(stderr, "[error]: can't open rkboot_s1.bin for writing\n"); |
| 268 | return -3; |
| 269 | } |
| 270 | |
| 271 | fwrite(buff, 1, rkboot_info.s1_len, fp_out); |
| 272 | |
| 273 | fprintf(stderr, "[info]: extracted rkboot_s1.bin file\n"); |
| 274 | free(buff); |
| 275 | fclose(fp_out); |
| 276 | |
| 277 | /* second stage */ |
| 278 | buff = binary_extract(fp_in, rkboot_info.s2_offset, |
| 279 | rkboot_info.s2_len, |
| 280 | action & SCRAMBLE, |
| 281 | CONTINOUS_ENC); |
| 282 | |
| 283 | if ( buff == NULL ) |
| 284 | { |
| 285 | fclose(fp_in); |
| 286 | fprintf(stderr, "error: can't extract image\n"); |
| 287 | return -2; |
| 288 | } |
| 289 | |
| 290 | if ((fp_out = fopen("rkboot_s2.bin", "wb")) == NULL) |
| 291 | { |
| 292 | free(buff); |
| 293 | fclose(fp_in); |
| 294 | fprintf(stderr, "[error]: can't open rkboot_s2.bin for writing\n"); |
| 295 | return -4; |
| 296 | } |
| 297 | |
| 298 | fwrite(buff, 1, rkboot_info.s2_len, fp_out); |
| 299 | |
| 300 | fprintf(stderr, "[info]: extracted rkboot_s2.bin file\n"); |
| 301 | free(buff); |
| 302 | fclose(fp_out); |
| 303 | |
| 304 | /* third stage */ |
| 305 | buff = binary_extract(fp_in, rkboot_info.s3_offset, |
| 306 | rkboot_info.s3_len, |
| 307 | action & SCRAMBLE, |
| 308 | PAGE_ENC); |
| 309 | if ( buff == NULL ) |
| 310 | { |
| 311 | fclose(fp_in); |
| 312 | fprintf(stderr, "[error]: can't extract image.\n"); |
| 313 | return -2; |
| 314 | } |
| 315 | |
| 316 | if ((fp_out = fopen("rkboot_s3.bin", "wb")) == NULL) |
| 317 | { |
| 318 | free(buff); |
| 319 | fclose(fp_in); |
| 320 | fprintf(stderr, "[error]: can't open rkboot_s3.bin for writing\n"); |
| 321 | return -4; |
| 322 | } |
| 323 | |
| 324 | fwrite(buff, 1, rkboot_info.s3_len, fp_out); |
| 325 | |
| 326 | fprintf(stderr, "[info]: extracted rkboot_s3.bin file\n"); |
| 327 | free(buff); |
| 328 | fclose(fp_out); |
| 329 | |
| 330 | /* forth stage */ |
| 331 | buff = binary_extract(fp_in, rkboot_info.s4_offset, |
| 332 | rkboot_info.s4_len, |
| 333 | action & SCRAMBLE, |
| 334 | CONTINOUS_ENC); |
| 335 | if ( buff == NULL ) |
| 336 | { |
| 337 | fclose(fp_in); |
| 338 | fprintf(stderr, "[error]: can't extract image\n"); |
| 339 | return -2; |
| 340 | } |
| 341 | |
| 342 | if ((fp_out = fopen("rkboot_s4.bin", "wb")) == NULL) |
| 343 | { |
| 344 | free(buff); |
| 345 | fclose(fp_in); |
| 346 | fprintf(stderr, "[error]: can't open rkboot_s4.bin for writing\n"); |
| 347 | return -4; |
| 348 | } |
| 349 | |
| 350 | fwrite(buff, 1, rkboot_info.s4_len, fp_out); |
| 351 | |
| 352 | fprintf(stderr, "[info]: extracted rkboot_s4.bin file\n"); |
| 353 | free(buff); |
| 354 | fclose(fp_out); |
| 355 | } |
| 356 | |
| 357 | fclose(fp_in); |
| 358 | return 0; |
| 359 | } |
| 360 | |