1 #ifndef FIRMWARE_LOAD_NG_H 2 #define FIRMWARE_LOAD_NG_H 3 4 #define MIN(a,b) ((a) < (b) ? (a) : (b)) 5 #define MAX(a,b) ((a) > (b) ? (a) : (b)) 6 7 // Digic 2-5+ (ignoring S1) 8 #define FW_ARCH_ARMv5 1 9 // Digic 6, 7 10 #define FW_ARCH_ARMv7 2 11 12 // additional arch flags 13 #define FW_ARCH_FL_VMSA 1 // firmware implements Virtual Memory System Architecture, i.e. has MMU 14 15 // for clarity of thumb bit manipulations 16 #define ADR_SET_THUMB(x) ((x)|1) 17 #define ADR_CLEAR_THUMB(x) ((x)&~1) 18 #define ADR_IS_THUMB(x) ((x)&1) 19 20 #define ADR_ALIGN4(x) ((x)&~0x3) 21 #define ADR_ALIGN2(x) ((x)&~0x1) 22 23 #define ADR_IS_ALIGN4(x) (((x)&0x3)==0) 24 25 // address regions 26 #define ADR_RANGE_INVALID 0 27 #define ADR_RANGE_ROM 1 28 #define ADR_RANGE_RAM_CODE 2 29 #define ADR_RANGE_INIT_DATA 3 30 31 #define ADR_RANGE_FL_NONE 0 32 #define ADR_RANGE_FL_TCM 1 // TCM 33 #define ADR_RANGE_FL_EVEC 2 // exception vector 34 35 // Stores a range of valid data in the firmware dump (used to skip over empty blocks) 36 typedef struct bufrange { 37 uint32_t *p; 38 int off; // NOTE these are in 32 bit blocks, not bytes 39 int len; 40 struct bufrange* next; 41 } BufRange; 42 43 44 // TODO may want to make run-time adjustable 45 #define ADR_HIST_SIZE 64 46 typedef struct { 47 // circular buffer of previous adr values, for backtracking 48 // use addresses rather than insn, because you might want to scan with detail off and then backtrack with on 49 // addresses have thumb bit set when disassembling in thumb mode 50 int cur; // index of current address, after iter 51 int count; // total number of valid entries 52 uint32_t adrs[ADR_HIST_SIZE]; 53 } adr_hist_t; 54 55 // state for disassembly iteration 56 typedef struct { 57 const uint8_t *code; // pointer into buffer for code 58 uint64_t adr; // firmware address - must be 64 bit for capstone iter, never has thumb bit set 59 // points to the next instruction to disassemble, insn->address gives the most 60 // recently disassembled address 61 size_t size; // remaining code size 62 cs_insn *insn; // cached instruction 63 uint32_t thumb; // thumb state 64 uint32_t insn_min_size; // 2 or 4, depending on thumb/arm state 65 csh cs_handle; // capstone handle to use with this state, updated for arm/thumb transitions 66 adr_hist_t ah; // history of previous instructions 67 } iter_state_t; 68 69 // struct for regions of ROM that are copied elsewhere 70 typedef struct { 71 uint8_t *buf; 72 uint32_t start; // copied / relocated firmware address 73 uint32_t src_start; // source ROM firmware address 74 int bytes; // size in bytes 75 int type; // ADR_RANGE_* define 76 int flags; // ADR_RANGE_FL_* 77 } adr_range_t; 78 79 #define FW_MAX_ADR_RANGES 10 80 81 #define FW_MAX_DRYOS_VERS 10 82 83 // scale factor for combined version + patch 84 #define FW_DRYOS_VER_MUL 100 85 86 // loaded firmware 87 typedef struct { 88 union { 89 uint8_t *buf8; // Firmware data 90 uint32_t *buf32; // Firmware data 91 }; 92 BufRange *br, *last; // Valid ranges 93 94 int arch; // firmware CPU arch, set by caller at load time 95 int arch_flags; // additional CPU arch information, inferred 96 uint32_t base; // Base address of the firmware in the camera 97 int main_offs; // Offset of main firmware from the start of the dump 98 99 uint32_t memisostart; // Start address of the Canon heap memory (where CHDK is loaded) 100 101 int size8; // Size of the firmware (as loaded from the dump) in bytes 102 int size32; // Size of the firmware in 32 bit words 103 104 int dryos_ver; // main firmware DryOS version number 105 int dryos_ver_patch; // main firmware DryOS patch number (e.g 58p3 = 3) 106 int dryos_ver_full; // main firmware DryOS version number * FW_DRYOS_VER_MUL + patch level 107 const char *dryos_ver_str; // main firmware DryOS version string 108 uint32_t dryos_ver_adr; // address of main firmware DryOS version string 109 uint32_t dryos_ver_ref_adr; // address of pointer used to identify main fw string 110 uint32_t dryos_ver_list[FW_MAX_DRYOS_VERS]; // addresses of all found DryOS version strings 111 uint32_t dryos_ver_count; // number of version strings found 112 113 char *firmware_ver_str; // Camera firmware version string 114 115 // TODO duplicated with adr_range stuff below 116 uint32_t data_start; // Start address of DATA section in RAM 117 uint32_t data_init_start; // Start address of initialisation section for DATA in ROM 118 int data_len; // Length of data section in bytes 119 120 // address ranges for ROM and copied data 121 int adr_range_count; 122 adr_range_t adr_ranges[FW_MAX_ADR_RANGES]; 123 124 // convenience values to optimize code searching 125 uint32_t rom_code_search_min_adr; // minimum ROM address for normal code searches (i.e. firmware start) 126 uint32_t rom_code_search_max_adr; // max ROM address for normal code searches, i.e. before copied data / code if known 127 // Values loaded from stubs & other files 128 stub_values *sv; 129 130 uint32_t thumb_default; // 1 if initial firmware code is expected to be thumb, 0 for arm. 131 csh cs_handle_thumb; // capstone handle for thumb disassembly 132 csh cs_handle_arm; // capstone handle for arm disassembly 133 iter_state_t* is; 134 } firmware; 135 136 /* 137 convert firmware address to pointer, or NULL if not in valid range 138 */ 139 uint8_t* adr2ptr(firmware *fw, uint32_t adr); 140 141 // as above, but include initialized data area (NOTE may change on camera at runtime!) 142 uint8_t* adr2ptr_with_data(firmware *fw, uint32_t adr); 143 144 // return constant string describing type 145 const char* adr_range_type_str(int type); 146 147 // return constant string describing type + flags 148 const char* adr_range_desc_str(adr_range_t *r); 149 150 // convert pointer into buf into firmware address 151 // current doesn't sanity check or adjust ranges 152 uint32_t ptr2adr(firmware *fw, uint8_t *ptr); 153 154 // return address range struct for adr, or NULL if not in known range 155 adr_range_t *adr_get_range(firmware *fw, uint32_t adr); 156 157 // return what kind of range adr is in 158 int adr_get_range_type(firmware *fw, uint32_t adr); 159 160 // return true if adr is in firmware DATA or BSS 161 int adr_is_var(firmware *fw, uint32_t adr); 162 163 // return true if adr is in the ROM search range, or one of the copied RAM code regions 164 int adr_is_main_fw_code(firmware *fw, uint32_t adr); 165 166 // 167 // Find the index of a string in the firmware 168 // Assumes the string starts on a 32bit boundary. 169 // String + terminating zero byte should be at least 4 bytes long 170 // Handles multiple string instances 171 int find_Nth_str(firmware *fw, char *str, int N); 172 173 // above, N=1 174 int find_str(firmware *fw, char *str); 175 176 // find sequence of bytes, starting from star_adr, up to max_adr, any alignment 177 // returns firmware address or 0 178 // use repeated calls to find multiple 179 // NOTE only handles ROM addresses 180 uint32_t find_next_bytes_range(firmware *fw, const void *bytes, size_t len, uint32_t start_adr, uint32_t max_adr); 181 182 // find up to maxmatch matching byte sequences, storing addresses in result 183 // returns count 184 int find_bytes_all(firmware *fw, const void *bytes, size_t len, uint32_t adr, uint32_t *result, int maxmatch); 185 186 // find index of string, starting from address, str can start at any address 187 // returns firmware address or 0 188 // use repeated calls to find multiple 189 // NOTE only handles ROM addresses 190 uint32_t find_next_str_bytes(firmware *fw, const char *str, uint32_t adr); 191 192 // as above, but ending within range of LDR pc or ADR from main fw code 193 uint32_t find_next_str_bytes_main_fw(firmware *fw, const char *str, uint32_t adr); 194 195 // as find_next_str_bytes, but without terminating null 196 uint32_t find_next_substr_bytes(firmware *fw, const char *str, uint32_t adr); 197 198 // find a string within range of LDR pc or ADR, starting from main fw 199 // i.e., a string directly referenced from main code 200 uint32_t find_str_bytes_main_fw(firmware *fw, const char *str); 201 202 // as find_next_str_bytes, first match 203 uint32_t find_str_bytes(firmware *fw, const char *str); 204 205 int isASCIIstring(firmware *fw, uint32_t adr); 206 207 /* 208 return firmware address of 32 bit value, starting at address "start", up to "maxadr" 209 */ 210 uint32_t find_u32_adr_range(firmware *fw, uint32_t val, uint32_t start, uint32_t maxadr); 211 212 /* 213 return firmware address of 32 bit value, starting at address "start", to end of dump 214 */ 215 uint32_t find_u32_adr(firmware *fw, uint32_t val, uint32_t start); 216 217 // return u32 value at adr 218 uint32_t fw_u32(firmware *fw, uint32_t adr); 219 220 // memcmp, but using a firmware address, returning 1 adr/size out of range 221 int fw_memcmp(firmware *fw, uint32_t adr,const void *cmp, size_t n); 222 223 // ****** address history functions ****** 224 // reset address history to empty 225 void adr_hist_reset(adr_hist_t *ah); 226 227 // return the index of current entry + i. may be negative or positive, wraps. Does not check validity 228 int adr_hist_index(adr_hist_t *ah, int i); 229 230 // add an entry to address history 231 void adr_hist_add(adr_hist_t *ah, uint32_t adr); 232 233 // return the i'th previous entry in this history, or 0 if not valid (maybe should be -1?) 234 // i= 0 = most recently disassembled instruction, if any 235 uint32_t adr_hist_get(adr_hist_t *ah, int i); 236 237 // ****** instruction analysis utilities ****** 238 // handle varying instruction ID enums in different capstone versions 239 // note these take an arm_insn enum, NOT a cs_insn * 240 #if CS_API_MAJOR < 4 241 // is insn_id a full reg MOV (does not include MOVT) 242 #define IS_INSN_ID_MOVx(insn_id) ((insn_id) == ARM_INS_MOV || (insn_id) == ARM_INS_MOVS || (insn_id) == ARM_INS_MOVW) 243 // is insn_id a a sub* 244 #define IS_INSN_ID_SUBx(insn_id) ((insn_id) == ARM_INS_SUB || (insn_id) == ARM_INS_SUBW || (insn_id) == ARM_INS_SUBS) 245 #else 246 #define IS_INSN_ID_MOVx(insn_id) ((insn_id) == ARM_INS_MOV || (insn_id) == ARM_INS_MOVW) 247 #define IS_INSN_ID_SUBx(insn_id) ((insn_id) == ARM_INS_SUB || (insn_id) == ARM_INS_SUBW) 248 #endif 249 250 251 // is insn an ARM instruction? 252 // like cs_insn_group(cs_handle,insn,ARM_GRP_ARM) but doesn't require handle and doesn't check or report errors 253 int isARM(cs_insn *insn); 254 255 /* 256 is insn a PC relative load? 257 */ 258 int isLDR_PC(cs_insn *insn); 259 260 /* 261 is insn a PC relative load to PC? 262 */ 263 int isLDR_PC_PC(cs_insn *insn); 264 265 // if insn is LDR Rn, [pc,#x] return pointer to value, otherwise null 266 uint32_t* LDR_PC2valptr_thumb(firmware *fw, cs_insn *insn); 267 uint32_t* LDR_PC2valptr_arm(firmware *fw, cs_insn *insn); 268 uint32_t* LDR_PC2valptr(firmware *fw, cs_insn *insn); 269 270 // return the address of value loaded by LDR rd, [pc, #x] or 0 if not LDR PC 271 uint32_t LDR_PC2adr(firmware *fw, cs_insn *insn); 272 273 // is insn address calculated with subw rd, pc, ... 274 int isSUBW_PC(cs_insn *insn); 275 276 // is insn address calculated with addw rd, pc, ... 277 int isADDW_PC(cs_insn *insn); 278 279 // is insn ADD rd, pc, #x (only generated for ARM in capstone) 280 int isADD_PC(cs_insn *insn); 281 282 // is insn SUB rd, pc, #x (only generated for ARM in capstone) 283 int isSUB_PC(cs_insn *insn); 284 285 // does insn look like a function return? 286 int isRETx(cs_insn *insn); 287 288 // does insn push LR (function start -ish) 289 int isPUSH_LR(cs_insn *insn); 290 291 // does insn pop LR (func end before tail call) 292 int isPOP_LR(cs_insn *insn); 293 294 // does insn pop PC 295 int isPOP_PC(cs_insn *insn); 296 297 // is the instruction ADD* rx, imm 298 int isADDx_imm(cs_insn *insn); 299 300 // is the instruction SUB* rx, imm 301 int isSUBx_imm(cs_insn *insn); 302 303 // is the instruction an ADR or ADR-like instruction? 304 int isADRx(cs_insn *insn); 305 306 // return value generated by an ADR or ADR-like instruction, or 0 (which should be rarely generated by ADR) 307 uint32_t ADRx2adr(firmware *fw, cs_insn *insn); 308 309 // return the value generated by an ADR (ie, the location of the value as a firmware address) 310 // NOTE not checked if it is in dump 311 uint32_t ADR2adr(firmware *fw, cs_insn *insn); 312 313 // if insn is adr/ AKA ADD Rn, pc,#x return pointer to value, otherwise null 314 uint32_t* ADR2valptr(firmware *fw, cs_insn *insn); 315 316 // return value loaded by PC relative LDR instruction, or 0 if out of range 317 uint32_t LDR_PC2val(firmware *fw, cs_insn *insn); 318 319 // return the target of B instruction, or 0 if current instruction isn't B 320 // both ARM and thumb instructions will NOT have the thumb bit set, 321 // thumbness must be determined from current state 322 uint32_t B_target(firmware *fw, cs_insn *insn); 323 324 // return the target of CBZ / CBNZ instruction, or 0 if current instruction isn't CBx 325 uint32_t CBx_target(firmware *fw, cs_insn *insn); 326 327 // return the target of BLX instruction, or 0 if current instruction isn't BLX imm 328 uint32_t BLXimm_target(firmware *fw, cs_insn *insn); 329 330 // return the target of BL instruction, or 0 if current instruction isn't BL 331 // both ARM and thumb instructions will NOT have the thumb bit set, 332 // thumbness must be determined from current state 333 uint32_t BL_target(firmware *fw, cs_insn *insn); 334 335 // as above, but also including B for tail calls 336 uint32_t B_BL_target(firmware *fw, cs_insn *insn); 337 338 // as above, but also including BLX imm 339 uint32_t B_BL_BLXimm_target(firmware *fw, cs_insn *insn); 340 341 // BX PC (mode change, small jump) Does NOT set thumb bit 342 uint32_t BX_PC_target(__attribute__ ((unused))firmware *fw, cs_insn *insn); 343 344 // results from get_TBx_PC_info 345 typedef struct { 346 uint32_t start; // address of first jumptable entry 347 uint32_t count; // number of entries, from preceding cmp, first_target or first invalid value 348 uint32_t first_target; // lowest jumptable target address (presumably, >= end of jump table in normal code) 349 int bytes; // size of jump table entries: 1 = tbb, 2=tbh 350 } tbx_info_t; // tbb/tbh info 351 352 // get the (likely) range of jumptable entries from a pc relative TBB or TBH instruction 353 // returns 0 on error or if instruction is not TBB/TBH, otherwise 1 354 int get_TBx_PC_info(firmware *fw,iter_state_t *is, tbx_info_t *ti); 355 356 // ****** disassembly iterator utilities ****** 357 // allocate a new iterator state, optionally initializing at adr (0/invalid OK) 358 iter_state_t *disasm_iter_new(firmware *fw, uint32_t adr); 359 360 // free iterator state and associated resources 361 void disasm_iter_free(iter_state_t *is); 362 363 // set iterator to adr, without clearing history (for branch following) 364 // thumb bit in adr sets mode 365 int disasm_iter_set(firmware *fw, iter_state_t *is, uint32_t adr); 366 367 // initialize iterator state at adr, clearing history 368 // thumb bit in adr sets mode 369 int disasm_iter_init(firmware *fw, iter_state_t *is, uint32_t adr); 370 371 /* 372 disassemble next instruction, recording address in history 373 returns false if state invalid or disassembly fails 374 if disassembly fails, is->adr is not incremented 375 */ 376 int disasm_iter(firmware *fw, iter_state_t *is); 377 378 // ***** disassembly utilities operating on the default iterator state ***** 379 // use the fw_disasm_iter functions to disassemble without setting up a new state, 380 // but beware some other functions might change them 381 /* 382 initialize iter state to begin iterating at adr 383 */ 384 int fw_disasm_iter_start(firmware *fw, uint32_t adr); 385 386 // disassemble the next instruction, updating cached state 387 int fw_disasm_iter(firmware *fw); 388 389 // disassemble single instruction at given adr, updating cached values 390 // history is cleared 391 int fw_disasm_iter_single(firmware *fw, uint32_t adr); 392 393 // ****** standalone disassembly without an iter_state ****** 394 /* 395 disassemble up to count instructions starting at firmware address adr 396 allocates and returns insns in insn, can be freed with cs_free(insn, count) 397 returns actual number disassembled, less than count on error 398 */ 399 // UNUSED for now 400 //size_t fw_disasm_adr(firmware *fw, uint32_t adr, unsigned count, cs_insn **insn); 401 402 403 // ***** utilities for searching disassembly over large ranges ****** 404 /* 405 callback used by fw_search_insn, called on valid instructions 406 _search continues iterating until callback returns non-zero. 407 is points to the most recently disassembled instruction 408 callback may advance is directly by calling disasm_iter 409 v1 and udata are passed through from the call to _search 410 */ 411 typedef uint32_t (*search_insn_fn)(firmware *fw, iter_state_t *is, uint32_t v1, void *udata); 412 413 /* 414 iterate over firmware disassembling, calling callback described above after each 415 successful disassembly iteration. If disassembly fails, the iter state is advanced 416 2 bytes without calling the callback. 417 starts at address is taken from the iter_state, which should be initialized by disasm_iter_new() 418 disasm_iter_init(), or a previous search or iter call. 419 end defaults to end of ram code or rom code (before init data, if known), based on start 420 v1 and udata are provided to the callback 421 */ 422 uint32_t fw_search_insn(firmware *fw, iter_state_t *is, search_insn_fn f,uint32_t v1, void *udata, uint32_t adr_end); 423 424 // ****** callbacks for use with fw_search_insn ****** 425 // search for constant references 426 uint32_t search_disasm_const_ref(firmware *fw, iter_state_t *is, uint32_t val, void *unused); 427 428 // search for string ref 429 uint32_t search_disasm_str_ref(firmware *fw, iter_state_t *is, uint32_t val, void *str); 430 431 // search for calls/jumps to immediate addresses 432 // thumb bit in address should be set appropriately 433 // returns 1 if found, address can be obtained from insn 434 uint32_t search_disasm_calls(firmware *fw, iter_state_t *is, uint32_t val, void *unused); 435 436 // callback for use with search_disasm_calls_multi 437 // adr is the matching address 438 typedef int (*search_calls_multi_fn)(firmware *fw, iter_state_t *is, uint32_t adr); 439 440 // structure used to define functions searched for, and functions to handle matches 441 // fn should be address with thumb bit set appropriately 442 typedef struct { 443 uint32_t adr; 444 search_calls_multi_fn fn; 445 } search_calls_multi_data_t; 446 447 // a search_calls_multi_fn that just returns 1 448 int search_calls_multi_end(firmware *fw, iter_state_t *is, uint32_t adr); 449 450 // Search for calls to multiple functions (more efficient than multiple passes) 451 // if adr is found in null terminated search_calls_multi_data array, returns fn return value 452 // otherwise 0 453 uint32_t search_disasm_calls_multi(firmware *fw, iter_state_t *is, uint32_t unused, void *userdata); 454 455 // as above, but check for single level of veneers 456 uint32_t search_disasm_calls_veneer_multi(firmware *fw, iter_state_t *is, uint32_t unused, void *userdata); 457 458 // ****** utilities for extracting register values ****** 459 /* 460 backtrack through is_init state history picking up constants loaded into r0-r3 461 return bitmask of regs with values found 462 affects fw->is, does not affect is_init 463 464 NOTE values may be inaccurate for many reasons, doesn't track all reg affecting ops, 465 doesn't account for branches landing in the middle of inspected code 466 doesn't account for many conditional cases 467 */ 468 int get_call_const_args(firmware *fw, iter_state_t *is_init, int max_backtrack, uint32_t *res); 469 470 /* 471 starting from is_init, look for a direct jump, such as 472 B <target> 473 LDR PC, [pc, #x] 474 BX PC 475 movw ip, #x 476 movt ip, #x 477 bx ip 478 if found, return target address with thumb bit set appropriately 479 NOTE does not check for conditional 480 uses fw->is 481 does not check CBx, since it would generally be part of a function not a veneer 482 */ 483 uint32_t get_direct_jump_target(firmware *fw, iter_state_t *is_init); 484 485 /* 486 return target of any single instruction branch or function call instruction, 487 with thumb bit set appropriately 488 returns 0 if current instruction not branch/call 489 */ 490 uint32_t get_branch_call_insn_target(firmware *fw, iter_state_t *is); 491 492 /* 493 search up to max_search_ins for first LDR, =value 494 and then match up to max_seq_insns for a sequence like 495 LDR Rbase,=adr 496 ... possible intervening ins 497 SUB Rbase,#adj // optional, may be any add/sub variant 498 ... possible intervening ins 499 LDR Rval,[Rbase + #off] 500 501 returns 1 if found, 0 if not 502 stores registers and constants in *result if successful 503 504 NOTE bad values are possible with intervening ins, short sequences recommended 505 506 TODO similar code for STR would be useful, but in many cases would have to handle load or move into reg_val 507 */ 508 typedef struct { 509 arm_reg reg_base; 510 arm_reg reg_val; 511 uint32_t adr_base; // address from original LDR 512 uint32_t adr_adj; // address adjusted by adj if present, normally struct address useful for stubs comments 513 uint32_t adr_final; // full address 514 // offsets are guaranteed to be small 515 int adj; 516 int off; 517 } var_ldr_desc_t; 518 int find_and_get_var_ldr(firmware *fw, 519 iter_state_t *is, 520 int max_search_insns, 521 int max_seq_insns, 522 arm_reg match_val_reg, // ARM_REG_INVALID for any 523 var_ldr_desc_t *result); 524 525 /* 526 check for, and optionally return information about 527 functions with return values that can be completely determined 528 from disassembly 529 uses fw->is 530 */ 531 // constants below may as flags on input, and as return valaue 532 // no simple function found 533 #define MATCH_SIMPLE_FUNC_NONE 0x0 534 // immediately returns, with no value 535 #define MATCH_SIMPLE_FUNC_NULLSUB 0x1 536 // immediately returns with a MOV constant 537 #define MATCH_SIMPLE_FUNC_IMM 0x2 538 // TODO LDR pc, =const, ADR 539 // TODO could also do pointer derefs and return pointer info without val 540 #define MATCH_SIMPLE_FUNC_ANY 0x3 541 typedef struct { 542 int ftype; 543 uint32_t retval; 544 } simple_func_desc_t; 545 int check_simple_func(firmware *fw, uint32_t adr, int match_ftype, simple_func_desc_t *info); 546 547 /* 548 advance iter_state is trying to find the last function called by a function 549 function assumed to PUSH LR, POP LR or PC (many small functions don't!) 550 either the last BL/BLXimm before pop {... PC} 551 or B after POP {... LR} 552 MOV or LDR to R0-R3 are allowed between POP LR and the final B 553 If a POP occurs before min_insns, the match fails 554 Calls before min_insns are ignored 555 */ 556 uint32_t find_last_call_from_func(firmware *fw, iter_state_t *is,int min_insns, int max_insns); 557 558 // ****** utilities for matching instructions and instruction sequences ****** 559 560 // use XXX_INVALID (=0) for don't care 561 typedef struct { 562 arm_op_type type; // ARM_OP_... REG, IMM, MEM support additional tests 563 arm_reg reg1; // reg for register type operands, base for mem 564 uint32_t flags; // 565 int32_t imm; // immediate value for imm, disp for mem 566 arm_reg reg2; // index reg form mem, or second reg for reg range 567 } op_match_t; 568 #define MATCH_OP_FL_IMM 0x0001 // use IMM value 569 #define MATCH_OP_FL_LAST 0x0002 // ignore all following ops, only check count 570 // macros for initializing above 571 // type reg1 flags imm reg2 572 #define MATCH_OP_ANY {ARM_OP_INVALID,ARM_REG_INVALID, 0, 0, ARM_REG_INVALID} 573 #define MATCH_OP_REST_ANY {ARM_OP_INVALID,ARM_REG_INVALID, MATCH_OP_FL_LAST, 0, ARM_REG_INVALID} 574 #define MATCH_OP_REG_ANY {ARM_OP_REG, ARM_REG_INVALID, 0, 0, ARM_REG_INVALID} 575 #define MATCH_OP_REG(r) {ARM_OP_REG, ARM_REG_##r, 0, 0, ARM_REG_INVALID} 576 #define MATCH_OP_REG_RANGE(r1,r2) {ARM_OP_REG, ARM_REG_##r1, 0, 0, ARM_REG_##r2} 577 #define MATCH_OP_IMM_ANY {ARM_OP_IMM, ARM_REG_INVALID, 0, 0, ARM_REG_INVALID} 578 #define MATCH_OP_IMM(imm) {ARM_OP_IMM, ARM_REG_INVALID, MATCH_OP_FL_IMM, (imm), ARM_REG_INVALID} 579 #define MATCH_OP_PIMM_ANY {ARM_OP_PIMM, ARM_REG_INVALID, 0, 0, ARM_REG_INVALID} 580 #define MATCH_OP_PIMM(imm) {ARM_OP_PIMM, ARM_REG_INVALID, MATCH_OP_FL_IMM, (imm), ARM_REG_INVALID} 581 #define MATCH_OP_CIMM_ANY {ARM_OP_CIMM, ARM_REG_INVALID, 0, 0, ARM_REG_INVALID} 582 #define MATCH_OP_CIMM(imm) {ARM_OP_CIMM, ARM_REG_INVALID, MATCH_OP_FL_IMM, (imm), ARM_REG_INVALID} 583 #define MATCH_OP_MEM_ANY {ARM_OP_MEM, ARM_REG_INVALID, 0, 0, ARM_REG_INVALID} 584 #define MATCH_OP_MEM(rb,ri,imm) {ARM_OP_MEM, ARM_REG_##rb, MATCH_OP_FL_IMM, (imm), ARM_REG_##ri} 585 #define MATCH_OP_MEM_BASE(r) {ARM_OP_MEM, ARM_REG_##r, 0, 0, ARM_REG_INVALID} 586 #define MATCH_OP_MEM_REGS(rb,ri) {ARM_OP_MEM, ARM_REG_##rb, 0, 0, ARM_REG_##ri} 587 588 #define MATCH_MAX_OPS 16 589 590 #define MATCH_OPCOUNT_ANY -1 // match any operands specified in operands, without checking count 591 #define MATCH_OPCOUNT_IGNORE -2 // don't check ops at all 592 593 #define MATCH_INS(ins,opcount) ARM_INS_##ins,(opcount),ARM_CC_INVALID 594 #define MATCH_INS_CC(ins,cc,opcount) ARM_INS_##ins,(opcount),ARM_CC_##cc 595 596 // use id ARM_INS_INVALID for don't care, ARM_INS_ENDING to end list of matches 597 typedef struct { 598 arm_insn id; 599 int op_count; // negative = special values above 600 arm_cc cc; // match condition code _INVALID = don't care 601 op_match_t operands[MATCH_MAX_OPS]; 602 } insn_match_t; 603 604 // some common matches for insn_match_find_next 605 // match a B instruction 606 extern const insn_match_t match_b[]; 607 608 // match a BL instruction 609 extern const insn_match_t match_bl[]; 610 611 // match B and BL 612 extern const insn_match_t match_b_bl[]; 613 614 // match B and BL, and BLX with an immediate 615 extern const insn_match_t match_b_bl_blximm[]; 616 617 // match only calls: BL or BLX imm 618 extern const insn_match_t match_bl_blximm[]; 619 620 // match BX LR 621 extern const insn_match_t match_bxlr[]; 622 623 // match BX <any reg> 624 extern const insn_match_t match_bxreg[]; 625 626 // match BLX <any reg> 627 extern const insn_match_t match_blxreg[]; 628 629 // match LDR rx [pc, ...] 630 extern const insn_match_t match_ldr_pc[]; 631 632 // check if single insn matches values defined by match 633 int insn_match(cs_insn *insn, const insn_match_t *match); 634 635 // check if single insn matches any of the provided matches 636 int insn_match_any(cs_insn *insn,const insn_match_t *match); 637 638 // iterate is until current instruction matches any of the provided matches or until limit reached 639 int insn_match_find_next(firmware *fw, iter_state_t *is, int max_insns, const insn_match_t *match); 640 641 // iterate is until current has matched any of the provided matches N times or until max_insns reached 642 int insn_match_find_nth(firmware *fw, iter_state_t *is, int max_insns, int num_to_match, const insn_match_t *match); 643 644 // iterate as long as sequence of instructions matches sequence defined in match 645 int insn_match_seq(firmware *fw, iter_state_t *is, const insn_match_t *match); 646 647 // find next matching sequence starting within max_insns 648 int insn_match_find_next_seq(firmware *fw, iter_state_t *is, int max_insns, const insn_match_t *match); 649 650 #define FIND_CONST_REF_MATCH_ANY 0 651 #define FIND_CONST_REF_MATCH_SEQ 1 652 /* 653 find instruction or sequence that receives specified constant in specified r0-r3 reg 654 search starting from is to max_search_bytes 655 allow up to max_gap_insns between constant load and match, generally small (4-8 max) 656 returns address of match with thumb bit set according to mode, or 0 on failure 657 modifies is and fw->is 658 */ 659 int find_const_ref_match(firmware *fw, 660 iter_state_t *is, 661 int max_search_bytes, 662 int max_gap_insns, 663 arm_reg match_reg, // must be R0-R3 664 uint32_t val, 665 const insn_match_t *match, 666 int match_type); 667 668 /* 669 find call that receives specified constant in specified r0-r3 reg 670 search starting from is to max_search_bytes 671 allow up to max_gap_insns between constant load and call, generally small (4-8 max) 672 returns address of call with thumb bit set according to mode, or 0 on failure 673 modifies is and fw->is 674 */ 675 int find_const_ref_call(firmware *fw, 676 iter_state_t *is, 677 int max_search_bytes, 678 int max_gap_insns, // insns between ref and call 679 arm_reg match_reg, // must be R0-R3 680 uint32_t val); 681 682 683 // ****** utilities for non-disasm searching ****** 684 // Search the firmware for something. The desired matching is performed using the supplied 'func' function. 685 // Continues searching until 'func' returns non-zero - then returns 1 686 // otherwise returns 0. 687 // Uses the BufRange structs to speed up searching 688 // Note: this version searches byte by byte in the firmware dump instead of by words 689 // borrowed from finsig_dryos 690 typedef int (*search_bytes_fn)(firmware*, int k); 691 int fw_search_bytes(firmware *fw, search_bytes_fn func); 692 693 // ****** firmware loading / initialization / de-allocation ****** 694 // add given address range 695 void fw_add_adr_range(firmware *fw, uint32_t start, uint32_t end, uint32_t src_start, int type, int flags); 696 697 // load firmware and initialize stuff that doesn't require disassembly 698 void firmware_load(firmware *fw, const char *filename, uint32_t base_adr,int fw_arch); 699 700 // initialize capstone state for loaded fw 701 int firmware_init_capstone(firmware *fw); 702 703 // init basic copied RAM code / data ranges - init_capstone must be called first 704 void firmware_init_data_ranges(firmware *fw); 705 706 // free resources associated with fw 707 void firmware_unload(firmware *fw); 708 709 // get iter_state instruction address with optional thumb bit 710 #define iter_state_adr(is) ((uint32_t)is->insn->address | is->thumb) 711 #endif