-
Notifications
You must be signed in to change notification settings - Fork 24
/
loader.c
349 lines (316 loc) · 9.2 KB
/
loader.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
#include <loader.h>
struct idblock0_t {
uint32_t signature;
uint8_t reserved0[4];
uint32_t disable_rc4;
uint16_t bootcode1_offset;
uint16_t bootcode2_offset;
uint8_t reserved1[490];
uint16_t flash_data_size;
uint16_t flash_boot_size;
uint16_t crc;
};
struct idblock1_t {
uint16_t sys_reserved_block;
uint16_t disk0_size;
uint16_t disk1_size;
uint16_t disk2_size;
uint16_t disk3_size;
uint32_t chip_tag;
uint32_t machine_id;
uint16_t loader_year;
uint16_t loader_date;
uint16_t loader_ver;
uint8_t reserved0[72];
uint16_t flash_data_offset;
uint16_t flash_data_len;
uint8_t reserved1[384];
uint32_t flash_chip_size;
uint8_t reserved2;
uint8_t access_time;
uint16_t phy_block_size;
uint8_t phy_page_size;
uint8_t ecc_bits;
uint8_t reserved3[8];
uint16_t id_block0;
uint16_t id_block1;
uint16_t id_block2;
uint16_t id_block3;
uint16_t id_block4;
};
struct idblock2_t {
uint16_t chip_info_size;
uint8_t chip_info[16];
uint8_t reserved[473];
uint8_t sz_vc_tag[3];
uint16_t sec0_crc;
uint16_t sec1_crc;
uint32_t boot_code_crc;
uint16_t sec3_custom_data_offset;
uint16_t sec3_custom_data_size;
uint8_t sz_crc_tag[4];
uint16_t sec3_crc;
};
struct idblock3_t {
uint16_t sn_size;
uint8_t sn[60];
uint8_t reserved[382];
uint8_t wifi_size;
uint8_t wifi_addr[6];
uint8_t imei_size;
uint8_t imei[15];
uint8_t uid_size;
uint8_t uid[30];
uint8_t bluetooth_size;
uint8_t bluetooth_addr[6];
uint8_t mac_size;
uint8_t mac_addr[6];
};
static inline uint32_t loader_align_size(uint32_t len)
{
uint32_t t = (len - 1) / 512 + 1;
return ((t - 1) / 4 + 1) * 2048;
}
static void idb_rc4(char * buf, int len)
{
struct rc4_ctx_t ctx;
uint8_t key[16] = { 124, 78, 3, 4, 85, 5, 9, 7, 45, 44, 123, 56, 23, 13, 23, 17 };
rc4_setkey(&ctx, key, sizeof(key));
rc4_crypt(&ctx, (uint8_t *)buf, len);
}
static void rkloader_ctx_mkidb(struct rkloader_ctx_t * ctx)
{
if(ctx->is_newidb)
{
ctx->idblen = 0;
for(int i = 0; i < ctx->nentry; i++)
{
struct rkloader_entry_t * e = ctx->entry[i];
if(e->type == RKLOADER_ENTRY_LOADER)
ctx->idblen += loader_align_size(get_unaligned_le32(&e->data_size));
}
if(ctx->idblen > 0)
{
ctx->idbbuf = calloc(1, ctx->idblen);
if(ctx->idbbuf)
{
int flash_head_index = 0;
uint32_t idblen = 0;
for(flash_head_index = 0; flash_head_index < ctx->nentry; flash_head_index++)
{
struct rkloader_entry_t * e = ctx->entry[flash_head_index];
if(e->type == RKLOADER_ENTRY_LOADER)
{
char str[256];
loader_wide2str(str, (uint8_t *)&e->name[0], sizeof(e->name));
if(strcmp(str, "FlashHead") == 0)
{
uint32_t len = loader_align_size(get_unaligned_le32(&e->data_size));
memset((char *)ctx->idbbuf + idblen, 0, len);
memcpy((char *)ctx->idbbuf + idblen, (char *)ctx->buffer + get_unaligned_le32(&e->data_offset), get_unaligned_le32(&e->data_size));
if(!ctx->is_rc4on)
{
for(int i = 0; i < (len / 512); i++)
idb_rc4((char *)ctx->idbbuf + idblen + 512 * i, 512);
}
idblen += len;
break;
}
}
}
for(int idx = 0; idx < ctx->nentry; idx++)
{
struct rkloader_entry_t * e = ctx->entry[idx];
if((e->type == RKLOADER_ENTRY_LOADER) && (idx != flash_head_index))
{
uint32_t len = loader_align_size(get_unaligned_le32(&e->data_size));
memset((char *)ctx->idbbuf + idblen, 0, len);
memcpy((char *)ctx->idbbuf + idblen, (char *)ctx->buffer + get_unaligned_le32(&e->data_offset), get_unaligned_le32(&e->data_size));
if(!ctx->is_rc4on)
{
for(int i = 0; i < (len / 512); i++)
idb_rc4((char *)ctx->idbbuf + idblen + 512 * i, 512);
}
idblen += len;
}
}
}
}
}
else
{
ctx->idblen = 0;
for(int i = 0; i < ctx->nentry; i++)
{
struct rkloader_entry_t * e = ctx->entry[i];
if(e->type == RKLOADER_ENTRY_LOADER)
{
char str[256];
loader_wide2str(str, (uint8_t *)&e->name[0], sizeof(e->name));
if((strcmp(str, "FlashBoot") == 0) || (strcmp(str, "FlashData") == 0))
ctx->idblen += loader_align_size(get_unaligned_le32(&e->data_size));
}
}
if(ctx->idblen > 0)
{
ctx->idblen += sizeof(struct idblock0_t) + sizeof(struct idblock1_t) + sizeof(struct idblock2_t) + sizeof(struct idblock3_t);
ctx->idbbuf = calloc(1, ctx->idblen);
if(ctx->idbbuf)
{
struct rkloader_entry_t * flash_data = NULL;
struct rkloader_entry_t * flash_boot = NULL;
uint32_t idblen = 0;
uint32_t len;
for(int i = 0; i < ctx->nentry; i++)
{
struct rkloader_entry_t * e = ctx->entry[i];
if(e->type == RKLOADER_ENTRY_LOADER)
{
char str[256];
loader_wide2str(str, (uint8_t *)&e->name[0], sizeof(e->name));
if(strcmp(str, "FlashData") == 0)
flash_data = e;
else if(strcmp(str, "FlashBoot") == 0)
flash_boot = e;
}
}
struct idblock0_t * idb0 = (struct idblock0_t *)((char *)ctx->idbbuf + idblen);
idb0->signature = 0x0ff0aa55;
idb0->disable_rc4 = ctx->is_rc4on ? 0 : 1;
idb0->bootcode1_offset = 4;
idb0->bootcode2_offset = 4;
idb0->flash_data_size = loader_align_size(get_unaligned_le32(&flash_data->data_size)) / 512;
idb0->flash_boot_size = loader_align_size(get_unaligned_le32(&flash_data->data_size)) / 512 + loader_align_size(get_unaligned_le32(&flash_boot->data_size)) / 512;
idblen += 512;
struct idblock1_t * idb1 = (struct idblock1_t *)((char *)ctx->idbbuf + idblen);
idb1->sys_reserved_block = 0xc;
idb1->disk0_size = 0xffff;
idb1->chip_tag = 0x38324b52;
idblen += 512;
struct idblock2_t * idb2 = (struct idblock2_t *)((char *)ctx->idbbuf + idblen);
strcpy((char *)idb2->sz_vc_tag, "VC");
strcpy((char *)idb2->sz_crc_tag, "CRC");
idblen += 512;
struct idblock3_t * idb3 = (struct idblock3_t *)((char *)ctx->idbbuf + idblen);
memset(idb3, 0, sizeof(struct idblock3_t));
idblen += 512;
len = loader_align_size(get_unaligned_le32(&flash_data->data_size));
memset((char *)ctx->idbbuf + idblen, 0, len);
memcpy((char *)ctx->idbbuf + idblen, (char *)ctx->buffer + get_unaligned_le32(&flash_data->data_offset), get_unaligned_le32(&flash_data->data_size));
if(idb0->disable_rc4)
{
for(int i = 0; i < (len / 512); i++)
idb_rc4((char *)ctx->idbbuf + idblen + 512 * i, 512);
}
idblen += len;
len = loader_align_size(get_unaligned_le32(&flash_boot->data_size));
memset((char *)ctx->idbbuf + idblen, 0, len);
memcpy((char *)ctx->idbbuf + idblen, (char *)ctx->buffer + get_unaligned_le32(&flash_boot->data_offset), get_unaligned_le32(&flash_boot->data_size));
if(idb0->disable_rc4)
{
for(int i = 0; i < (len / 512); i++)
idb_rc4((char *)ctx->idbbuf + idblen + 512 * i, 512);
}
idblen += len;
idb2->sec0_crc = crc16_sum(0xffff, (const uint8_t *)idb0, 512);
idb2->sec1_crc = crc16_sum(0xffff, (const uint8_t *)idb1, 512);
idb2->sec3_crc = crc16_sum(0xffff, (const uint8_t *)idb3, 512);
idb_rc4((char *)idb0, sizeof(struct idblock0_t));
idb_rc4((char *)idb2, sizeof(struct idblock2_t));
idb_rc4((char *)idb3, sizeof(struct idblock3_t));
}
}
}
}
char * loader_wide2str(char * str, uint8_t * wide, int len)
{
int i;
for(i = 0; i < len; i++)
{
char c = wide[i * 2 + 0] & 0xff;
str[i] = (c && isprint(c)) ? c : '\0';
}
str[i] = '\0';
return str;
}
struct rkloader_ctx_t * rkloader_ctx_alloc(const char * filename)
{
struct rkloader_ctx_t * ctx = calloc(1, sizeof(struct rkloader_ctx_t));
if(!ctx)
return NULL;
ctx->buffer = file_load(filename, &ctx->length);
if(!ctx->buffer || ctx->length <= sizeof(struct rkloader_header_t))
{
if(ctx->buffer)
free(ctx->buffer);
if(ctx)
free(ctx);
return NULL;
}
ctx->header = (struct rkloader_header_t *)ctx->buffer;
if((le32_to_cpu(ctx->header->tag) != 0x544f4f42) && (le32_to_cpu(ctx->header->tag) != 0x2052444c))
{
if(ctx->buffer)
free(ctx->buffer);
if(ctx)
free(ctx);
return NULL;
}
if(le32_to_cpu(ctx->header->tag) == 0x2052444c)
ctx->is_newidb = 1;
else
ctx->is_newidb = 0;
if(ctx->header->rc4_flag)
ctx->is_rc4on = 0;
else
ctx->is_rc4on = 1;
if(ctx->header->sign_flag == 'S')
ctx->is_sign = 1;
else
ctx->is_sign = 0;
ctx->nentry = ctx->header->code471_num + ctx->header->code472_num + ctx->header->loader_num;
if(ctx->nentry <= 0)
{
if(ctx->buffer)
free(ctx->buffer);
if(ctx)
free(ctx);
return NULL;
}
for(int i = 0; i < ctx->nentry; i++)
{
ctx->entry[i] = (struct rkloader_entry_t *)(ctx->buffer + sizeof(struct rkloader_header_t) + sizeof(struct rkloader_entry_t) * i);
}
struct rkloader_entry_t * e = ctx->entry[ctx->nentry - 1];
uint32_t len = get_unaligned_le32(&e->data_offset) + get_unaligned_le32(&e->data_size);
if(ctx->length != len + 4)
{
if(ctx->buffer)
free(ctx->buffer);
if(ctx)
free(ctx);
return NULL;
}
uint32_t crc32 = 0x0;
if(crc32_sum(crc32, (const uint8_t *)ctx->buffer, len) != get_unaligned_le32((char *)ctx->buffer + len))
{
if(ctx->buffer)
free(ctx->buffer);
if(ctx)
free(ctx);
return NULL;
}
rkloader_ctx_mkidb(ctx);
return ctx;
}
void rkloader_ctx_free(struct rkloader_ctx_t * ctx)
{
if(ctx)
{
if(ctx->buffer)
free(ctx->buffer);
if(ctx->idbbuf)
free(ctx->idbbuf);
free(ctx);
}
}