This source file includes following definitions.
- addBufRange
- findRanges
- getBufRangeForIndex
- find_Nth_str
- find_str
- find_next_bytes_range
- find_bytes_all
- find_next_substr_bytes
- find_next_str_bytes_range
- find_next_str_bytes_main_fw
- find_str_bytes_main_fw
- find_next_str_bytes
- find_str_bytes
- isASCIIstring
- adr_get_range
- adr_get_range_type
- ptr2adr
- adr2ptr
- adr2ptr_with_data
- adr_range_type_str
- adr_range_desc_str
- adr_is_var
- adr_is_main_fw_code
- find_u32_adr_range
- find_u32_adr
- fw_u32
- fw_memcmp
- adr_hist_reset
- adr_hist_index
- adr_hist_add
- adr_hist_get
- isARM
- isLDR_PC
- isLDR_PC_PC
- isSUBW_PC
- isADDW_PC
- isADD_PC
- isSUB_PC
- isRETx
- isPUSH_LR
- isPOP_LR
- isPOP_PC
- isADDx_imm
- isSUBx_imm
- isADRx
- LDR_PC2valptr_thumb
- LDR_PC2valptr_arm
- LDR_PC2valptr
- LDR_PC2adr
- ADRx2adr
- ADR2adr
- ADR2valptr
- LDR_PC2val
- LDR_PC_PC_target
- B_target
- CBx_target
- BLXimm_target
- BL_target
- B_BL_target
- B_BL_BLXimm_target
- BX_PC_target
- get_TBx_PC_info
- disasm_iter_new
- disasm_iter_free
- disasm_iter_set
- disasm_iter_init
- disasm_iter
- disasm_iter_redo
- fw_disasm_iter_start
- fw_disasm_iter
- fw_disasm_iter_single
- fw_disasm_adr
- fw_search_insn
- search_disasm_const_ref
- search_disasm_str_ref
- search_disasm_calls
- search_calls_multi_end
- search_disasm_calls_multi
- search_disasm_calls_veneer_multi
- get_call_const_args
- get_direct_jump_target
- get_branch_call_insn_target
- find_and_get_var_ldr
- find_const_ref_call
- check_simple_func
- find_last_call_from_func
- insn_match_seq
- reg_in_range
- insn_match
- insn_match_any
- insn_match_find_next
- insn_match_find_nth
- insn_match_find_next_seq
- fw_search_bytes
- fw_add_adr_range
- find_dryos_vers
- firmware_load
- do_blx_check
- firmware_init_capstone
- find_startup_copy
- find_exception_vec
- firmware_init_data_ranges
- firmware_unload
1 #include <inttypes.h>
2 #include <stdio.h>
3 #include <stdint.h>
4 #include <string.h>
5
6 #include <capstone.h>
7
8 #include "stubs_load.h"
9 #include "firmware_load_ng.h"
10
11
12
13 static void addBufRange(firmware *fw, int o, int l)
14 {
15 BufRange *n = malloc(sizeof(BufRange));
16 n->p = fw->buf32 + o;
17 n->off = o;
18 n->len = l;
19 n->next = 0;
20 if (fw->br == 0)
21 {
22 fw->br = n;
23 }
24 else
25 {
26 fw->last->next = n;
27 }
28 fw->last = n;
29 }
30
31
32 static void findRanges(firmware *fw)
33 {
34 int i, j, k;
35
36
37 fw->br = 0; fw->last = 0;
38 k = -1; j = 0;
39 for (i = 0; i < fw->size32; i++)
40 {
41 if (fw->buf32[i] == 0xFFFFFFFF)
42 {
43 if (k == -1)
44 {
45 k = i;
46 }
47 }
48 else
49 {
50 if (k != -1)
51 {
52 if (i - k > 32)
53 {
54 if (k - j > 8)
55 {
56
57 addBufRange(fw,j,k - j);
58 }
59 j = i;
60 }
61 k = -1;
62 }
63 }
64 }
65
66 if (k != -1)
67 {
68 if (k - j > 8)
69 {
70 addBufRange(fw,j,k - j);
71 }
72 }
73 else
74 {
75 if (i - j > 8)
76 {
77 addBufRange(fw,j,i - j);
78 }
79 }
80 }
81
82
83 BufRange *getBufRangeForIndex(firmware *fw,int i)
84 {
85 BufRange *br = fw->br;
86 while (br) {
87 if(i >= br->off && i < br->off + br->len) {
88 return br;
89 }
90 br = br->next;
91 }
92 return NULL;
93 }
94
95
96
97
98
99 int find_Nth_str(firmware *fw, char *str, int N)
100 {
101 int nlen = strlen(str);
102 uint32_t nm0 = *((uint32_t*)str);
103 uint32_t *p;
104 int j;
105
106 BufRange *br = fw->br;
107 while (br)
108 {
109 for (p = br->p, j = 0; j < br->len - nlen/4; j++, p++)
110 {
111 if ((nm0 == *p) && ((nlen<=4) || (memcmp(p+1,str+4,nlen-4) == 0)) )
112 {
113 if (--N == 0)
114 return j+br->off;
115 }
116 }
117 br = br->next;
118 }
119
120 return -1;
121 }
122
123 int find_str(firmware *fw, char *str)
124 {
125 return find_Nth_str(fw, str, 1);
126 }
127
128
129
130
131
132 uint32_t find_next_bytes_range(firmware *fw, const void *bytes, size_t len, uint32_t start_adr, uint32_t max_adr)
133 {
134 if(!start_adr) {
135 start_adr = fw->base;
136 }
137 if(start_adr < fw->base || start_adr >= fw->base + fw->size8) {
138 fprintf(stderr,"find_next_bytes_range invalid start_adr 0x%08x\n",start_adr);
139 return 0;
140 }
141 if(!max_adr) {
142 max_adr = fw->base + fw->size8-1;
143 }
144 if(max_adr < fw->base || max_adr >= fw->base + fw->size8) {
145 fprintf(stderr,"find_next_bytes_range invalid max_adr 0x%08x\n",max_adr);
146 return 0;
147 }
148 int end_k = (max_adr - fw->base);
149 BufRange *p = getBufRangeForIndex(fw,(start_adr - fw->base)/4);
150 if(!p) {
151 return 0;
152 }
153 int k = start_adr - fw->base;
154
155 while (k < end_k)
156 {
157 for (; k < (p->off + p->len)*4; k++)
158 {
159 if (memcmp(fw->buf8+k,bytes,len) == 0) {
160 return fw->base+k;
161 }
162 }
163 p = p->next;
164 if(!p) {
165 break;
166 }
167 k = p->off*4;
168 }
169 return 0;
170 }
171
172
173
174 int find_bytes_all(firmware *fw, const void *bytes, size_t len, uint32_t adr, uint32_t *result, int max)
175 {
176 int i;
177 for(i=0,adr=find_next_bytes_range(fw,bytes,len,0,0); adr && (i < max); adr=find_next_bytes_range(fw,bytes,len,adr+len,0),i++) {
178 result[i] = adr;
179 }
180 return i;
181 }
182
183 uint32_t find_next_substr_bytes(firmware *fw, const char *str, uint32_t adr)
184 {
185
186
187 return find_next_bytes_range(fw,str,strlen(str),adr,0);
188 }
189
190 uint32_t find_next_str_bytes_range(firmware *fw, const char *str, uint32_t adr,uint32_t max_adr)
191 {
192
193 return find_next_bytes_range(fw,str,strlen(str)+1,adr,max_adr);
194 }
195
196 uint32_t find_next_str_bytes_main_fw(firmware *fw, const char *str, uint32_t adr)
197 {
198
199
200 uint32_t max_adr;
201 if(fw->base + fw->size8 - 4096 > fw->rom_code_search_max_adr) {
202 max_adr = fw->rom_code_search_max_adr + 4096;
203 } else {
204 max_adr = fw->base + fw->size8;
205 }
206 return find_next_bytes_range(fw,str,strlen(str)+1,adr,max_adr);
207 }
208
209
210 uint32_t find_str_bytes_main_fw(firmware *fw, const char *str)
211 {
212 return find_next_str_bytes_main_fw(fw,str,fw->rom_code_search_min_adr);
213 }
214
215 uint32_t find_next_str_bytes(firmware *fw, const char *str, uint32_t adr)
216 {
217
218 return find_next_bytes_range(fw,str,strlen(str)+1,adr,0);
219 }
220
221
222
223 uint32_t find_str_bytes(firmware *fw, const char *str)
224 {
225 return find_next_str_bytes(fw,str,fw->base);
226 }
227
228 int isASCIIstring(firmware *fw, uint32_t adr)
229 {
230 unsigned char *p = (unsigned char*)adr2ptr_with_data(fw, adr);
231 if(!p) {
232 return 0;
233 }
234
235 int i;
236 for (i = 0; (i < 100) && (p[i] != 0); i++)
237 {
238 if (!((p[i] == '\r') || (p[i] == '\n') || (p[i] == '\t') || ((p[i] >= 0x20) && (p[i] <= 0x7f))))
239 {
240 return 0;
241 }
242 }
243 if ((i >= 2) && (p[i] == 0))
244 return 1;
245 return 0;
246 }
247
248
249 adr_range_t *adr_get_range(firmware *fw, uint32_t adr)
250 {
251 int i;
252 adr_range_t *r=fw->adr_ranges;
253 for(i=0;i<fw->adr_range_count;i++) {
254 if(adr >= r->start && adr < r->start + r->bytes) {
255 return r;
256 }
257 r++;
258 }
259 return NULL;
260 }
261
262
263 int adr_get_range_type(firmware *fw, uint32_t adr)
264 {
265 adr_range_t *r=adr_get_range(fw,adr);
266 if(!r) {
267 return ADR_RANGE_INVALID;
268 }
269 return r->type;
270 }
271
272 uint32_t ptr2adr(firmware *fw, uint8_t *ptr)
273 {
274
275 return (ptr-fw->buf8)+fw->base;
276 }
277
278 uint8_t* adr2ptr(firmware *fw, uint32_t adr)
279 {
280 adr_range_t *r=adr_get_range(fw,adr);
281 if(!r) {
282 return NULL;
283 }
284 switch(r->type) {
285 case ADR_RANGE_RAM_CODE:
286 case ADR_RANGE_ROM:
287 return (r->buf)+(adr - r->start);
288 default:
289 return NULL;
290 }
291 }
292
293 uint8_t* adr2ptr_with_data(firmware *fw, uint32_t adr)
294 {
295 adr_range_t *r=adr_get_range(fw,adr);
296 if(!r) {
297 return NULL;
298 }
299 switch(r->type) {
300 case ADR_RANGE_RAM_CODE:
301 case ADR_RANGE_INIT_DATA:
302 case ADR_RANGE_ROM:
303 return (r->buf)+(adr - r->start);
304 default:
305 return NULL;
306 }
307 }
308
309
310 const char* adr_range_type_str(int type)
311 {
312 switch(type) {
313 case ADR_RANGE_INVALID:
314 return "(invalid)";
315 case ADR_RANGE_ROM:
316 return "ROM";
317 case ADR_RANGE_RAM_CODE:
318 return "RAM code";
319 case ADR_RANGE_INIT_DATA:
320 return "RAM data";
321 default:
322 return "(unknown)";
323 }
324 }
325
326
327 const char* adr_range_desc_str(adr_range_t *r)
328 {
329 switch(r->type) {
330 case ADR_RANGE_INVALID:
331 return "(invalid)";
332 case ADR_RANGE_ROM:
333 return "ROM";
334 case ADR_RANGE_RAM_CODE:
335 if(r->flags & ADR_RANGE_FL_EVEC) {
336 return "EVEC";
337 } else if(r->flags & ADR_RANGE_FL_TCM) {
338 return "TCM code";
339 }
340 return "RAM code";
341 case ADR_RANGE_INIT_DATA:
342 return "RAM data";
343 default:
344 return "(unknown)";
345 }
346 }
347
348
349 int adr_is_var(firmware *fw, uint32_t adr)
350 {
351 return (adr > fw->data_start && adr < fw->memisostart);
352 }
353
354
355 int adr_is_main_fw_code(firmware *fw, uint32_t adr)
356 {
357 int adr_type = adr_get_range_type(fw,adr);
358 if(adr_type == ADR_RANGE_RAM_CODE) {
359 return 1;
360 }
361 if(adr_type != ADR_RANGE_ROM) {
362 return 0;
363 }
364 if(adr < fw->rom_code_search_min_adr || adr > fw->rom_code_search_max_adr) {
365 return 0;
366 }
367 return 1;
368 }
369
370
371
372
373 uint32_t find_u32_adr_range(firmware *fw, uint32_t val, uint32_t start,uint32_t maxadr)
374 {
375
376 if(start == 0) {
377 start=fw->base;
378 }
379 if(start & 3) {
380 fprintf(stderr,"find_u32_adr unaligned start 0x%08x\n",start);
381 return 0;
382 }
383 uint32_t *p=(uint32_t *)adr2ptr(fw,start);
384 if(!p) {
385 fprintf(stderr,"find_u32_adr bad start 0x%08x\n",start);
386 return 0;
387 }
388 uint32_t *p_end;
389 if(maxadr) {
390 p_end = (uint32_t *)adr2ptr(fw,maxadr);
391 } else {
392 p_end = fw->buf32 + fw->size32 - 1;
393 }
394
395 while(p<=p_end) {
396 if(*p==val) {
397 return ptr2adr(fw,(uint8_t *)p);
398 }
399 p++;
400 }
401 return 0;
402 }
403
404
405 uint32_t find_u32_adr(firmware *fw, uint32_t val, uint32_t start)
406 {
407 return find_u32_adr_range(fw,val,start, fw->base + (fw->size8 -4));
408 }
409
410
411 uint32_t fw_u32(firmware *fw, uint32_t adr)
412 {
413 uint32_t *p=(uint32_t *)adr2ptr(fw,adr);
414 if(!p) {
415 fprintf(stderr,"fw_u32 bad adr 0x%08x\n",adr);
416 return 0;
417 }
418 return *p;
419 }
420
421
422 int fw_memcmp(firmware *fw, uint32_t adr,const void *cmp, size_t n)
423 {
424 uint32_t *p=(uint32_t *)adr2ptr(fw,adr);
425 if(!p) {
426 return 1;
427 }
428 if(n >= fw->size8 - (adr - fw->base)) {
429 return 1;
430 }
431 return memcmp(p,cmp,n);
432 }
433
434
435
436
437 void adr_hist_reset(adr_hist_t *ah)
438 {
439 ah->cur=0;
440 ah->count=0;
441
442
443 }
444
445
446 int adr_hist_index(adr_hist_t *ah, int i)
447 {
448 int r=(ah->cur+i)%ADR_HIST_SIZE;
449 if(r < 0) {
450 return ADR_HIST_SIZE + r;
451 }
452 return r;
453 }
454
455
456 void adr_hist_add(adr_hist_t *ah, uint32_t adr)
457 {
458 ah->cur=adr_hist_index(ah,1);
459 ah->adrs[ah->cur]=adr;
460 if(ah->count < ADR_HIST_SIZE) {
461 ah->count++;
462 }
463 }
464
465
466
467 uint32_t adr_hist_get(adr_hist_t *ah, int i)
468 {
469 if(!ah->count || i > ah->count) {
470 return 0;
471 }
472 return ah->adrs[adr_hist_index(ah,-i)];
473 }
474
475
476
477
478 int isARM(cs_insn *insn)
479 {
480 int i;
481 for(i=0;i<insn->detail->groups_count;i++) {
482 if(insn->detail->groups[i] == ARM_GRP_ARM) {
483 return 1;
484 }
485 }
486 return 0;
487 }
488
489
490
491
492 int isLDR_PC(cs_insn *insn)
493 {
494 return insn->id == ARM_INS_LDR
495 && insn->detail->arm.op_count == 2
496 && insn->detail->arm.operands[0].type == ARM_OP_REG
497 && insn->detail->arm.operands[1].type == ARM_OP_MEM
498 && insn->detail->arm.operands[1].mem.base == ARM_REG_PC;
499
500 }
501
502
503
504
505 int isLDR_PC_PC(cs_insn *insn)
506 {
507 if(!isLDR_PC(insn)) {
508 return 0;
509 }
510 return (insn->detail->arm.operands[0].reg == ARM_REG_PC);
511 }
512
513
514 int isSUBW_PC(cs_insn *insn)
515 {
516 return(insn->id == ARM_INS_SUBW
517 && insn->detail->arm.op_count == 3
518 && insn->detail->arm.operands[0].type == ARM_OP_REG
519 && insn->detail->arm.operands[0].reg != ARM_REG_PC
520 && insn->detail->arm.operands[1].type == ARM_OP_REG
521 && insn->detail->arm.operands[1].reg == ARM_REG_PC
522 && insn->detail->arm.operands[2].type == ARM_OP_IMM);
523 }
524
525
526 int isADDW_PC(cs_insn *insn)
527 {
528 return(insn->id == ARM_INS_ADDW
529 && insn->detail->arm.op_count == 3
530 && insn->detail->arm.operands[0].type == ARM_OP_REG
531 && insn->detail->arm.operands[0].reg != ARM_REG_PC
532 && insn->detail->arm.operands[1].type == ARM_OP_REG
533 && insn->detail->arm.operands[1].reg == ARM_REG_PC
534 && insn->detail->arm.operands[2].type == ARM_OP_IMM);
535 }
536
537
538 int isADD_PC(cs_insn *insn)
539 {
540 return (insn->id == ARM_INS_ADD
541 && insn->detail->arm.op_count == 3
542 && insn->detail->arm.operands[0].reg != ARM_REG_PC
543 && insn->detail->arm.operands[1].type == ARM_OP_REG
544 && insn->detail->arm.operands[1].reg == ARM_REG_PC
545 && insn->detail->arm.operands[2].type == ARM_OP_IMM);
546 }
547
548
549 int isSUB_PC(cs_insn *insn)
550 {
551 return (insn->id == ARM_INS_SUB
552 && insn->detail->arm.op_count == 3
553 && insn->detail->arm.operands[0].reg != ARM_REG_PC
554 && insn->detail->arm.operands[1].type == ARM_OP_REG
555 && insn->detail->arm.operands[1].reg == ARM_REG_PC
556 && insn->detail->arm.operands[2].type == ARM_OP_IMM);
557 }
558
559
560 int isRETx(cs_insn *insn)
561 {
562
563 if(insn->id == ARM_INS_BX
564 && insn->detail->arm.op_count == 1
565 && insn->detail->arm.operands[0].type == ARM_OP_REG
566 && insn->detail->arm.operands[0].reg == ARM_REG_LR) {
567 return 1;
568 }
569
570
571
572
573 if(insn->id == ARM_INS_POP) {
574 int i;
575 for(i=0; i < insn->detail->arm.op_count; i++) {
576 if(insn->detail->arm.operands[i].type == ARM_OP_REG
577 && insn->detail->arm.operands[i].reg == ARM_REG_PC) {
578 return 1;
579 }
580 }
581 }
582
583 if(insn->id == ARM_INS_MOV
584 && insn->detail->arm.operands[0].type == ARM_OP_REG
585 && insn->detail->arm.operands[0].reg == ARM_REG_PC
586 && insn->detail->arm.operands[1].type == ARM_OP_REG
587 && insn->detail->arm.operands[1].reg == ARM_REG_LR) {
588 return 1;
589 }
590 return 0;
591 }
592
593
594 int isPUSH_LR(cs_insn *insn)
595 {
596 if(insn->id != ARM_INS_PUSH) {
597 return 0;
598 }
599 int i;
600 for(i=0; i < insn->detail->arm.op_count; i++) {
601 if(insn->detail->arm.operands[i].type == ARM_OP_REG
602 && insn->detail->arm.operands[i].reg == ARM_REG_LR) {
603 return 1;
604 }
605 }
606 return 0;
607 }
608
609
610 int isPOP_LR(cs_insn *insn)
611 {
612 if(insn->id != ARM_INS_POP) {
613 return 0;
614 }
615 int i;
616 for(i=0; i < insn->detail->arm.op_count; i++) {
617 if(insn->detail->arm.operands[i].type == ARM_OP_REG
618 && insn->detail->arm.operands[i].reg == ARM_REG_LR) {
619 return 1;
620 }
621 }
622 return 0;
623 }
624
625
626 int isPOP_PC(cs_insn *insn)
627 {
628 if(insn->id != ARM_INS_POP) {
629 return 0;
630 }
631 int i;
632 for(i=0; i < insn->detail->arm.op_count; i++) {
633 if(insn->detail->arm.operands[i].type == ARM_OP_REG
634 && insn->detail->arm.operands[i].reg == ARM_REG_PC) {
635 return 1;
636 }
637 }
638 return 0;
639 }
640
641
642 int isADDx_imm(cs_insn *insn)
643 {
644 return ((insn->id == ARM_INS_ADD || insn->id == ARM_INS_ADDW) && insn->detail->arm.operands[1].type == ARM_OP_IMM);
645 }
646
647 int isSUBx_imm(cs_insn *insn)
648 {
649 return (IS_INSN_ID_SUBx(insn->id) && insn->detail->arm.operands[1].type == ARM_OP_IMM);
650 }
651
652
653 int isADRx(cs_insn *insn)
654 {
655 return ((insn->id == ARM_INS_ADR)
656 || isSUBW_PC(insn)
657 || isADDW_PC(insn)
658 || (isARM(insn) && (isADD_PC(insn) || isSUB_PC(insn))));
659 }
660
661
662 uint32_t* LDR_PC2valptr_thumb(firmware *fw, cs_insn *insn)
663 {
664 if(!isLDR_PC(insn)) {
665 return NULL;
666 }
667 uint32_t adr;
668
669
670 adr=(insn->address&~3)+4+insn->detail->arm.operands[1].mem.disp;
671 return (uint32_t *)adr2ptr(fw,adr);
672 }
673
674 uint32_t* LDR_PC2valptr_arm(firmware *fw, cs_insn *insn)
675 {
676 if(!isLDR_PC(insn)) {
677 return NULL;
678 }
679 uint32_t adr;
680
681
682 adr=insn->address+8+insn->detail->arm.operands[1].mem.disp;
683 return (uint32_t *)adr2ptr(fw,adr);
684 }
685
686 uint32_t* LDR_PC2valptr(firmware *fw, cs_insn *insn)
687 {
688 if(isARM(insn)) {
689 return LDR_PC2valptr_arm(fw,insn);
690 } else {
691 return LDR_PC2valptr_thumb(fw,insn);
692 }
693 }
694
695
696 uint32_t LDR_PC2adr(__attribute__ ((unused))firmware *fw, cs_insn *insn)
697 {
698 if(!isLDR_PC(insn)) {
699 return 0;
700 }
701 if(isARM(insn)) {
702 return insn->address+8+insn->detail->arm.operands[1].mem.disp;
703 } else {
704 return (insn->address&~3)+4+insn->detail->arm.operands[1].mem.disp;
705 }
706 }
707
708
709 uint32_t ADRx2adr(__attribute__ ((unused))firmware *fw, cs_insn *insn)
710 {
711 if(insn->id == ARM_INS_ADR) {
712 return (insn->address&~3)+4+insn->detail->arm.operands[1].imm;
713 }
714 if(isSUBW_PC(insn)) {
715 return (insn->address&~3)+4-insn->detail->arm.operands[2].imm;
716 }
717 if(isADDW_PC(insn)) {
718 return (insn->address&~3)+4+insn->detail->arm.operands[2].imm;
719 }
720 if(isARM(insn)) {
721 if(isADD_PC(insn)) {
722 return insn->address+8+insn->detail->arm.operands[2].imm;
723 }
724 if(isSUB_PC(insn)) {
725 return insn->address+8-insn->detail->arm.operands[2].imm;
726 }
727 }
728 return 0;
729 }
730
731
732
733 uint32_t ADR2adr(__attribute__ ((unused))firmware *fw, cs_insn *insn)
734 {
735 if(insn->id != ARM_INS_ADR) {
736 return 0;
737 }
738
739
740
741
742
743
744 return (insn->address&~3)+4+insn->detail->arm.operands[1].imm;
745 }
746
747
748 uint32_t* ADR2valptr(firmware *fw, cs_insn *insn)
749 {
750 uint32_t adr=ADR2adr(fw,insn);
751 return (uint32_t *)adr2ptr(fw,adr);
752 }
753
754
755 uint32_t LDR_PC2val(firmware *fw, cs_insn *insn)
756 {
757 uint32_t *p=LDR_PC2valptr(fw,insn);
758 if(p) {
759 return *p;
760 }
761 return 0;
762 }
763
764
765 uint32_t LDR_PC_PC_target(firmware *fw, cs_insn *insn)
766 {
767 if(!isLDR_PC_PC(insn)) {
768 return 0;
769 }
770 return LDR_PC2val(fw,insn);
771 }
772
773
774 uint32_t B_target(__attribute__ ((unused))firmware *fw, cs_insn *insn)
775 {
776 if(insn->id == ARM_INS_B) {
777 return insn->detail->arm.operands[0].imm;
778 }
779 return 0;
780 }
781
782
783
784 uint32_t CBx_target(__attribute__ ((unused))firmware *fw, cs_insn *insn)
785 {
786 if(insn->id == ARM_INS_CBZ || insn->id == ARM_INS_CBNZ) {
787 return insn->detail->arm.operands[1].imm;
788 }
789 return 0;
790 }
791
792
793 uint32_t BLXimm_target(__attribute__ ((unused))firmware *fw, cs_insn *insn)
794 {
795 if(insn->id == ARM_INS_BLX && insn->detail->arm.operands[0].type == ARM_OP_IMM) {
796 return insn->detail->arm.operands[0].imm;
797 }
798 return 0;
799 }
800
801
802
803 uint32_t BL_target(__attribute__ ((unused))firmware *fw, cs_insn *insn)
804 {
805 if(insn->id == ARM_INS_BL) {
806 return insn->detail->arm.operands[0].imm;
807 }
808 return 0;
809 }
810
811
812 uint32_t B_BL_target(__attribute__ ((unused))firmware *fw, cs_insn *insn)
813 {
814 if(insn->id == ARM_INS_B || insn->id == ARM_INS_BL) {
815 return insn->detail->arm.operands[0].imm;
816 }
817 return 0;
818 }
819
820
821
822 uint32_t B_BL_BLXimm_target(__attribute__ ((unused))firmware *fw, cs_insn *insn)
823 {
824 if(insn->id == ARM_INS_B
825 || insn->id == ARM_INS_BL
826 || (insn->id == ARM_INS_BLX && insn->detail->arm.operands[0].type == ARM_OP_IMM)) {
827 return insn->detail->arm.operands[0].imm;
828 }
829 return 0;
830 }
831
832
833 uint32_t BX_PC_target(__attribute__ ((unused))firmware *fw, cs_insn *insn)
834 {
835 if(insn->id == ARM_INS_BX
836 && insn->detail->arm.operands[0].type == ARM_OP_REG
837 && insn->detail->arm.operands[0].reg == ARM_REG_PC) {
838 if(insn->size == 2) {
839
840
841 if((insn->address & 2) == 2) {
842 return 0;
843 }
844 return (uint32_t)(insn->address) + 4;
845 } else {
846 return (uint32_t)(insn->address) + 8;
847 }
848 }
849 return 0;
850 }
851
852
853
854
855 int get_TBx_PC_info(firmware *fw,iter_state_t *is, tbx_info_t *ti)
856 {
857 if(!(is->insn->id == ARM_INS_TBH || is->insn->id == ARM_INS_TBB) || is->insn->detail->arm.operands[0].mem.base != ARM_REG_PC) {
858 return 0;
859 }
860 ti->start=(uint32_t)is->adr;
861 ti->first_target=0;
862 ti->bytes=(is->insn->id == ARM_INS_TBH)?2:1;
863
864 uint32_t max_adr;
865
866 if(ti->bytes==1) {
867 max_adr=ti->start+(2*255);
868 } else {
869 max_adr=ti->start+(2*65535);
870 }
871 arm_reg i_reg=is->insn->detail->arm.operands[0].mem.index;
872
873
874
875
876 int max_backtrack = 8;
877 if(is->ah.count - 1 < max_backtrack) {
878 max_backtrack = is->ah.count-1;
879 }
880
881 int max_count=0;
882 int found_bhs=0;
883 int i;
884 for(i=1;i<=max_backtrack;i++) {
885 fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i));
886 if(fw->is->insn->id == ARM_INS_B && fw->is->insn->detail->arm.cc == ARM_CC_HS) {
887 found_bhs=1;
888 continue;
889 }
890
891 if(found_bhs && fw->is->insn->id == ARM_INS_CMP) {
892
893 if((arm_reg)fw->is->insn->detail->arm.operands[0].reg == i_reg
894 || fw->is->insn->detail->arm.operands[1].type == ARM_OP_IMM) {
895 max_count = fw->is->insn->detail->arm.operands[1].imm;
896 }
897
898 break;
899 }
900 }
901 if(max_count) {
902 max_adr = ti->start+max_count*ti->bytes;
903
904 }
905 uint32_t adr=ti->start;
906 while(adr < max_adr) {
907 uint8_t *p=adr2ptr(fw,adr);
908 if(!p) {
909 fprintf(stderr,"get_TBx_PC_info: jumptable outside of valid address range at 0x%08x\n",adr);
910 return 0;
911 }
912 uint16_t off;
913 if(ti->bytes==1) {
914 off=(uint16_t)*p;
915 } else {
916 off=*(uint16_t *)p;
917 }
918
919
920
921 if(!off) {
922 break;
923 }
924 uint32_t target = ti->start+2*off;
925
926 if(target <= adr) {
927 fprintf(stderr,"get_TBx_PC_info: jumptable target 0x%08x inside jumptable %d at 0x%08x\n",target,off,adr);
928 break;
929 }
930 if(!ti->first_target || target < ti->first_target) {
931 ti->first_target=target;
932 if(target < max_adr) {
933 max_adr=target;
934 }
935 }
936 adr+=ti->bytes;
937 }
938
939 if(max_count) {
940 ti->count=max_count;
941 } else {
942
943 ti->count=(adr-ti->start)/ti->bytes;
944 }
945 return 1;
946 }
947
948
949
950
951
952 iter_state_t *disasm_iter_new(firmware *fw, uint32_t adr)
953 {
954 iter_state_t *is=(iter_state_t *)malloc(sizeof(iter_state_t));
955
956
957 is->insn=cs_malloc(fw->cs_handle_arm);
958 disasm_iter_init(fw,is,adr);
959 return is;
960 }
961
962
963 void disasm_iter_free(iter_state_t *is)
964 {
965 cs_free(is->insn,1);
966 free(is);
967 return;
968 }
969
970
971
972 int disasm_iter_set(firmware *fw, iter_state_t *is, uint32_t adr)
973 {
974
975 if(ADR_IS_THUMB(adr)) {
976 is->cs_handle=fw->cs_handle_thumb;
977 is->thumb=1;
978 is->insn_min_size=2;
979 adr=ADR_CLEAR_THUMB(adr);
980 } else {
981 is->cs_handle=fw->cs_handle_arm;
982 is->thumb=0;
983 is->insn_min_size=4;
984 if(!ADR_IS_ALIGN4(adr)) {
985 fprintf(stderr,"disasm_iter_set: unaligned ARM address 0x%08x\n",adr);
986 is->code=NULL;
987 is->size=0;
988 is->adr=0;
989 return 0;
990 }
991 }
992 uint8_t *p=adr2ptr(fw,adr);
993 if(!p) {
994
995
996 is->code=NULL;
997 is->size=0;
998 is->adr=0;
999 return 0;
1000 }
1001
1002 is->code=p;
1003 is->size=fw->size8 - (p-fw->buf8);
1004 is->adr=adr;
1005 return 1;
1006 }
1007
1008
1009 int disasm_iter_init(__attribute__ ((unused))firmware *fw, iter_state_t *is, uint32_t adr)
1010 {
1011 adr_hist_reset(&is->ah);
1012 return disasm_iter_set(fw,is,adr);
1013 }
1014
1015
1016
1017
1018 int disasm_iter(__attribute__ ((unused))firmware *fw, iter_state_t *is)
1019 {
1020
1021 if(!is->code) {
1022 return 0;
1023 }
1024 adr_hist_add(&is->ah,(uint32_t)is->adr | is->thumb);
1025 return cs_disasm_iter(is->cs_handle, &is->code, &is->size, &is->adr, is->insn);
1026 }
1027
1028
1029
1030
1031 #if 0
1032 int disasm_iter_redo(firmware *fw,iter_state_t *is) {
1033 if(!is->code || !is->ah.count) {
1034 return 0;
1035 }
1036 is->code -= is->insn->size;
1037 is->adr -= is->insn->size;
1038 is->size += is->insn->size;
1039
1040 return cs_disasm_iter(is->cs_handle, &is->code, &is->size, &is->adr, is->insn);
1041 }
1042 #endif
1043
1044
1045
1046
1047
1048
1049 int fw_disasm_iter_start(firmware *fw, uint32_t adr)
1050 {
1051 return disasm_iter_init(fw,fw->is,adr);
1052 }
1053
1054
1055 int fw_disasm_iter(firmware *fw)
1056 {
1057 return disasm_iter(fw,fw->is);
1058 }
1059
1060
1061
1062 int fw_disasm_iter_single(firmware *fw, uint32_t adr)
1063 {
1064 fw_disasm_iter_start(fw,adr);
1065 return fw_disasm_iter(fw);
1066 }
1067
1068
1069
1070
1071
1072
1073
1074 #if 0
1075 size_t fw_disasm_adr(firmware *fw, uint32_t adr, unsigned count, cs_insn **insn)
1076 {
1077 uint8_t *p=adr2ptr(fw,adr);
1078 if(!p) {
1079 *insn=NULL;
1080 return 0;
1081 }
1082 return cs_disasm(fw->cs_handle, p, fw->size8 - (p-fw->buf8), adr, count, insn);
1083 }
1084 #endif
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096 uint32_t fw_search_insn(firmware *fw, iter_state_t *is, search_insn_fn f, uint32_t v1, void *udata, uint32_t adr_end)
1097 {
1098 uint32_t adr_start=is->adr;
1099 adr_range_t *r_start=adr_get_range(fw,adr_start);
1100 if(!r_start) {
1101 fprintf(stderr,"fw_search_insn: invalid start address 0x%08x\n",adr_start);
1102 return 0;
1103 }
1104
1105
1106 if(!adr_end) {
1107 if(r_start->type == ADR_RANGE_ROM) {
1108 adr_end = fw->rom_code_search_max_adr;
1109 } else {
1110 adr_end=r_start->start + r_start->bytes - is->insn_min_size;
1111 }
1112 }
1113 adr_range_t *r_end=adr_get_range(fw,adr_end);
1114
1115 if(!r_end) {
1116 fprintf(stderr,"fw_search_insn: invalid end address 0x%08x\n",adr_end);
1117 return 0;
1118 }
1119
1120 adr_end=ADR_CLEAR_THUMB(adr_end);
1121
1122 if((r_start != r_end) || (adr_end < adr_start)) {
1123 fprintf(stderr,"fw_search_insn: invalid address range 0x%08x 0x%08x\n",adr_start,adr_end);
1124 return 0;
1125 }
1126
1127 uint32_t adr=adr_start;
1128
1129 if(r_start->type != ADR_RANGE_ROM) {
1130 while(adr < adr_end) {
1131 if(disasm_iter(fw,is)) {
1132 uint32_t r=f(fw,is,v1,udata);
1133 if(r) {
1134 return r;
1135 }
1136 adr=(uint32_t)is->adr;
1137 } else {
1138
1139
1140 adr=adr+is->insn_min_size;
1141 if(!disasm_iter_init(fw,is,adr|is->thumb)) {
1142 fprintf(stderr,"fw_search_insn: disasm_iter_init failed\n");
1143 return 0;
1144 }
1145 }
1146 }
1147 return 0;
1148 }
1149 BufRange *br=fw->br;
1150
1151
1152 while(br && adr < adr_end) {
1153 uint32_t *p_adr=(uint32_t *)adr2ptr(fw,(uint32_t)adr);
1154 uint32_t *br_end = br->p + br->len;
1155 uint32_t adr_chunk_end = ptr2adr(fw,(uint8_t*)br_end);
1156 if(adr_end < adr_chunk_end) {
1157 adr_chunk_end = adr_end;
1158 }
1159
1160 if(p_adr < br->p) {
1161 adr=ptr2adr(fw,(uint8_t *)br->p);
1162 if(!disasm_iter_init(fw,is,(uint32_t)adr | is->thumb)) {
1163 return 0;
1164 }
1165 p_adr=(uint32_t *)adr2ptr(fw,(uint32_t)adr);
1166 }
1167
1168 while(adr < adr_chunk_end) {
1169 if(disasm_iter(fw,is)) {
1170 uint32_t r=f(fw,is,v1,udata);
1171 if(r) {
1172 return r;
1173 }
1174 adr=(uint32_t)is->adr;
1175 } else {
1176
1177
1178 adr=adr+is->insn_min_size;
1179 if(!disasm_iter_init(fw,is,adr|is->thumb)) {
1180 fprintf(stderr,"fw_search_insn: disasm_iter_init failed\n");
1181 return 0;
1182 }
1183 }
1184 }
1185
1186 br=br->next;
1187 }
1188 return 0;
1189 }
1190
1191
1192
1193
1194 uint32_t search_disasm_const_ref(firmware *fw, iter_state_t *is, uint32_t val, __attribute__ ((unused))void *unused)
1195 {
1196
1197 uint32_t av=ADRx2adr(fw,is->insn);
1198 if(av) {
1199
1200 if(av == val) {
1201 return (uint32_t)is->insn->address;
1202 }
1203 return 0;
1204 }
1205 uint32_t *pv=LDR_PC2valptr(fw,is->insn);
1206 if(pv) {
1207
1208 if(*pv == val) {
1209 return (uint32_t)is->insn->address;
1210 }
1211 }
1212 return 0;
1213 }
1214
1215
1216 uint32_t search_disasm_str_ref(firmware *fw, iter_state_t *is, __attribute__ ((unused))uint32_t val, void *udata)
1217 {
1218 const char *str=(const char *)udata;
1219
1220 uint32_t av=ADRx2adr(fw,is->insn);
1221 if(av) {
1222
1223 char *cmp=(char *)adr2ptr_with_data(fw,av);
1224 if(cmp && (strcmp(cmp,str) == 0)) {
1225 return (uint32_t)is->insn->address;
1226 }
1227 return 0;
1228 }
1229 uint32_t *pv=LDR_PC2valptr(fw,is->insn);
1230 if(pv) {
1231
1232 char *cmp=(char *)adr2ptr_with_data(fw,*pv);
1233 if(cmp && (strcmp(cmp,str) == 0)) {
1234 return (uint32_t)is->insn->address;
1235 }
1236 }
1237 return 0;
1238 }
1239
1240
1241
1242
1243 uint32_t search_disasm_calls(firmware *fw, iter_state_t *is, uint32_t val, __attribute__ ((unused))void *unused)
1244 {
1245
1246 uint32_t sub=get_branch_call_insn_target(fw,is);
1247 if(sub) {
1248 if(sub == val) {
1249 return 1;
1250 }
1251 }
1252 return 0;
1253 }
1254
1255
1256 int search_calls_multi_end(__attribute__ ((unused))firmware *fw, __attribute__ ((unused))iter_state_t *is, __attribute__ ((unused))uint32_t adr) {
1257 return 1;
1258 }
1259
1260
1261
1262
1263
1264 uint32_t search_disasm_calls_multi(firmware *fw, iter_state_t *is, __attribute__ ((unused))uint32_t unused, void *userdata)
1265 {
1266 search_calls_multi_data_t *data=(search_calls_multi_data_t *)userdata;
1267 uint32_t sub=get_branch_call_insn_target(fw,is);
1268 if(sub) {
1269 while(data->adr) {
1270 if(data->adr == sub) {
1271 return data->fn(fw,is,sub);
1272 }
1273 data++;
1274 }
1275 }
1276 return 0;
1277 }
1278
1279
1280 uint32_t search_disasm_calls_veneer_multi(firmware *fw, iter_state_t *is, __attribute__ ((unused))uint32_t unused, void *userdata)
1281 {
1282 search_calls_multi_data_t *data=(search_calls_multi_data_t *)userdata;
1283 uint32_t sub=get_branch_call_insn_target(fw,is);
1284 if(sub) {
1285 while(data->adr) {
1286 if(data->adr == sub) {
1287 return data->fn(fw,is,sub);
1288 }
1289 data++;
1290 }
1291 uint32_t veneer=0;
1292 fw_disasm_iter_single(fw,sub);
1293 veneer=get_branch_call_insn_target(fw,fw->is);
1294 data=(search_calls_multi_data_t *)userdata;
1295 while(data->adr) {
1296 if(data->adr == veneer) {
1297 return data->fn(fw,is,sub);
1298 }
1299 data++;
1300 }
1301 }
1302 return 0;
1303 }
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315 int get_call_const_args(firmware *fw, iter_state_t *is_init, int max_backtrack, uint32_t *res)
1316 {
1317 int i;
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328 for (i=0;i<4;i++) {
1329 res[i]=0;
1330 }
1331
1332
1333 if(is_init->ah.count <= 1) {
1334 return 0;
1335 }
1336 if(is_init->ah.count - 1 < max_backtrack) {
1337
1338
1339
1340
1341
1342 max_backtrack = is_init->ah.count-1;
1343 }
1344 uint32_t found_bits=0;
1345 uint32_t known_bits=0;
1346
1347 for(i=1;i<=max_backtrack && known_bits !=0xf;i++) {
1348
1349
1350 fw_disasm_iter_single(fw,adr_hist_get(&is_init->ah,i));
1351
1352
1353
1354
1355
1356
1357 arm_insn insn_id = fw->is->insn->id;
1358
1359
1360 if((insn_id == ARM_INS_BL || insn_id == ARM_INS_BLX
1361
1362 )
1363 && fw->is->insn->detail->arm.cc == ARM_CC_AL) {
1364 break;
1365 }
1366
1367
1368
1369 if(fw->is->insn->detail->arm.operands[0].type != ARM_OP_REG) {
1370 continue;
1371 }
1372 arm_reg rd = fw->is->insn->detail->arm.operands[0].reg;
1373
1374
1375 if(rd < ARM_REG_R0 || rd > ARM_REG_R3) {
1376 continue;
1377 }
1378
1379 int rd_i = rd - ARM_REG_R0;
1380 uint32_t rd_bit = 1 << rd_i;
1381
1382 if(!(known_bits & rd_bit)) {
1383
1384
1385 known_bits |=rd_bit;
1386
1387 uint32_t *pv=LDR_PC2valptr(fw,fw->is->insn);
1388 if(pv) {
1389 res[rd_i] += *pv;
1390
1391 found_bits |=rd_bit;
1392 continue;
1393 }
1394 uint32_t v=ADRx2adr(fw,fw->is->insn);
1395 if(v) {
1396 res[rd_i] += v;
1397
1398 found_bits |=rd_bit;
1399 continue;
1400 }
1401
1402 if( IS_INSN_ID_MOVx(insn_id)
1403 && fw->is->insn->detail->arm.operands[1].type == ARM_OP_IMM) {
1404 res[rd_i] += fw->is->insn->detail->arm.operands[1].imm;
1405
1406 found_bits |=rd_bit;
1407 } else if(isADDx_imm(fw->is->insn)) {
1408 res[rd_i] += fw->is->insn->detail->arm.operands[1].imm;
1409
1410
1411 known_bits ^=rd_bit;
1412
1413 } else if(isSUBx_imm(fw->is->insn)) {
1414 res[rd_i] = (int)(res[rd_i]) - fw->is->insn->detail->arm.operands[1].imm;
1415
1416
1417 known_bits ^=rd_bit;
1418
1419 }
1420
1421
1422 }
1423 }
1424
1425 return found_bits;
1426 }
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441 uint32_t get_direct_jump_target(firmware *fw, iter_state_t *is_init)
1442 {
1443 uint32_t adr=B_target(fw,is_init->insn);
1444
1445 if(adr) {
1446 return (adr | is_init->thumb);
1447 }
1448 adr=LDR_PC_PC_target(fw,is_init->insn);
1449
1450 if(adr) {
1451 return adr;
1452 }
1453
1454 adr=BX_PC_target(fw,is_init->insn);
1455 if(adr) {
1456
1457 if(is_init->thumb) {
1458 return ADR_CLEAR_THUMB(adr);
1459 } else {
1460 return ADR_SET_THUMB(adr);
1461 }
1462 }
1463
1464 if((is_init->insn->id == ARM_INS_MOV || is_init->insn->id == ARM_INS_MOVW)
1465 && is_init->insn->detail->arm.operands[0].reg == ARM_REG_IP
1466 && is_init->insn->detail->arm.operands[1].type == ARM_OP_IMM) {
1467 adr = is_init->insn->detail->arm.operands[1].imm;
1468
1469 if(!fw_disasm_iter_single(fw,is_init->adr | is_init->thumb)) {
1470 fprintf(stderr,"get_direct_jump_target: disasm single failed at 0x%"PRIx64"\n",fw->is->insn->address);
1471 return 0;
1472 }
1473
1474 if(!(fw->is->insn->id == ARM_INS_MOVT
1475 && fw->is->insn->detail->arm.operands[0].reg == ARM_REG_IP
1476 && fw->is->insn->detail->arm.operands[1].type == ARM_OP_IMM)) {
1477
1478
1479 return 0;
1480 }
1481
1482 adr = (fw->is->insn->detail->arm.operands[1].imm << 16) | (adr&0xFFFF);
1483 if(!fw_disasm_iter(fw)) {
1484 fprintf(stderr,"get_direct_jump_target: disasm 2 failed at 0x%"PRIx64"\n",fw->is->insn->address);
1485 return 0;
1486 }
1487
1488 if(fw->is->insn->id == ARM_INS_BX
1489 && fw->is->insn->detail->arm.operands[0].type == ARM_OP_REG
1490 && fw->is->insn->detail->arm.operands[0].reg == ARM_REG_IP) {
1491 return adr;
1492 }
1493 }
1494 return 0;
1495 }
1496
1497
1498
1499
1500
1501
1502 uint32_t get_branch_call_insn_target(firmware *fw, iter_state_t *is)
1503 {
1504 uint32_t adr=B_BL_target(fw,is->insn);
1505 if(adr) {
1506 return (adr | is->thumb);
1507 }
1508
1509 if(is->thumb) {
1510 adr=CBx_target(fw,is->insn);
1511 if(adr) {
1512 return ADR_SET_THUMB(adr);
1513 }
1514 }
1515
1516 adr=BLXimm_target(fw,is->insn);
1517 if(adr) {
1518 if(is->thumb) {
1519 return adr;
1520 } else {
1521 return adr | is->thumb;
1522 }
1523 }
1524
1525 adr=LDR_PC_PC_target(fw,is->insn);
1526 if(adr) {
1527 return adr;
1528 }
1529 adr=BX_PC_target(fw,is->insn);
1530 if(adr) {
1531
1532 if(is->thumb) {
1533 return ADR_CLEAR_THUMB(adr);
1534 } else {
1535 return ADR_SET_THUMB(adr);
1536 }
1537 }
1538 return 0;
1539 }
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557 int find_and_get_var_ldr(firmware *fw,
1558 iter_state_t *is,
1559 int max_search_insns,
1560 int max_seq_insns,
1561 arm_reg match_val_reg,
1562 var_ldr_desc_t *result)
1563
1564 {
1565 if(!insn_match_find_next(fw,is,max_search_insns,match_ldr_pc)) {
1566
1567 return 0;
1568 }
1569 var_ldr_desc_t r;
1570 memset(&r,0,sizeof(r));
1571 r.reg_base=is->insn->detail->arm.operands[0].reg;
1572 r.adr_base=LDR_PC2val(fw,is->insn);
1573 int seq_count=1;
1574
1575 while(seq_count < max_seq_insns) {
1576
1577 if(!disasm_iter(fw,is)) {
1578 return 0;
1579 }
1580
1581
1582
1583 if(isLDR_PC(is->insn)) {
1584
1585 return 0;
1586 }
1587 seq_count++;
1588
1589 if(isADDx_imm(is->insn) || isSUBx_imm(is->insn)) {
1590 if((arm_reg)is->insn->detail->arm.operands[0].reg != r.reg_base) {
1591 continue;
1592 }
1593 if(isADDx_imm(is->insn)) {
1594 r.adj=is->insn->detail->arm.operands[1].imm;
1595 } else {
1596 r.adj=-is->insn->detail->arm.operands[1].imm;
1597 }
1598 if(!disasm_iter(fw,is)) {
1599 return 0;
1600 }
1601 seq_count++;
1602 } else {
1603 r.adj=0;
1604 }
1605
1606
1607
1608
1609 if((r.reg_base >= ARM_REG_R0 && r.reg_base <= ARM_REG_R3)
1610 && (is->insn->id == ARM_INS_BL || is->insn->id == ARM_INS_BLX
1611 || is->insn->id == ARM_INS_B || is->insn->id == ARM_INS_BX)
1612 && is->insn->detail->arm.cc == ARM_CC_AL) {
1613
1614 return 0;
1615 }
1616 if(is->insn->id != ARM_INS_LDR || (arm_reg)is->insn->detail->arm.operands[1].reg != r.reg_base) {
1617
1618
1619 if(is->insn->detail->arm.operands[0].type == ARM_OP_REG && (arm_reg)is->insn->detail->arm.operands[0].reg == r.reg_base) {
1620
1621 return 0;
1622 }
1623 continue;
1624 }
1625 r.reg_val = is->insn->detail->arm.operands[0].reg;
1626 if(match_val_reg != ARM_REG_INVALID && (r.reg_val != match_val_reg)) {
1627 continue;
1628 }
1629 r.off = is->insn->detail->arm.operands[1].mem.disp;
1630 r.adr_adj = r.adr_base + r.adj;
1631 r.adr_final = r.adr_adj + r.off;
1632 memcpy(result,&r,sizeof(r));
1633 return 1;
1634 }
1635 return 0;
1636 }
1637
1638
1639
1640
1641
1642
1643
1644 int find_const_ref_call(firmware *fw,
1645 iter_state_t *is,
1646 int max_search_bytes,
1647 int max_gap_insns,
1648 arm_reg match_reg,
1649 uint32_t val)
1650
1651 {
1652 if(match_reg < ARM_REG_R0 || match_reg > ARM_REG_R3) {
1653 fprintf(stderr,"find_const_ref_call: invalid match_reg %d\n",match_reg);
1654 return 0;
1655 }
1656 if(max_gap_insns >= ADR_HIST_SIZE) {
1657 fprintf(stderr,"find_const_ref_call: invalid max_gap_insns %d\n",max_gap_insns);
1658 return 0;
1659 }
1660
1661 while(fw_search_insn(fw,is,search_disasm_const_ref,val,NULL,(uint32_t)(is->adr+max_search_bytes))) {
1662 uint32_t next_adr = (uint32_t)is->adr;
1663
1664
1665 if(insn_match_find_next(fw,is,max_gap_insns,match_bl_blximm)) {
1666 uint32_t reg_num = match_reg - ARM_REG_R0;
1667 uint32_t reg_bit = 1 << reg_num;
1668 uint32_t regs[4];
1669
1670 if((get_call_const_args(fw,is,max_gap_insns,regs)®_bit)==reg_bit) {
1671 if(regs[reg_num] == val) {
1672 return iter_state_adr(is);
1673 }
1674 }
1675 }
1676
1677 disasm_iter_init(fw,is,next_adr | is->thumb);
1678 }
1679 return 0;
1680 }
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690 #define MATCH_SIMPLE_FUNC_NONE 0x0
1691
1692 #define MATCH_SIMPLE_FUNC_NULLSUB 0x1
1693
1694 #define MATCH_SIMPLE_FUNC_IMM 0x2
1695
1696
1697 #define MATCH_SIMPLE_FUNC_ANY 0x3
1698 int check_simple_func(firmware *fw, uint32_t adr, int match_ftype, simple_func_desc_t *info)
1699 {
1700 const insn_match_t match_mov_r0_imm[]={
1701 {MATCH_INS(MOV, 2), {MATCH_OP_REG(R0), MATCH_OP_IMM_ANY}},
1702 #if CS_API_MAJOR < 4
1703 {MATCH_INS(MOVS, 2), {MATCH_OP_REG(R0), MATCH_OP_IMM_ANY}},
1704 #endif
1705 {ARM_INS_ENDING}
1706 };
1707
1708 int found = 0;
1709 int found_val = 0;
1710 if(info) {
1711 info->ftype = MATCH_SIMPLE_FUNC_NONE;
1712 info->retval = 0;
1713 }
1714 if(!fw_disasm_iter_single(fw,adr)) {
1715
1716 return 0;
1717 }
1718 if(match_ftype & MATCH_SIMPLE_FUNC_IMM) {
1719
1720 if(insn_match_any(fw->is->insn,match_mov_r0_imm)) {
1721 found_val = fw->is->insn->detail->arm.operands[1].imm;
1722 found = MATCH_SIMPLE_FUNC_IMM;
1723
1724 if(!fw_disasm_iter(fw)) {
1725
1726 return 0;
1727 }
1728 }
1729 }
1730 if(!isRETx(fw->is->insn)) {
1731
1732 return 0;
1733 }
1734
1735 if(!found && (match_ftype & MATCH_SIMPLE_FUNC_NULLSUB)) {
1736 found = MATCH_SIMPLE_FUNC_NULLSUB;
1737
1738 }
1739 if(found) {
1740 if(info) {
1741 info->ftype = found;
1742 info->retval = found_val;
1743 }
1744 }
1745 return found;
1746 }
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757 uint32_t find_last_call_from_func(firmware *fw, iter_state_t *is,int min_insns, int max_insns)
1758 {
1759 int push_found=0;
1760 uint32_t last_adr=0;
1761 int count;
1762 for(count=0; count < max_insns; count++) {
1763 if(!disasm_iter(fw,is)) {
1764 fprintf(stderr,"find_last_call_from_func: disasm failed 0x%"PRIx64"\n",is->adr);
1765 return 0;
1766 }
1767
1768 if(isPUSH_LR(is->insn)) {
1769
1770 if(push_found) {
1771
1772 return 0;
1773 }
1774 push_found=1;
1775 continue;
1776 }
1777
1778
1779 if(!push_found) {
1780 continue;
1781 }
1782
1783 if(insn_match_any(is->insn,match_bl_blximm) && count >= min_insns) {
1784
1785 last_adr=get_branch_call_insn_target(fw,is);
1786 continue;
1787 }
1788
1789 if(isPOP_PC(is->insn)) {
1790
1791 if(last_adr) {
1792 return last_adr;
1793 }
1794
1795 return 0;
1796 }
1797
1798 if(isPOP_LR(is->insn)) {
1799
1800 if(count < min_insns) {
1801
1802 return 0;
1803 }
1804 if(!disasm_iter(fw,is)) {
1805 fprintf(stderr,"find_last_call_from_func: disasm failed 0x%"PRIx64"\n",is->adr);
1806 return 0;
1807 }
1808
1809
1810
1811 const insn_match_t match_tail[]={
1812 {MATCH_INS(MOV, MATCH_OPCOUNT_ANY), {MATCH_OP_REG_RANGE(R0,R3), MATCH_OP_REST_ANY}},
1813
1814
1815 #if CS_API_MAJOR < 4
1816 {MATCH_INS(MOV, MATCH_OPCOUNT_ANY), {MATCH_OP_REG_RANGE(R0,R3), MATCH_OP_REST_ANY}},
1817 #endif
1818
1819 {MATCH_INS(LDR, 2), {MATCH_OP_REG_RANGE(R0,R3), MATCH_OP_ANY}},
1820 {ARM_INS_ENDING}
1821 };
1822 while(insn_match_any(is->insn,match_tail) && count < max_insns) {
1823 if(!disasm_iter(fw,is)) {
1824 fprintf(stderr,"find_last_call_from_func: disasm failed 0x%"PRIx64"\n",is->adr);
1825 return 0;
1826 }
1827 count++;
1828 }
1829 if(is->insn->id == ARM_INS_B && is->insn->detail->arm.cc == ARM_CC_AL) {
1830 return get_branch_call_insn_target(fw,is);
1831 }
1832
1833
1834 return 0;
1835 }
1836
1837 if(isRETx(is->insn)) {
1838
1839 return 0;
1840 }
1841 }
1842
1843 return 0;
1844 }
1845
1846
1847
1848
1849 const insn_match_t match_b[]={
1850 {MATCH_INS(B, MATCH_OPCOUNT_IGNORE)},
1851 {ARM_INS_ENDING}
1852 };
1853 const insn_match_t match_bl[]={
1854 {MATCH_INS(BL, MATCH_OPCOUNT_IGNORE)},
1855 {ARM_INS_ENDING}
1856 };
1857 const insn_match_t match_b_bl[]={
1858 {MATCH_INS(B, MATCH_OPCOUNT_IGNORE)},
1859 {MATCH_INS(BL, MATCH_OPCOUNT_IGNORE)},
1860 {ARM_INS_ENDING}
1861 };
1862
1863 const insn_match_t match_b_bl_blximm[]={
1864 {MATCH_INS(B, MATCH_OPCOUNT_IGNORE)},
1865 {MATCH_INS(BL, MATCH_OPCOUNT_IGNORE)},
1866 {MATCH_INS(BLX, 1), {MATCH_OP_IMM_ANY}},
1867 {ARM_INS_ENDING}
1868 };
1869
1870 const insn_match_t match_bl_blximm[]={
1871 {MATCH_INS(BL, MATCH_OPCOUNT_IGNORE)},
1872 {MATCH_INS(BLX, 1), {MATCH_OP_IMM_ANY}},
1873 {ARM_INS_ENDING}
1874 };
1875
1876 const insn_match_t match_bxlr[]={
1877 {MATCH_INS(BX, 1), {MATCH_OP_REG(LR)}},
1878 {ARM_INS_ENDING}
1879 };
1880
1881 const insn_match_t match_ldr_pc[]={
1882 {MATCH_INS(LDR, 2), {MATCH_OP_REG_ANY, MATCH_OP_MEM_BASE(PC)}},
1883 {ARM_INS_ENDING}
1884 };
1885
1886
1887 int insn_match_seq(firmware *fw, iter_state_t *is, const insn_match_t *match)
1888 {
1889
1890 while(match->id != ARM_INS_ENDING && disasm_iter(fw,is) && insn_match(is->insn,match)) {
1891
1892 match++;
1893 }
1894 return (match->id == ARM_INS_ENDING);
1895 }
1896
1897
1898 static const arm_reg reg_order[] = {
1899 ARM_REG_R0,
1900 ARM_REG_R1,
1901 ARM_REG_R2,
1902 ARM_REG_R3,
1903 ARM_REG_R4,
1904 ARM_REG_R5,
1905 ARM_REG_R6,
1906 ARM_REG_R7,
1907 ARM_REG_R8,
1908 ARM_REG_R9,
1909 ARM_REG_R10,
1910 ARM_REG_R11,
1911 ARM_REG_R12,
1912 ARM_REG_SP,
1913 ARM_REG_LR,
1914 ARM_REG_PC,
1915 };
1916
1917 int reg_in_range(arm_reg r, arm_reg min_reg, arm_reg max_reg)
1918 {
1919 int c = -1, c_min = -1, c_max = -1;
1920 int i;
1921 for(i=0; i<(int)(sizeof(reg_order)/sizeof(arm_reg)); i++) {
1922 if(reg_order[i] == r) {
1923 c = i;
1924 }
1925 if(reg_order[i] == min_reg) {
1926 c_min = i;
1927 }
1928 if(reg_order[i] == max_reg) {
1929 c_max = i;
1930 }
1931 }
1932
1933 if( c < 0 || c_min < 0 || c_max < 0) {
1934 return 0;
1935 }
1936 return (c >= c_min && c <= c_max);
1937 }
1938
1939
1940 int insn_match(cs_insn *insn,const insn_match_t *match)
1941 {
1942
1943 if(match->id != ARM_INS_INVALID && insn->id != match->id) {
1944 return 0;
1945 }
1946
1947 if(match->cc != ARM_CC_INVALID && insn->detail->arm.cc != match->cc) {
1948 return 0;
1949 }
1950
1951 if(match->op_count == MATCH_OPCOUNT_IGNORE) {
1952 return 1;
1953 }
1954
1955 if(match->op_count >= 0 && insn->detail->arm.op_count != match->op_count) {
1956 return 0;
1957 }
1958 int i;
1959
1960 for(i=0; i<MATCH_MAX_OPS && i < insn->detail->arm.op_count; i++) {
1961
1962 if(match->operands[i].type != ARM_OP_INVALID && insn->detail->arm.operands[i].type != match->operands[i].type) {
1963 return 0;
1964 }
1965
1966 if(match->operands[i].reg1 != ARM_REG_INVALID) {
1967 if(insn->detail->arm.operands[i].type == ARM_OP_REG) {
1968
1969 if(match->operands[i].reg2 != ARM_REG_INVALID) {
1970 if(!reg_in_range((arm_reg)insn->detail->arm.operands[i].reg,
1971 match->operands[i].reg1, match->operands[i].reg2)) {
1972 return 0;
1973 }
1974 } else if((arm_reg)insn->detail->arm.operands[i].reg != match->operands[i].reg1) {
1975 return 0;
1976 }
1977 } else if(insn->detail->arm.operands[i].type == ARM_OP_MEM) {
1978 if(insn->detail->arm.operands[i].mem.base != match->operands[i].reg1) {
1979 return 0;
1980 }
1981 } else {
1982 fprintf(stderr,"insn_match: reg1 match requested on operand not reg or mem %d\n",
1983 insn->detail->arm.operands[i].type);
1984 }
1985 }
1986 if(match->operands[i].reg2 != ARM_REG_INVALID) {
1987 if(insn->detail->arm.operands[i].type == ARM_OP_MEM) {
1988 if(insn->detail->arm.operands[i].mem.index != match->operands[i].reg2) {
1989 return 0;
1990 }
1991 } else if(insn->detail->arm.operands[i].type != ARM_OP_REG) {
1992 fprintf(stderr,"insn_match: reg2 match requested on operand not reg or mem %d\n",
1993 insn->detail->arm.operands[i].type);
1994 }
1995 }
1996 if(match->operands[i].flags & MATCH_OP_FL_IMM) {
1997 if(insn->detail->arm.operands[i].type == ARM_OP_IMM
1998 || insn->detail->arm.operands[i].type == ARM_OP_PIMM
1999 || insn->detail->arm.operands[i].type == ARM_OP_CIMM) {
2000 if(insn->detail->arm.operands[i].imm != match->operands[i].imm) {
2001 return 0;
2002 }
2003 } else if(insn->detail->arm.operands[i].type == ARM_OP_MEM) {
2004 if(insn->detail->arm.operands[i].mem.disp != match->operands[i].imm) {
2005 return 0;
2006 }
2007 } else {
2008 fprintf(stderr,"insn_match: imm match requested on operand not imm or mem %d\n",
2009 insn->detail->arm.operands[i].type);
2010 }
2011 }
2012 if(match->operands[i].flags & MATCH_OP_FL_LAST) {
2013 break;
2014 }
2015 }
2016 return 1;
2017 }
2018
2019
2020 int insn_match_any(cs_insn *insn,const insn_match_t *match)
2021 {
2022 const insn_match_t *m;
2023
2024 for(m=match;m->id != ARM_INS_ENDING;m++) {
2025 if(insn_match(insn,m)) {
2026 return 1;
2027 }
2028 }
2029 return 0;
2030 }
2031
2032
2033 int insn_match_find_next(firmware *fw, iter_state_t *is, int max_insns, const insn_match_t *match)
2034 {
2035 int i=0;
2036 while(i < max_insns) {
2037
2038 if(!disasm_iter(fw,is)) {
2039 return 0;
2040 }
2041
2042 if(insn_match_any(is->insn,match)) {
2043 return 1;
2044 }
2045 i++;
2046 }
2047
2048 return 0;
2049 }
2050
2051
2052 int insn_match_find_nth(firmware *fw, iter_state_t *is, int max_insns, int num_to_match, const insn_match_t *match)
2053 {
2054 int i=0;
2055 int num_matched=0;
2056 while(i < max_insns) {
2057
2058 if(!disasm_iter(fw,is)) {
2059 return 0;
2060 }
2061
2062
2063 const insn_match_t *m;
2064
2065 for(m=match;m->id != ARM_INS_ENDING;m++) {
2066 if(insn_match(is->insn,m)) {
2067 num_matched++;
2068 }
2069 }
2070 if(num_matched == num_to_match) {
2071 return 1;
2072 }
2073 i++;
2074 }
2075
2076 return 0;
2077 }
2078
2079
2080 int insn_match_find_next_seq(firmware *fw, iter_state_t *is, int max_insns, const insn_match_t *match)
2081 {
2082 int count=0;
2083 while(count < max_insns) {
2084 const insn_match_t *m=match;
2085
2086 while(m->id != ARM_INS_ENDING && disasm_iter(fw,is) && insn_match(is->insn,m)) {
2087 m++;
2088 count++;
2089 }
2090 if(m->id == ARM_INS_ENDING) {
2091 return 1;
2092 }
2093
2094 count++;
2095 }
2096 return 0;
2097 }
2098
2099
2100
2101
2102
2103
2104
2105 int fw_search_bytes(firmware *fw, search_bytes_fn func)
2106 {
2107 BufRange *p = fw->br;
2108 while (p)
2109 {
2110 int k;
2111 for (k = p->off*4; k < (p->off + p->len)*4; k++)
2112 {
2113 if (func(fw,k))
2114 return 1;
2115 }
2116 p = p->next;
2117 }
2118 return 0;
2119 }
2120
2121
2122
2123
2124 void fw_add_adr_range(firmware *fw, uint32_t start, uint32_t end, uint32_t src_start, int type, int flags)
2125 {
2126 if(fw->adr_range_count == FW_MAX_ADR_RANGES) {
2127 fprintf(stderr,"fw_add_adr_range: FW_MAX_ADR_RANGES hit\n");
2128 return;
2129 }
2130 if(src_start < fw->base) {
2131 fprintf(stderr,"fw_add_adr_range: src_start 0x%08x < base 0x%08x\n",src_start,fw->base);
2132 return;
2133 }
2134 if(src_start >= fw->base+fw->size8) {
2135 fprintf(stderr,"fw_add_adr_range: src_start 0x%08x outside dump end 0x%08x\n",src_start,fw->base+fw->size8);
2136 return;
2137 }
2138 if(end <= start) {
2139 fprintf(stderr,"fw_add_adr_range: end 0x%08x <= start 0x%08x\n",end,start);
2140 return;
2141 }
2142 uint32_t len=end-start;
2143 if(len > 0xFFFFFFFF - src_start) {
2144 fprintf(stderr,"fw_add_adr_range: range too long %d\n",len);
2145 return;
2146 }
2147 if(len > fw->size8 - (start - fw->base)) {
2148 fprintf(stderr,"fw_add_adr_range: range outside of dump %d\n",len);
2149 return;
2150 }
2151 adr_range_t *r=&fw->adr_ranges[fw->adr_range_count];
2152
2153 r->start=start;
2154 r->src_start=src_start;
2155 r->bytes=len;
2156 r->type=type;
2157 r->flags=flags;
2158 r->buf=fw->buf8 + (r->src_start - fw->base);
2159
2160 fw->adr_range_count++;
2161 }
2162
2163 void find_dryos_vers(firmware *fw)
2164 {
2165 const char *sig="DRYOS version 2.3, release #";
2166 fw->dryos_ver_count = find_bytes_all(fw,sig,strlen(sig),fw->base,fw->dryos_ver_list,FW_MAX_DRYOS_VERS);
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176 if(fw->dryos_ver_count) {
2177 if(fw->dryos_ver_count == FW_MAX_DRYOS_VERS) {
2178 fprintf(stderr,"WARNING hit FW_MAX_DRYOS_VERS\n");
2179 }
2180 uint32_t i;
2181 int match_i;
2182 uint32_t min_adr = 0xFFFFFFFF;
2183
2184
2185 uint32_t maxadr = (fw->rom_code_search_max_adr - 0x800000 > fw->base)?fw->base + 0x800000:fw->rom_code_search_max_adr;
2186
2187
2188 for(i=0; i<fw->dryos_ver_count; i++) {
2189
2190
2191 uint32_t adr = find_u32_adr_range(fw,fw->dryos_ver_list[i],fw->rom_code_search_min_adr,maxadr);
2192 if(adr && adr < min_adr) {
2193 min_adr = adr;
2194 match_i = i;
2195 }
2196 }
2197 if(min_adr == 0xFFFFFFFF) {
2198 fprintf(stderr,"WARNING dryos version pointer not found, defaulting to first\n");
2199 match_i = 0;
2200 min_adr = 0;
2201 }
2202 fw->dryos_ver_str = (const char *)adr2ptr(fw,fw->dryos_ver_list[match_i]);
2203 const char *s = (const char *)adr2ptr(fw,fw->dryos_ver_list[match_i]+strlen(sig));
2204 fw->dryos_ver = atoi(s);
2205 if(s[4] == '+' && s[5] == 'p') {
2206 fw->dryos_ver_patch = atoi(s+6);
2207 if(fw->dryos_ver_patch >= FW_DRYOS_VER_MUL) {
2208 fprintf(stderr,"WARNING unexpected patch revision %d\n",fw->dryos_ver_patch);
2209 }
2210 } else {
2211 fw->dryos_ver_patch = 0;
2212 }
2213 fw->dryos_ver_full = fw->dryos_ver * FW_DRYOS_VER_MUL + fw->dryos_ver_patch;
2214 fw->dryos_ver_adr = fw->dryos_ver_list[match_i];
2215 fw->dryos_ver_ref_adr = min_adr;
2216
2217 } else {
2218 fw->dryos_ver = 0;
2219 fw->dryos_ver_patch = 0;
2220 fw->dryos_ver_full = 0;
2221 fw->dryos_ver_str = NULL;
2222 fw->dryos_ver_adr = 0;
2223 }
2224 }
2225
2226
2227 void firmware_load(firmware *fw, const char *filename, uint32_t base_adr,int fw_arch)
2228 {
2229 FILE *f = fopen(filename, "rb");
2230 if (f == NULL)
2231 {
2232 fprintf(stderr,"Error opening %s\n",filename);
2233 exit(1);
2234 }
2235 fseek(f,0,SEEK_END);
2236 fw->size8 = ftell(f);
2237 fseek(f,0,SEEK_SET);
2238
2239
2240 if(fw->size8&3) {
2241 fprintf(stderr,"WARNING: dump size %d is not divisible by 4, truncating\n",fw->size8);
2242 fw->size8 &= ~3;
2243 }
2244
2245
2246 if((int)(0xFFFFFFFF - base_adr) < fw->size8) {
2247 fprintf(stderr,"adjusted dump size 0x%08x->",fw->size8);
2248 fw->size8 = 0xFFFFFFFC - base_adr;
2249 fprintf(stderr,"0x%08x\n",fw->size8);
2250 }
2251
2252 fw->arch=fw_arch;
2253 fw->size32=fw->size8/4;
2254
2255 fw->base = base_adr;
2256
2257 fw->buf8 = malloc(fw->size8);
2258 if(!fw->buf8) {
2259 fprintf(stderr,"malloc %d failed\n",fw->size8);
2260 exit(1);
2261 }
2262 fread(fw->buf8, 1, fw->size8, f);
2263 fclose(f);
2264 findRanges(fw);
2265
2266 fw->adr_range_count=0;
2267
2268 fw_add_adr_range(fw,fw->base, fw->base+fw->size8, fw->base, ADR_RANGE_ROM, ADR_RANGE_FL_NONE);
2269
2270 fw->main_offs = 0;
2271 int k = find_str(fw, "gaonisoy");
2272
2273 if(k == -1) {
2274
2275 if(find_str(fw,"VxWorks") == -1) {
2276 fprintf(stderr,"WARNING gaonisoy string not found, assuming code start offset 0\n");
2277 }
2278 } else if (k != 1) {
2279
2280 if(fw_memcmp(fw,fw->base+0x20004,"gaonisoy",8) == 0) {
2281 fw->main_offs = 0x20000;
2282 } else if (fw_memcmp(fw,fw->base+0x10004,"gaonisoy",8) == 0) {
2283 fw->main_offs = 0x10000;
2284 } else {
2285 fprintf(stderr,"WARNING code start offset not found, assuming 0\n");
2286 }
2287 }
2288
2289 fw->rom_code_search_min_adr = fw->base + fw->main_offs;
2290 fw->rom_code_search_max_adr=fw->base+fw->size8 - 4;
2291
2292 find_dryos_vers(fw);
2293
2294 fw->firmware_ver_str = 0;
2295 k = find_str(fw, "Firmware Ver ");
2296 if (k != -1)
2297 {
2298 fw->firmware_ver_str = (char *)fw->buf8 + k*4;
2299 }
2300
2301 if(fw->arch==FW_ARCH_ARMv5) {
2302 fw->thumb_default = 0;
2303 } else if(fw->arch==FW_ARCH_ARMv7) {
2304 fw->thumb_default = 1;
2305 } else {
2306 fprintf(stderr,"firmware_init_capstone: invalid arch\n");
2307 }
2308 }
2309
2310
2311 int do_blx_check(firmware *fw)
2312 {
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331 static const uint8_t code[]=
2332 "\x00\xf0\x06\xe8"
2333 "\x01\x20"
2334 "\x00\xf0\x04\xe8"
2335 ;
2336 cs_insn *insn;
2337 size_t count;
2338 count = cs_disasm(fw->cs_handle_thumb, code, sizeof(code), 0xFF000000, 3, &insn);
2339
2340 if(!(count == 3 && insn[0].id == ARM_INS_BLX && insn[2].id == ARM_INS_BLX)) {
2341 fprintf(stderr,"do_blx_check: disassembly failed\n");
2342 return 0;
2343 }
2344
2345 int r=(insn[0].detail->arm.operands[0].imm == insn[2].detail->arm.operands[0].imm);
2346
2347
2348 if(!r) {
2349 fprintf(stderr,"WARNING! Incorrect disassembly is likely\n");
2350 }
2351 cs_free(insn,count);
2352 return r;
2353 }
2354
2355
2356 int firmware_init_capstone(firmware *fw)
2357 {
2358 if (cs_open(CS_ARCH_ARM, CS_MODE_ARM, &fw->cs_handle_arm) != CS_ERR_OK) {
2359 fprintf(stderr,"cs_open ARM failed\n");
2360 return 0;
2361 }
2362 cs_option(fw->cs_handle_arm, CS_OPT_DETAIL, CS_OPT_ON);
2363 if (cs_open(CS_ARCH_ARM, CS_MODE_THUMB, &fw->cs_handle_thumb) != CS_ERR_OK) {
2364 fprintf(stderr,"cs_open thumb failed\n");
2365 return 0;
2366 }
2367 cs_option(fw->cs_handle_thumb, CS_OPT_DETAIL, CS_OPT_ON);
2368 fw->is=disasm_iter_new(fw,0);
2369 do_blx_check(fw);
2370 return 1;
2371 }
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381 int find_startup_copy(firmware *fw,
2382 iter_state_t *is,
2383 int max_search,
2384 uint32_t *src_start,
2385 uint32_t *dst_start,
2386 uint32_t *dst_end)
2387 {
2388 int count=0;
2389 uint32_t *fptr = NULL;
2390 uint32_t *dptr = NULL;
2391 uint32_t *eptr = NULL;
2392 *src_start=0;
2393 *dst_start=0;
2394 *dst_end=0;
2395
2396 while(disasm_iter(fw,is) && count < max_search) {
2397 uint32_t *pv=LDR_PC2valptr(fw,is->insn);
2398
2399
2400 if(!pv) {
2401 fptr=dptr=eptr=NULL;
2402 }else if(!fptr) {
2403
2404 if(*pv > fw->base) {
2405 fptr=pv;
2406 }
2407 } else if(!dptr) {
2408 if(*pv < fw->base) {
2409 dptr=pv;
2410 } else {
2411 fptr=NULL;
2412 }
2413 } else if(!eptr) {
2414 if(*pv < fw->base && *pv > *dptr) {
2415 eptr=pv;
2416 } else {
2417
2418 fptr=dptr=NULL;
2419 }
2420 }
2421 if(fptr && dptr && eptr) {
2422 *src_start=*fptr;
2423 *dst_start=*dptr;
2424 *dst_end=*eptr;
2425 return 1;
2426 }
2427 count++;
2428 }
2429 return 0;
2430 }
2431
2432 void find_exception_vec(firmware *fw, iter_state_t *is)
2433 {
2434
2435
2436 if(fw->arch != FW_ARCH_ARMv7) {
2437 return;
2438 }
2439
2440 const insn_match_t match_bl_mcr[]={
2441 {MATCH_INS(BL, 1), {MATCH_OP_IMM_ANY}},
2442
2443 {MATCH_INS(MCR, 6), {MATCH_OP_PIMM(15),MATCH_OP_IMM(0),MATCH_OP_REG_ANY,MATCH_OP_CIMM(12),MATCH_OP_CIMM(0),MATCH_OP_IMM(0)}},
2444 {ARM_INS_ENDING}
2445 };
2446
2447
2448 disasm_iter_init(fw, is, fw->base + fw->main_offs + 12 + fw->thumb_default);
2449 if(!insn_match_find_next(fw,is,4,match_bl_mcr)) {
2450
2451 return;
2452 }
2453
2454 uint32_t faddr = get_branch_call_insn_target(fw,is);
2455 if(faddr) {
2456
2457 disasm_iter_init(fw, is, faddr);
2458 disasm_iter(fw, is);
2459 int ra,rb;
2460 uint32_t va, vb;
2461 if(!IS_INSN_ID_MOVx(is->insn->id) || is->insn->detail->arm.operands[1].type != ARM_OP_IMM) {
2462 return;
2463 }
2464 ra = is->insn->detail->arm.operands[0].reg;
2465 va = is->insn->detail->arm.operands[1].imm;
2466 disasm_iter(fw, is);
2467 if(is->insn->id != ARM_INS_MOVT
2468 || is->insn->detail->arm.operands[0].reg != ra
2469 || is->insn->detail->arm.operands[1].type != ARM_OP_IMM) {
2470 return;
2471 }
2472 va = (is->insn->detail->arm.operands[1].imm << 16) | (va & 0xFFFF);
2473
2474 va = va & ~1;
2475 if(adr_get_range_type(fw,va) != ADR_RANGE_ROM) {
2476 return;
2477 }
2478 disasm_iter(fw, is);
2479 if(!IS_INSN_ID_MOVx(is->insn->id) || is->insn->detail->arm.operands[1].type != ARM_OP_IMM) {
2480 return;
2481 }
2482 rb = is->insn->detail->arm.operands[0].reg;
2483 vb = is->insn->detail->arm.operands[1].imm;
2484 disasm_iter(fw, is);
2485 if(is->insn->id != ARM_INS_MOVT
2486 || is->insn->detail->arm.operands[0].reg != rb
2487 || is->insn->detail->arm.operands[1].type != ARM_OP_IMM) {
2488 return;
2489 }
2490 vb = (is->insn->detail->arm.operands[1].imm << 16) | (vb & 0xFFFF);
2491 vb = vb & ~1;
2492 if(adr_get_range_type(fw,vb) != ADR_RANGE_ROM) {
2493 return;
2494 }
2495 if(va >= vb) {
2496 return;
2497 }
2498 fw_add_adr_range(fw,0,vb - va, va, ADR_RANGE_RAM_CODE, ADR_RANGE_FL_EVEC | ADR_RANGE_FL_TCM);
2499
2500
2501 } else if(is->insn->id == ARM_INS_MCR) {
2502
2503 fw->arch_flags |= FW_ARCH_FL_VMSA;
2504
2505 disasm_iter_init(fw, is, adr_hist_get(&is->ah,1));
2506 disasm_iter(fw, is);
2507
2508
2509 }
2510 }
2511
2512
2513 void firmware_init_data_ranges(firmware *fw)
2514 {
2515
2516 uint32_t src_start, dst_start, dst_end;
2517 uint32_t data_found_copy = 0;
2518
2519
2520 iter_state_t *is=disasm_iter_new(fw, fw->base + fw->main_offs + 12 + fw->thumb_default);
2521
2522 fw->data_init_start=0;
2523 fw->data_start=0;
2524 fw->data_len=0;
2525
2526 fw->memisostart=0;
2527
2528 int base2_found=0;
2529 int base3_found=0;
2530
2531
2532 int max_search=100;
2533 while(find_startup_copy(fw,is,max_search,&src_start,&dst_start,&dst_end)) {
2534
2535 if(dst_start < 0x100000) {
2536
2537 if(fw->data_init_start) {
2538 fprintf(stderr,"firmware_init_data_ranges: data already found, unexpected start 0x%08x src 0x%08x end 0x%08x\n",
2539 dst_start,src_start,dst_end);
2540 continue;
2541 }
2542
2543
2544 if(dst_start != 0x1900 && dst_start != 0x8000) {
2545 fprintf(stderr,"firmware_init_data_ranges: guess unknown ROM data_start 0x%08x src 0x%08x end 0x%08x\n",
2546 dst_start,src_start,dst_end);
2547 }
2548 fw->data_init_start=src_start;
2549 fw->data_start=dst_start;
2550 fw->data_len=dst_end-dst_start;
2551 fw_add_adr_range(fw,dst_start,dst_end,src_start, ADR_RANGE_INIT_DATA, ADR_RANGE_FL_NONE);
2552 data_found_copy=is->adr;
2553 } else if(dst_start < 0x08000000) {
2554
2555 if(base2_found) {
2556 fprintf(stderr,"firmware_init_data_ranges: base2 already found, unexpected start 0x%08x src 0x%08x end 0x%08x\n",
2557 dst_start,src_start,dst_end);
2558 continue;
2559 }
2560 base2_found=1;
2561
2562 if( dst_start != 0x003f1000 &&
2563 dst_start != 0x00431000 &&
2564 dst_start != 0x00471000 &&
2565 dst_start != 0x00685000 &&
2566 dst_start != 0x00671000 &&
2567 dst_start != 0x006b1000 &&
2568 dst_start != 0x010c1000 &&
2569 dst_start != 0x010e1000 &&
2570 dst_start != 0x01900000) {
2571 fprintf(stderr,"firmware_init_data_ranges: guess unknown base2 0x%08x src 0x%08x end 0x%08x\n",
2572 dst_start,src_start,dst_end);
2573 }
2574 fw_add_adr_range(fw,dst_start,dst_end,src_start,ADR_RANGE_RAM_CODE, ADR_RANGE_FL_NONE);
2575 } else {
2576
2577 if(base3_found) {
2578 fprintf(stderr,"firmware_init_data_ranges: base3 already found, unexpected start 0x%08x src 0x%08x end 0x%08x\n",
2579 dst_start,src_start,dst_end);
2580 continue;
2581 }
2582 base3_found=1;
2583 if(dst_start != 0xbfe10800 &&
2584 dst_start != 0xdffc4900) {
2585 fprintf(stderr,"firmware_init_data_ranges: guess unknown base3 0x%08x src 0x%08x end 0x%08x\n",
2586 dst_start,src_start,dst_end);
2587 }
2588 fw_add_adr_range(fw,dst_start,dst_end,src_start,ADR_RANGE_RAM_CODE, ADR_RANGE_FL_TCM);
2589 }
2590 if(fw->data_start && base2_found && base3_found) {
2591 break;
2592 }
2593
2594 max_search=16;
2595 }
2596
2597
2598 if(data_found_copy) {
2599 int count=0;
2600 uint32_t *eptr=NULL;
2601 uint32_t *dptr=NULL;
2602 disasm_iter_init(fw,is,(data_found_copy-4) | fw->thumb_default);
2603 while(disasm_iter(fw,is) && count < 20) {
2604 uint32_t *pv=LDR_PC2valptr(fw,is->insn);
2605
2606 if(!pv) {
2607
2608 } else if(!dptr) {
2609
2610
2611 if(*pv == fw->data_start + fw->data_len) {
2612 dptr=pv;
2613 }
2614 } else if(!eptr) {
2615 if(*pv < fw->base) {
2616 if(*pv != fw->data_start + fw->data_len) {
2617 eptr=pv;
2618 }
2619 } else {
2620 eptr=dptr=NULL;
2621 }
2622 }
2623 if(dptr && eptr) {
2624
2625 fw->memisostart=*eptr;
2626 break;
2627 }
2628 count++;
2629 }
2630 }
2631
2632 find_exception_vec(fw,is);
2633
2634
2635
2636 if(fw->data_start) {
2637 fw->rom_code_search_max_adr=fw->data_init_start;
2638 }
2639
2640 if(fw->dryos_ver_adr) {
2641 if(fw->dryos_ver_adr < fw->rom_code_search_max_adr) {
2642 fw->rom_code_search_max_adr = fw->dryos_ver_adr;
2643 }
2644 }
2645 disasm_iter_free(is);
2646 }
2647
2648
2649 void firmware_unload(firmware *fw)
2650 {
2651 if(!fw) {
2652 return;
2653 }
2654 if(fw->is) {
2655 disasm_iter_free(fw->is);
2656 }
2657 if(fw->cs_handle_arm) {
2658 cs_close(&fw->cs_handle_arm);
2659 }
2660 if(fw->cs_handle_thumb) {
2661 cs_close(&fw->cs_handle_thumb);
2662 }
2663 free(fw->buf8);
2664 memset(fw,0,sizeof(firmware));
2665 }