diff options
Diffstat (limited to 'utils/rk27utils/rkboottool')
-rw-r--r-- | utils/rk27utils/rkboottool/Makefile | 7 | ||||
-rw-r--r-- | utils/rk27utils/rkboottool/rkboottool.c | 360 |
2 files changed, 367 insertions, 0 deletions
diff --git a/utils/rk27utils/rkboottool/Makefile b/utils/rk27utils/rkboottool/Makefile new file mode 100644 index 0000000000..895dfc87cc --- /dev/null +++ b/utils/rk27utils/rkboottool/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | all: rkboottool | ||
2 | |||
3 | rkboottool: rkboottool.c | ||
4 | gcc -g -std=c99 -o $@ -W -Wall $^ | ||
5 | |||
6 | clean: | ||
7 | rm -fr rkboottool | ||
diff --git a/utils/rk27utils/rkboottool/rkboottool.c b/utils/rk27utils/rkboottool/rkboottool.c new file mode 100644 index 0000000000..ad08b0b5f6 --- /dev/null +++ b/utils/rk27utils/rkboottool/rkboottool.c | |||
@@ -0,0 +1,360 @@ | |||
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 | |||