def resolveCallingAddressBackwards(self, func, target, start, end): ''' start is callingAddr end is curFun.start ''' pc = start pc = idc.prev_head(pc, 0) while pc > end: opcode = idc.GetMnem(pc) opTarget = idc.print_operand(pc, 0) # print hex(pc) # print opcode # print target # print '\n' value = None if opcode in self.collectRegMnem and opTarget == target: return None if opcode in self.assignRegMnem and opTarget == target: if opcode == 'MOV': nextTarget = idc.print_operand(pc, 1) return self.resolveCallingAddressBackwards(func, nextTarget, pc, end) elif opcode == 'LDR': dataref = list(idautils.DataRefsFrom(pc))[0] value = idc.print_operand(dataref, 0) return value pc = idc.prev_head(pc, 0) return None
def find_all_ioctls(): """ From the currently selected address attempts to traverse all blocks inside the current function to find all immediate values which are used for a comparison/sub immediately before a jz. Returns a list of address, second operand pairs. """ ioctls = [] # Find the currently selected function and get a list of all of it's basic blocks addr = idc.get_screen_ea() f = idaapi.get_func(addr) fc = idaapi.FlowChart(f, flags=idaapi.FC_PREDS) for block in fc: # grab the last two instructions in the block last_inst = idc.prev_head(block.end_ea) penultimate_inst = idc.prev_head(last_inst) # If the penultimate instruction is cmp or sub against an immediate value immediately preceding a 'jz' # then it's a decent guess that it's an IOCTL code (if this is a dispatch function) if idc.print_insn_mnem(penultimate_inst) in [ 'cmp', 'sub' ] and idc.get_operand_type(penultimate_inst, 1) == 5: if idc.print_insn_mnem(last_inst) == 'jz': value = get_operand_value(penultimate_inst) ioctls.append((penultimate_inst, value)) ioctl_tracker.add_ioctl(penultimate_inst, value) return ioctls
def get_protocols(self): """found UEFI protocols information in idb""" for service_name in self.gBServices: for address in self.gBServices[service_name]: ea, found = address, False if self.arch == 'x86': for _ in range(1, 25): ea = idc.prev_head(ea) if (idc.get_operand_value(ea, 0) > self.base and idc.print_insn_mnem(ea) == 'push'): found = True break if self.arch == 'x64': for _ in range(1, 16): ea = idc.prev_head(ea) if (idc.get_operand_value(ea, 1) > self.base and idc.print_insn_mnem(ea) == 'lea'): found = True break if not found: continue for xref in idautils.DataRefsFrom(ea): if idc.print_insn_mnem(xref): continue if not check_guid(xref): continue cur_guid = get_guid(xref) record = { 'address': xref, 'service': service_name, 'guid': cur_guid, } if not self.Protocols['all'].count(record): self.Protocols['all'].append(record)
def main(): print("[*] loading crypto constants") for const in non_sparse_consts: const["byte_array"] = convert_to_byte_array(const) for start in idautils.Segments(): print("[*] searching for crypto constants in %s" % idc.get_segm_name(start)) ea = start while ea < idc.get_segm_end(start): bbbb = list(struct.unpack("BBBB", idc.get_bytes(ea, 4))) for const in non_sparse_consts: if bbbb != const["byte_array"][:4]: continue if map(lambda x:ord(x), idc.get_bytes(ea, len(const["byte_array"]))) == const["byte_array"]: print(("0x%0" + str(digits) + "X: found const array %s (used in %s)") % (ea, const["name"], const["algorithm"])) idc.set_name(ea, const["name"]) if const["size"] == "B": idc.create_byte(ea) elif const["size"] == "L": idc.create_dword(ea) elif const["size"] == "Q": idc.create_qword(ea) idc.make_array(ea, len(const["array"])) ea += len(const["byte_array"]) - 4 break ea += 4 ea = start if idc.get_segm_attr(ea, idc.SEGATTR_TYPE) == 2: while ea < idc.get_segm_end(start): d = ida_bytes.get_dword(ea) for const in sparse_consts: if d != const["array"][0]: continue tmp = ea + 4 for val in const["array"][1:]: for i in range(8): if ida_bytes.get_dword(tmp + i) == val: tmp = tmp + i + 4 break else: break else: print(("0x%0" + str(digits) + "X: found sparse constants for %s") % (ea, const["algorithm"])) cmt = idc.get_cmt(idc.prev_head(ea), 0) if cmt: idc.set_cmt(idc.prev_head(ea), cmt + ' ' + const["name"], 0) else: idc.set_cmt(idc.prev_head(ea), const["name"], 0) ea = tmp break ea += 1 print("[*] finished")
def trace_rep_mov(stack_var, loc, func_ea, state): """ Helper function to trace back a rep mov """ loc = idc.prev_head(loc) while loc != func_ea: mnem = idc.print_insn_mnem(loc) if mnem == 'lea' and idc.print_operand(loc, 0) == 'edi': if stack_var == get_operand_value_replacement(loc, 1, state): return trace_register('esi', loc, func_ea, state) return None loc = idc.prev_head(loc) return None
def get_stacked_bytes(dec_func_addr): func_stacked_bytes_addr_dict = {} xrefs = idautils.CodeRefsTo(dec_func_addr, 0) for xref in xrefs: prev_addr = idc.prev_head(xref) prev_addr_2 = idc.prev_head(prev_addr) if idc.print_insn_mnem(prev_addr_2) == "call": func_name = idc.print_operand(prev_addr_2, 0) func_addr = idc.get_name_ea_simple(func_name) func_stacked_bytes_addr_dict[xref] = func_addr # enc_mod_addr = list(set(enc_mod_addr)) # [Debug] Get unique functions only for xref, stacked_bytes_addr in func_stacked_bytes_addr_dict.items(): print(f"Address: {hex(stacked_bytes_addr)}") func_ea = idc.get_func_attr(stacked_bytes_addr, idc.FUNCATTR_START) bytes_collected = bytearray() # Collected stack string store here for ins in idautils.FuncItems(func_ea): if ida_bytes.is_code(ida_bytes.get_full_flags(ins)): if idc.print_insn_mnem(ins) == "mov": if idc.get_operand_type(ins, 1) == idc.o_imm: # disasm = idc.GetDisasm(ins) # [Debug] hex_str_len = len( idc.print_operand(ins, 1).lstrip("0").rstrip("h")) const_hex_byte = idc.print_operand( ins, 1).lstrip("0").rstrip("h") if hex_str_len != 8: # Skip if const hex byte less than 8 append_zero = "0" * (8 - hex_str_len) const_hex_byte = append_zero + const_hex_byte # print(struct.pack("<I", int(const_hex_byte, 16))) # [Debug] # else: # print(struct.pack("<I", int(const_hex_byte, 16))) # [Debug] bytes_collected += struct.pack("<I", int(const_hex_byte, 16)) if len(bytes_collected) >= 1: cmt_str = "" if dec_func_addr == 0x10001253: # fn_name_addr print(f"{decode_fnname(bytes_collected[4:])}") cmt_str = decode_fnname(bytes_collected[4:]) elif dec_func_addr == 0x1000122B: # mod_name_addr print(f"{decode_modname(bytes_collected[4:])}") cmt_str = decode_modname(bytes_collected[4:]) idc.set_cmt(xref, cmt_str, 1) # Comment near xref decoder function else: print(f"[-] {hex(stacked_bytes_addr)} addr error")
def ret_vals(bbl): iaddr = idc.prev_head(bbl.end_ea) while idc.next_head(iaddr) != bbl.start_ea: if is_eax_written(iaddr) and is_nothing_read(iaddr): return [idc.get_operand_value(iaddr, 1)] if is_eax_read(iaddr): return [] iaddr = idc.prev_head(iaddr) ret = [] for bb in bbl.preds(): ret = ret + ret_vals(bb) return ret
def get_con2_var_or_num(i_cnt, cur_addr): """ :param i_cnt: the register of the virtual call :param cur_addr: the current address in the memory :return: "success" string and the address of the vtable's location. if it fails it sends the reason and -1 """ start_addr = idc.get_func_attr(cur_addr, idc.FUNCATTR_START) virt_call_addr = cur_addr cur_addr = idc.prev_head(cur_addr) dct_arch = get_arch_dct() if dct_arch == -1: return 'Wrong Architechture', "-1", cur_addr while cur_addr >= start_addr: if idc.print_insn_mnem( cur_addr)[:3] == dct_arch["opcode"] and idc.print_operand( cur_addr, 0) == i_cnt: # TODO lea ? opnd2 = idc.print_operand(cur_addr, 1) place = opnd2.find(dct_arch["separator"]) if place != -1: # if the function is not the first in the vtable register = opnd2[opnd2.find('[') + 1:place] if opnd2.find('*') == -1: offset = opnd2[place + dct_arch["val_offset"]:opnd2.find(']')] else: offset = "*" return register, offset, cur_addr else: offset = "0" if opnd2.find(']') != -1: register = opnd2[opnd2.find('[') + 1:opnd2.find(']')] else: register = opnd2 return register, offset, cur_addr elif idc.print_insn_mnem(cur_addr)[:4] == "call": intr_func_name = idc.print_operand(cur_addr, 0) # In case the code has CFG -> ignores the function call before the virtual calls if "guard_check_icall_fptr" not in intr_func_name: if "nullsub" not in intr_func_name: # intr_func_name = idc.Demangle(intr_func_name, idc.GetLongPrm(idc.INF_SHORT_DN)) print( "Warning! At address 0x%08x: The vtable assignment might be in another function (Maybe %s)," " could not place BP." % (virt_call_addr, intr_func_name)) cur_addr = start_addr cur_addr = idc.prev_head(cur_addr) return "out of the function", "-1", cur_addr return '', 0, cur_addr
def get_branch_type(self): if self.bbl == None: return -1 addr = self.addr while addr != self.bbl.end_ea: mnem = idc.print_insn_mnem(addr).lower() if mnem.startswith("call"): if op_type[idc.get_operand_type(addr,0)] != "o_near" and\ op_type[idc.get_operand_type(addr,0)] != "o_far": return ICALL else: return CALL addr = idc.next_head(addr) addr = idc.prev_head(self.bbl.end_ea) mnem = idc.print_insn_mnem(addr).lower() if mnem in u_jumps or mnem in c_jumps: if op_type[idc.get_operand_type(addr,0)] != "o_near" and\ op_type[idc.get_operand_type(addr,0)] != "o_far": return IJMP else: if mnem in u_jumps: return JMP else: return CJMP elif self.bbl.type >= 2 and self.bbl.type <= 5: return RET return NA
def find_ehfuncinfo_addr(self): for eh_addr in self.frmhdlr_xref: addr_ = eh_addr for i in range(0, self.MAX_SEARCH): addr_ = idc.prev_head(addr_) mnem = idc.print_insn_mnem(addr_) ### locate the ehfuncInfo address if mnem == 'mov' and idc.get_operand_type( addr_, 0) == o_reg and idc.get_operand_type( addr_, 1) == o_imm: op1 = idc.print_operand(addr_, 0) op2 = idc.print_operand(addr_, 1) ## eh function info address eh_func_info_addr = get_operand_value(addr_, 1) #print(hex(addr_), mnem, op1, op2,hex(eh_func_info_addr)) ### locate the ptryBlockMapAddr for ad in idautils.XrefsTo(addr_, flags=0): seh_init_addr = ad.frm print( "[+] seh_frame_addr: {} ehFuncInfo_struct_addr: {}\n------------------------------------------------------------------" .format(hex(addr_), hex(eh_func_info_addr))) ### locate the xref of the _cxxframehandler ehfuncinfo self.parse_func_info_entry(seh_init_addr, addr_, eh_func_info_addr) return
def getMinorDispatchTableAddress(ea): """find address of last lea in function""" start = idc.get_func_attr(ea, idc.FUNCATTR_START) end = idc.prev_head(idc.get_func_attr(ea, idc.FUNCATTR_END), start) res = prevMnemonic(end, 'lea', start) assert res != idc.BADADDR return idc.get_operand_value(res, 1)
def is_eax_set(bbl): iaddr = idc.prev_head(bbl.end_ea) iaddr = idc.prev_head(bbl.end_ea) while idc.next_head(iaddr) != bbl.start_ea: if is_eax_written(iaddr): return True if is_eax_read(iaddr): return False iaddr = idc.prev_head(iaddr) ret = True for bb in bbl.preds(): ret = ret & is_eax_set(bb) if ret == False: break return ret
def replace_sym_const(ea, api): for arg_n in api_list[api].keys(): # Calling Convention: cdecl, stdcall push_cnt = 0 ea_search = ea while push_cnt < arg_n: ea_search = idc.prev_head(ea_search) op = idc.print_insn_mnem(ea_search) if op == "push": push_cnt += 1 operand = idc.print_operand(ea_search, 0) if operand.isdigit(): operand = int(idc.print_operand(ea_search, 0)) else: continue enum_name = api + "_" + str(arg_n) const = api_list[api][arg_n][operand] enum_id = ida_enum.get_enum(enum_name) if enum_id == BADADDR: # add new enum enum_qty = ida_enum.get_enum_qty() enum_id = ida_enum.add_enum(enum_qty, enum_name, 0) symbolic_id = ida_enum.get_enum_member_by_name(const) if symbolic_id == BADADDR: # add new enum member ida_enum.add_enum_member(enum_id, const, operand, 0xffffffff) ida_bytes.op_enum(ea_search, 0, enum_id, 0)
def track_register(self, ea, target_dest_reg): f_start = idc.get_func_attr(ea, idc.FUNCATTR_START) f_end = idc.get_func_attr(ea, idc.FUNCATTR_END) curr_ea = ea dst = None src = None target = target_dest_reg.lower() target_dest_reg = target_dest_reg.lower() target_value = None target_ea = idc.BADADDR target_type = None previous_call = None ret_dict = {} while curr_ea != idc.BADADDR: #instruction = idc.GetDisasm(curr_ea) # print "0x%08x %s" % (curr_ea, instruction) # looking for the previous place this register was assigned a value mnem = idc.print_insn_mnem(curr_ea).lower() dst = idc.print_operand(curr_ea, 0).lower() src = idc.print_operand(curr_ea, 1).lower() if dst == target and self.is_set_argument_instr(mnem): target = src target_value = src target_ea = curr_ea # print " new target set %s (type=%d)" % (target, idc.get_operand_type(curr_ea, 1)) if target.startswith("="): break if dst == target == "r0" and self.is_call_instr(mnem): target_value = "<return from previous call>" previous_call = curr_ea break # step to previous instruction curr_ea = idc.prev_head(curr_ea - 1, f_start) if target_value: # print ">>> 0x%08x, %s is set to %s @ 0x%08x" % (ea, target_dest_reg, target_value, target_ea) ret_dict = { "target": target_dest_reg, "value": target_value, "target_ea": target_ea, "ea": ea } if previous_call: ret_dict["previous_call"] = previous_call return ret_dict # fall through if nothing is found return {}
def AEG_GuessArgs(addr): _iter_addr = addr ret = [] while 1: _iter_addr = idc.prev_head(_iter_addr) _iter_instr = AEG_Instruction(_iter_addr) _op = _iter_instr.GetOperator() if _op in ('jmp', 'call', 'ret', 'retn', 'leave'): break elif 'j' in _op: break elif _op == 'mov': _opnd0 = _iter_instr.GetOperand(0) if INFO_BITS == 32: ## mov [esp+xx] , xxx if 'esp' in _opnd0 and ']' in _opnd0: ret.append(_iter_addr) else: if 'di' in _opnd0 or 'si' in _opnd0 or 'dx' in _opnd0 or 'cx' in _opnd0: ret.append(_iter_addr) elif _op == 'push': ret.append(_iter_addr) elif 'lea' == _op: ## lea rsi, xxx _opnd0 = _iter_instr.GetOperand(0) if 'si' in _opnd0 or 'di' in _opnd0: ret.append(_iter_addr) return ret
def decrypt_all_strings(decrypt_string_func_ea): global STRING_DICTIONARY for ref in idautils.CodeRefsTo(decrypt_string_func_ea, 1): # this function can be better. I hate it rn but oh well prev_instruction_ea = 0x472DAC if ref == translate_ea( 0x1db3) else idc.prev_head(ref) if idc.print_insn_mnem( prev_instruction_ea) == 'push' or idc.print_insn_mnem( prev_instruction_ea) == 'lea': encrypted_blob_ea = idc.get_operand_value( prev_instruction_ea, 1) if ref == translate_ea(0x1db3) else idc.get_operand_value( prev_instruction_ea, 0) length = int.from_bytes(idaapi.get_bytes(encrypted_blob_ea - 4, 4), 'little') #print(hex(prev_instruction_ea) + " and " + hex(encrypted_blob_ea) + " and " + hex(length)) encrypted_blob = [ x for x in idaapi.get_bytes(encrypted_blob_ea, length) ] encrypted_blob = decrypt_config(encrypted_blob, length) string = '' for each in encrypted_blob: if each != 0: string += chr(each) STRING_DICTIONARY[translate_ea_to_offset( encrypted_blob_ea)] = string return
def resolve_all_APIs(resolve_ea, mode): if resolve_ea is None: print('resolve fails..') return for ref in idautils.CodeRefsTo(resolve_ea, 1): # only 1 ref curr_ea = ref while True: prev_instruction_ea = idc.prev_head(curr_ea) if mode == 1: if idc.print_insn_mnem(prev_instruction_ea) == 'push': hash_val = idc.get_operand_value(prev_instruction_ea, 0) if hash_val in export_hashes: print(hex(ref) + ' : ' + export_hashes[hash_val]) idc.set_cmt(ref, export_hashes[hash_val], 0) break else: if idc.print_insn_mnem(prev_instruction_ea) == 'mov': hash_val = idc.get_operand_value(prev_instruction_ea, 1) print(hex(hash_val)) if hash_val in export_hashes: print(hex(ref) + ' : ' + export_hashes[hash_val]) idc.set_cmt(ref, export_hashes[hash_val], 0) break curr_ea = prev_instruction_ea
def trace_register_family(reg, loc, func_ea, state=None): """ Trace a provided register to the location in which any member of its register family is set. If it is set using a mov operation, the value is either an o_imm type (return the immediate value) or an o_mem type, that means the referenced location MAY a pointer to the actual data, which we need to acquire. We validate this by ensuring the acquired value is within the loaded memory range of the application. Otherwise we return idc.BADADDR. If the register is set using an lea operation, it is likely done so using a stack variable (which we validate) and then trace back to determine how the stack variable is set. :param reg: The referenced register which a location is loaded into :param loc: The starting offset for tracing back from :param func_ea: Starting function offset :param state: the current TraceState (a new state will be created if one is not provided) :return: The acquired location, or idc.BADADDR """ if state is None: state = TraceState() reg_fam = unsafe_get_reg_fam(reg) if reg_fam: loc = idc.prev_head(loc) while loc != func_ea: opnd = idc.print_operand(loc, 0) op_type_1 = idc.get_operand_type(loc, 1) opval_1 = idc.get_operand_value(loc, 1) mnem = idc.print_insn_mnem(loc) if 'mov' in mnem and opnd in reg_fam: if op_type_1 == idc.o_imm: return opval_1 elif op_type_1 == idc.o_mem: poss_loc = idc.get_wide_dword(opval_1) if idaapi.cvar.inf.minEA <= poss_loc < idaapi.cvar.inf.maxEA: return poss_loc else: return opval_1 else: return idc.BADADDR elif mnem == 'lea' and op_type_1 == idc.o_displ and opnd in reg_fam: stack_var = get_operand_value_replacement(loc, 1, state) return trace_stack_var(stack_var, loc, func_ea, state) elif is_64_bit() and mnem == 'lea' and opnd in reg_fam: if op_type_1 == idc.o_mem: return opval_1 loc = idc.prev_head(loc) return idc.BADADDR
def trace_register_family_x64(reg, loc, func_ea, state=None): """ Shouldn't be any different than trace_register_family except for continuing a trace if a register is loaded into the target register. However, using it in trace_register_family was not behaving properly, so keeping it separate for now. Also unsure of what the repercussions would be of adding that into the existing trace_register_family. :param reg: The referenced register which a location is loaded into :param loc: The starting offset for tracing back from :param func_ea: Starting function offset :param state: the current TraceState :return: The acquired location, or idc.BADADDR """ if state is None: state = TraceState() reg_fam = unsafe_get_reg_fam(reg) if reg_fam: loc = idc.prev_head(loc) while loc != func_ea: opnd = idc.print_operand(loc, 0) op_type_1 = idc.get_operand_type(loc, 1) opval_1 = idc.get_operand_value(loc, 1) mnem = idc.print_insn_mnem(loc) if "mov" in mnem and opnd in reg_fam: if op_type_1 == idc.o_imm: return opval_1 elif op_type_1 == idc.o_mem: poss_loc = idc.get_wide_dword(opval_1) if idaapi.cvar.inf.minEA <= poss_loc < idaapi.cvar.inf.maxEA: return poss_loc else: return opval_1 elif op_type_1 == idc.o_reg: return trace_register_family_x64(idc.print_operand(loc, 1), loc, func_ea, state) else: return idc.BADADDR elif mnem == "lea" and op_type_1 == idc.o_displ and opnd in reg_fam: stack_var = get_operand_value_replacement(loc, 1, state) return trace_stack_var(stack_var, loc, func_ea, state) elif is_64_bit() and mnem == "lea" and opnd in reg_fam: if op_type_1 == idc.o_mem: return opval_1 loc = idc.prev_head(loc) return idc.BADADDR
def get_bb_ends(address): """ Get end addresses of all bbs in function containing address. :param address: address in function :return: list of bb end addresses """ function = idaapi.get_func(address) flowchart = idaapi.FlowChart(function) return [idc.prev_head(bb.end_ea) for bb in flowchart]
def trace_stack_var(stack_var, loc, func_ea, state=None): """ Trace a provided stack variable to the location in which it is set. If it is set using a mov operation, the value may be set from a register, which we then need to call back to trace_register in order to acquire the value. Otherwise it is either an o_imm type (return the immediate value) or an o_mem type, that means the referenced location MAY a pointer to the actual data, which we need to acquire. We validate this by ensuring the acquired value is within the loaded memory range of the application. Otherwise we return idc.BADADDR. :param stack_var: The stack variable which a location is loaded into :param loc: The starting offset for tracing back from :param func_ea: Starting function offset :param state: the current TraceState :return: The acquired location, or idc.BADADDR """ if state is None: state = TraceState() loc = idc.prev_head(loc) while loc != func_ea: op_type_1 = idc.get_operand_type(loc, 1) opval_1 = idc.get_operand_value(loc, 1) mnem = idc.print_insn_mnem(loc) dis = idc.GetDisasm(loc) if mnem == "mov" and stack_var == get_operand_value_replacement( loc, 0, state): if op_type_1 == idc.o_reg: return trace_register(idc.print_operand(loc, 1), loc, func_ea, state) elif op_type_1 == idc.o_imm: return opval_1 elif op_type_1 == idc.o_mem: poss_loc = idc.get_wide_dword(opval_1) if idaapi.cvar.inf.minEA <= poss_loc < idaapi.cvar.inf.maxEA: return poss_loc else: return opval_1 else: return idc.BADADDR elif any(x in dis for x in MOVS): result = trace_rep_mov(stack_var, loc, func_ea, state) if result: return result loc = idc.prev_head(loc) return idc.BADADDR
def hand_register(line, start_ea, reg_target): current = line while (current >= start_ea): current = idc.prev_head(current) if (idc.print_insn_mnem(current) == 'jmp'): return hand_block(line, current, reg_target) if (idc.print_operand(current, 0) == reg_target) and (idc.print_insn_mnem(current) in ['mov', 'lea']): return idc.print_operand(current, 1)
def func_bound(self): if self.func == None: return (IDA_ERROR, IDA_ERROR) fend = idc.prev_head(self.func.end_ea) if self.addr == fend: if idc.print_insn_mnem(self.addr) in u_jumps: return (RESOLVE_NAME, RESOLVE_NAME) else: return (IDA_ERROR, IDA_ERROR) return (self.func.start_ea, fend)
def set_types(self): ''' handle (EFI_BOOT_SERVICES *) type and (EFI_SYSTEM_TABLE *) for x64 images ''' RAX = 0 O_REG = 1 O_MEM = 2 EFI_BOOT_SERVICES = 'EFI_BOOT_SERVICES *' EFI_SYSTEM_TABLE = 'EFI_SYSTEM_TABLE *' empty = True for service in self.gBServices: for address in self.gBServices[service]: ea = address num_of_attempts = 10 for _ in range(num_of_attempts): ea = idc.prev_head(ea) if (idc.print_insn_mnem(ea) == 'mov' and idc.get_operand_type(ea, 1) == O_MEM): if (idc.get_operand_type(ea, 0) == O_REG and idc.get_operand_value(ea, 0) == RAX): gvar = idc.get_operand_value(ea, 1) gvar_type = idc.get_type(gvar) ''' if (EFI_SYSTEM_TABLE *) ''' if ((gvar_type != 'EFI_SYSTEM_TABLE *') and \ (idc.print_operand(address, 0).find('rax') == 1) ): if self._find_est(gvar, ea, address): print( '[ {0} ] Type ({type}) successfully applied' .format( '{addr:#010x}'.format(addr=gvar), type=EFI_SYSTEM_TABLE)) empty = False break ''' otherwise it (EFI_BOOT_SERVICES *) ''' if (gvar_type != 'EFI_BOOT_SERVICES *' and gvar_type != 'EFI_SYSTEM_TABLE *'): if idc.SetType(gvar, EFI_BOOT_SERVICES): empty = False idc.set_name( gvar, 'gBs_{addr:#x}'.format(addr=gvar)) print( '[ {0} ] Type ({type}) successfully applied' .format( '{addr:#010x}'.format(addr=gvar), type=EFI_BOOT_SERVICES)) break if empty: print(' * list is empty')
def find_function_starts(location, start_mnem_bytes=None): """ Description: Identifies all possible function starts since the most recent function or Align. Input: location - The EA to search before start_mnem_bytes - Try to start functions on a particular instruction Instructions are entered as space separated bytes (i.e. '55' for 'push ebp') The specified pattern will be used first, then the defaults will be used If no pattern is specified, the defaults will be used, which prefers 'push ebp' Output: starts - A list of function end EAs sorted: start_mnem_bytes, push ebp, (push esp, push esi, push edi) """ # foreach target bytes: # step instructions up # if instruction matches the target bytes, add to the corresponding output list # if we hit a function or an align, quit # return starts in the order: # start_nmem_bytes # push ebp # others, sorted ascending min_location = None ea = location while min_location is None: ea = idc.prev_head(ea) if idaapi.get_func(ea) or idc.is_align(idc.get_full_flags(ea)): min_location = ea elif ea == idc.BADADDR: min_location = idaapi.getseg(location).start_ea min_location = max(min_location, idaapi.getseg(location).start_ea) targets = ['55', '54', '56', '57'] if start_mnem_bytes: targets.insert(0, start_mnem_bytes) starts = {} for target in targets: function_starts = [] ea = find_binary_instruction_start(location - 1, idc.SEARCH_UP, target, min_location) while ea != idc.BADADDR: if ea < min_location: break else: function_starts.append(ea) ea = find_binary_instruction_start(ea - 1, idc.SEARCH_UP, target, min_location) starts[target] = function_starts return (starts[start_mnem_bytes] if start_mnem_bytes else []) + starts['55'] + \ sorted(itertools.chain.from_iterable(starts[target] for target in targets[-3:]))
def imp_cb(ea, name, ord): if name in funcs: for xref in idautils.XrefsTo(ea): call_addr = xref.frm caller_name = idc.get_func_name(call_addr) prev = idc.prev_head(call_addr) for _ in range(10): if idc.get_cmt(prev, 0) == 'Tag' and idc.get_operand_type( prev, 1) == 5: tag_raw = idc.get_operand_value(prev, 1) tag = '' for i in range(3, -1, -1): tag += chr((tag_raw >> 8 * i) & 0xFF) if tag in tags.keys(): tags[tag].add(caller_name) else: tags[tag] = set([caller_name]) break prev = idc.prev_head(prev) return True
def find_function_starts_near(location, start_mnem_bytes=None): """ Description: Identifies the nearest possible function starts since the most recent function or Align. Input: location - The EA to search before start_mnem_bytes - Try to start functions on a particular instruction Instructions are entered as space separated bytes (i.e. '55' for 'push ebp') The specified pattern will be used first, then the defaults will be used If no pattern is specified, the defaults will be used, which prefers 'push ebp' Output: starts - A list of function end EAs sorted: start_mnem_bytes, push ebp, (push esp, push esi, push edi) """ # foreach target bytes: # step instructions up # if instruction matches the target bytes, add to output list # then move on to the next target bytes # if we hit a function or an align, quit # return starts in the order # start_nmem_bytes # push ebp # others, sorted descending min_location = None ea = location while min_location is None: ea = idc.prev_head(ea) if idaapi.get_func(ea) or idc.is_align(idc.get_full_flags(ea)): min_location = ea elif ea == idc.BADADDR: min_location = idaapi.getseg(location).start_ea min_location = max(min_location, idaapi.getseg(location).start_ea) targets = ['55', '54', '56', '57'] if start_mnem_bytes: targets.insert(0, start_mnem_bytes) starts = {} for target in targets: ea = find_binary_instruction_start(location - 1, idc.SEARCH_UP, target, min_location) if ea != idc.BADADDR: starts[target] = ea return [ start for start in ( [starts.get(start_mnem_bytes, None), starts.get('55', None)] + sorted([starts.get(target, None) for target in targets[-3:]], reverse=True)) if start ]
def find_arg_ea(ea_call, arg_name): """ Return ea of argument by looking backwards from library function call. Arguments: ea_call -- effective address of call arg_name -- the argument name to look for """ # the search for previous instruction/data will stop at the specified # address (inclusive) prev_instr = idc.prev_head(ea_call, ea_call - PREVIOUS_INSTR_DELTA) while prev_instr > (ea_call - ARG_SEARCH_THRESHOLD) and \ prev_instr != idaapi.BADADDR: # False indicates not to look for repeatable comments comment = idc.get_cmt(prev_instr, False) if comment == arg_name: return prev_instr prev_instr = idc.prev_head(prev_instr, prev_instr - PREVIOUS_INSTR_DELTA) raise ArgumentNotFoundException( ' Argument {} not found within threshold'.format(arg_name))
def set_types(self): """ handle (EFI_BOOT_SERVICES *) type """ RAX = 0 O_REG = 1 O_MEM = 2 EFI_BOOT_SERVICES = "EFI_BOOT_SERVICES *" empty = True for service in self.gBServices: for address in self.gBServices[service]: ea = address num_of_attempts = 10 for _ in range(num_of_attempts): ea = idc.prev_head(ea) if (idc.GetMnem(ea) == "mov" and idc.get_operand_type(ea, 1) == O_MEM): if (idc.get_operand_type(ea, 0) == O_REG and idc.get_operand_value(ea, 0) == RAX): gBs_var = idc.get_operand_value(ea, 1) gBs_var_type = idc.get_type(gBs_var) if (gBs_var_type == "EFI_BOOT_SERVICES *"): empty = False print("[{0}] EFI_BOOT_SERVICES->{1}".format( "{addr:#010x}".format(addr=address), service)) print("\t [address] {0}".format( "{addr:#010x}".format(addr=gBs_var))) print("\t [message] type already applied") break if idc.SetType(gBs_var, EFI_BOOT_SERVICES): empty = False idc.MakeName( gBs_var, "gBs_{addr:#x}".format(addr=gBs_var)) print("[{0}] EFI_BOOT_SERVICES->{1}".format( "{addr:#010x}".format(addr=address), service)) print("\t [address] {0}".format( "{addr:#010x}".format(addr=gBs_var))) print("\t [message] type successfully applied") else: empty = False print("[{0}] EFI_BOOT_SERVICES->{1}".format( "{addr:#010x}".format(addr=address), service)) print("\t [address] {0}".format( "{addr:#010x}".format(addr=gBs_var))) print("\t [message] type not applied") break if empty: print(" * list is empty")
def find_function_arg_with_operand_value(addr, mnemonic, register, value, idx_operand): """ 00000000000167FC mov [rsp+20h], rax idc.get_operand_value(0x167FC, 0) ==> 0x20 """ for _ in range(20): # looks up to 20 instructions behind addr = idc.prev_head(addr) if idc.print_insn_mnem(addr) == mnemonic and register in idc.print_operand(addr, idx_operand)\ and idc.get_operand_value(addr, idx_operand) == value: return addr return None
def get_protocols(self): """ found UEFI protocols information in idb """ for service_name in self.gBServices: for address in self.gBServices[service_name]: ea, found = address, False if self.arch == "x86": for i in range(1, 25): ea = idc.prev_head(ea) if (idc.get_operand_value(ea, 0) > self.base and idc.GetMnem(ea) == "push"): found = True break if self.arch == "x64": for i in range(1, 16): ea = idc.prev_head(ea) if (idc.get_operand_value(ea, 1) > self.base and idc.GetMnem(ea) == "lea"): found = True break if not found: continue for xref in idautils.DataRefsFrom(ea): if (idc.GetMnem(xref) == ""): cur_guid = utils.get_guid(xref) if cur_guid != [0] * 11: record = { "address": xref, "service": service_name, "guid": cur_guid, } record["address"] = xref record["service"] = service_name record["guid"] = cur_guid if not self.Protocols["All"].count(record): self.Protocols["All"].append(record)
def symbolic_exec(): from miasm2.ir.symbexec import SymbolicExecutionEngine from miasm2.core.bin_stream_ida import bin_stream_ida from utils import guess_machine start, end = idc.SelStart(), idc.SelEnd() bs = bin_stream_ida() machine = guess_machine(addr=start) mdis = machine.dis_engine(bs) if start == idc.BADADDR and end == idc.BADADDR: start = idc.ScreenEA() end = idc.next_head(start) # Get next instruction address mdis.dont_dis = [end] asmcfg = mdis.dis_multiblock(start) ira = machine.ira(loc_db=mdis.loc_db) ircfg = ira.new_ircfg_from_asmcfg(asmcfg) print "Run symbolic execution..." sb = SymbolicExecutionEngine(ira, machine.mn.regs.regs_init) sb.run_at(ircfg, start) modified = {} for dst, src in sb.modified(init_state=machine.mn.regs.regs_init): modified[dst] = src view = symbolicexec_t() all_views.append(view) if not view.Create(modified, machine, mdis.loc_db, "Symbolic Execution - 0x%x to 0x%x" % (start, idc.prev_head(end))): return view.Show()