def read_bytes_at(ea, count): """ """ segm_end = idc.get_segm_end(ea) if ea + count > segm_end: return idc.get_bytes(ea, segm_end - ea) else: return idc.get_bytes(ea, count)
def _read_bytes(start_ea, end_ea): """ Description: Reads and returns the bytes from <start_ea> to <end_ea>. Reads are returned in sections READ_LENGTH in length to avoid potential memory concerns for extremely large ranges. Input: start_ea - The start of the range end_ea - The end of the range Output: A string of the bytes in the given range """ global SECTION_START block_start = start_ea block_end = end_ea while block_start < end_ea: while block_start < end_ea and idc.get_bytes(block_start, 1) is None: block_start += 1 if block_start >= end_ea: break block_end = block_start + 1 while block_end < end_ea and idc.get_bytes(block_end, 1) is not None: block_end += 1 SECTION_START = block_start while block_start < block_end: yield idc.get_bytes(block_start, min(READ_LENGTH, block_end - block_start)) SECTION_START += READ_LENGTH block_start += READ_LENGTH block_start = block_end + 1
def extract_info_from_IDA(self): prots = ida_bytes.get_qword(self.ea + 0x10) if prots: count = ida_bytes.get_qword(prots) entrysize = 0x8 p_ea = prots + 8 for i in range(count): proto_ea = idc.get_qword(p_ea) self.prots.append(proto_ea) p_ea += entrysize type_info = ida_bytes.get_qword(self.ea + 0x48) for idx in range(0, 4): # 0: inst_meths # 1: class_meths # 2: opt_inst_meths # 3: opt_class_meths meth_list = ida_bytes.get_qword(self.ea + 0x18 + idx * 8) if meth_list: entrysize = ida_bytes.get_dword(meth_list) count = ida_bytes.get_dword(meth_list + 4) ea = meth_list + 8 for i in range(0, count): sel = idc.get_bytes(idc.Qword(ea), idc.get_item_size(idc.Qword(ea)) - 1) meth_type = idc.get_bytes(idc.Qword(type_info), idc.get_item_size(idc.Qword(type_info)) - 1) self.meths[sel] = meth_type ea += entrysize type_info += 8
def __get_instruction_bytes_wildcarded(pattern, addr, instr_type, op1_type, op2_type): """Replaces bytes related to memory addresses with wildcards. TODO: To be replaced by ida_idp.ph_calcrel() Args: pattern: current buffer containing the bytes of the current instruction. addr: the address of the current instruction to be wildcarded instr_type: type of the current instruction op1_type: type of the first operand op2_type: type of the second operand Returns: String: hex-encoded representation of the bytes obtained at addr where all the operands that refers to memmory addresses are wildcarded. """ type_calls = frozenset( [idaapi.NN_call, idaapi.NN_callfi, idaapi.NN_callni]) type_jumps = frozenset( [idaapi.NN_jmp, idaapi.NN_jmpfi, idaapi.NN_jmpni]) inst_prefix = binascii.hexlify(idc.get_bytes(addr, 1)).decode('utf-8') drefs = [x for x in idautils.DataRefsFrom(addr)] logging.debug('[VTGREP] Wildcarding: %s', idc.generate_disasm_line(addr, 0)) # Known 2 bytes opcodes if inst_prefix in ('0f', 'f2', 'f3'): pattern = binascii.hexlify(idc.get_bytes(addr, 2)).decode('utf-8') inst_num_bytes = 2 # CALLs or JUMPs using 2 bytes opcodes elif inst_prefix == 'ff' and (instr_type in type_jumps or instr_type in type_calls): pattern = binascii.hexlify(idc.get_bytes(addr, 2)).decode('utf-8') inst_num_bytes = 2 # A PUSH instruction using an inmediate value (mem offset) elif (inst_prefix == 'ff' and drefs and (op1_type == idaapi.o_imm or op2_type == idaapi.o_imm)): pattern = binascii.hexlify(idc.get_bytes(addr, 2)).decode('utf-8') inst_num_bytes = 2 # No prefix is used else: pattern = inst_prefix inst_num_bytes = 1 pattern += ' ' + '??' * (idc.get_item_size(addr) - inst_num_bytes) + ' ' return pattern
def read_bytes_at(ea, count): """ """ # check if byte has a value, see get_wide_byte doc if not idc.is_loaded(ea): return b"" segm_end = idc.get_segm_end(ea) if ea + count > segm_end: return idc.get_bytes(ea, segm_end - ea) else: return idc.get_bytes(ea, count)
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 get_dbg_brk_linux32(): ''' Return the current brk value in the debugged process (only x86 Linux) ''' #TODO this method is so weird, find a unused address to inject code not the base address code = "" code += '\xb8-\x00\x00\x00' #mov eax, sys_brk ; 45 code += '1\xdb' #xor ebx, ebx code += '\xcd\x80' #int 0x80 eax = idc.get_reg_value("eax") ebx = idc.get_reg_value("ebx") eip = idc.get_reg_value("eip") efl = idc.get_reg_value("efl") base = idaapi.get_imagebase() #inj = idc.next_head(eip) #skip current instr inj = base save = idc.get_bytes(inj, len(code), use_dbg=True) for i in xrange(len(code)): idc.patch_dbg_byte(inj + i, ord(code[i])) #idc.MakeCode(inj) idc.set_reg_value(inj, "eip") idaapi.step_into() idc.GetDebuggerEvent(idc.WFNE_SUSP, -1) idaapi.step_into() idc.GetDebuggerEvent(idc.WFNE_SUSP, -1) idaapi.step_into() idc.GetDebuggerEvent(idc.WFNE_SUSP, -1) brk_res = idc.get_reg_value("eax") idc.set_reg_value(eax, "eax") idc.set_reg_value(ebx, "ebx") idc.set_reg_value(eip, "eip") idc.set_reg_value(efl, "efl") for i in xrange(len(save)): idc.patch_dbg_byte(inj + i, ord(save[i])) save = idc.get_bytes(inj, len(code), use_dbg=True) #idc.MakeCode(inj) return brk_res
def get_dbg_brk_linux64(): ''' Return the current brk value in the debugged process (only x86_64 Linux) ''' #TODO this method is so weird, find a unused address to inject code not the base address code = "" code += 'H\xc7\xc0\x0c\x00\x00\x00' #mov rax, sys_brk ; 12 code += 'H1\xff' #xor rdi, rdi code += '\x0f\x05' #syscall rax = idc.get_reg_value("rax") rdi = idc.get_reg_value("rdi") rip = idc.get_reg_value("rip") efl = idc.get_reg_value("efl") base = idaapi.get_imagebase() #inj = idc.next_head(rip) #skip current instr inj = base save = idc.get_bytes(inj, len(code), use_dbg=True) for i in xrange(len(code)): idc.patch_dbg_byte(inj + i, ord(code[i])) #idc.MakeCode(inj) idc.set_reg_value(inj, "rip") idaapi.step_into() idc.GetDebuggerEvent(idc.WFNE_SUSP, -1) idaapi.step_into() idc.GetDebuggerEvent(idc.WFNE_SUSP, -1) idaapi.step_into() idc.GetDebuggerEvent(idc.WFNE_SUSP, -1) brk_res = idc.get_reg_value("rax") idc.set_reg_value(rax, "rax") idc.set_reg_value(rdi, "rdi") idc.set_reg_value(rip, "rip") idc.set_reg_value(efl, "efl") for i in xrange(len(save)): idc.patch_dbg_byte(inj + i, ord(save[i])) save = idc.get_bytes(inj, len(code), use_dbg=True) #idc.MakeCode(inj) return brk_res
def getLZ77CompressedSize(compressed_ea): """ Iterates the compressed data, and returns its size :param compressed_ea: the linear address of the compressed data :return: its size in bytes or <0 if this is an invalid format """ dataHeader = 0 chars = idc.get_bytes(compressed_ea, 4) for i in range(len(chars)): dataHeader |= ord(chars[i]) << 8 * i decompSize = (dataHeader & ~0xFF) >> 8 # compression type must match if (dataHeader & 0xF0) >> 4 != 1: return -1 # iterate, and figure out the number of bytes copied size = 0 ea = compressed_ea + 4 # iterate the blocks and keep count of the data size while size < decompSize: # parse block flags (compressed or not) flags = ord(idc.get_bytes(ea, 1)) ea += 1 # iterate the blocks, MSB first. for i in range(7, -1, -1): if flags & (1 << i): # block i is compressed chars = idc.get_bytes(ea, 2) block = ord(chars[0]) + (ord(chars[1]) << 8) size += ((block & 0xF0) >> 4) + 3 ea += 2 # check that the displacement doesn't underflow disp = ((block & 0xFF00) >> (16 - 4)) | block & 0xF if size - disp - 1 < 0: return -2 else: # block i is uncompressed, it's just one byte size += 1 ea += 1 # we might finish decompressing while processing blocks if size >= decompSize: # ensure that the rest of the flags are 0! # this is a practical restriction. (likely true, not technically part of the specs) for j in range(i, -1, -1): if flags & (1 << j) != 0: return -3 break print('decompressed size: 0x%X' % decompSize) return ea - compressed_ea
def iterateByPaddingToTheLastInstruction(ea): debug( "iterateByPaddingToTheLastInstruction. Address: 0x{:X}".format(ea)) for i in range(0, 16): ea -= 1 bytes = idc.get_bytes(ea, 1) debug('ea: 0x{:X}'.format(ea)) debug(idc.get_bytes(ea, 1)[0]) if idc.get_bytes(ea, 1)[0] == 0xCC or idc.get_bytes(ea, 1)[0] == 0x90: print('continue') continue break
def find_guid_in_address_space(start_address, end_address): """ This function will try to parse memonique with an operand value as second parameter, then will try to validate it with registry :ivar int start_address: """ result = [] for head in idautils.Heads(start_address, end_address): # search for direct value operand for operand_value in [ idc.get_operand_value(head, 1), idc.get_operand_value(head, 0) ]: guid_bytes = idc.get_bytes(operand_value, 16) guid = guid_bytes_to_string(guid_bytes) try: result.append(build_com_from_class_definition(head, guid)) break except WindowsError as e: pass try: result.append(build_com_from_interface_definition(head, guid)) break except WindowsError as e: pass return result
def _get_bytes(self, location, size=None, code_page=None): """ Extracts bytes from given location. :param location: Location to pull bytes :param size: Number of bytes to pull (determines size by looking for terminator if not provided) :param code_page: Known code_page used to determine terminator. :return: bytes or None """ # Determine size by looking for terminator. # (Use provided encoding to determine terminator width.) if size is None: width = 1 if code_page: if '16' in code_page: width = 2 elif '32' in code_page: width = 4 end_location = idc.find_binary(location, idc.SEARCH_DOWN, "00 " * width) if end_location == idc.BADADDR: logger.warning('Failed to extract bytes from 0x{:08X}'.format(location)) return None size = end_location - location while size % width: # ensure unicode strings are a valid length size += 1 # Pull size amount of bytes from IDA. data = idc.get_bytes(location, size) if data is None: logger.warning('Failed to extract {} bytes from 0x{:08X}'.format(size, location)) return data
def copy_bytes(): """ Copy selected bytes to clipboard """ if using_ida7api: start = idc.read_selection_start() end = idc.read_selection_end() if idaapi.BADADDR in (start, end): ea = idc.here() start = idaapi.get_item_head(ea) end = idaapi.get_item_end(ea) # # reference https://stackoverflow.com/questions/6624453/whats-the-correct-way-to-convert-bytes-to-a-hex-string-in-python-3 data = idc.get_bytes(start, end - start).hex() print("Bytes copied: %s" % data) copy_to_clip(data) else: start = idc.SelStart() end = idc.SelEnd() if idaapi.BADADDR in (start, end): ea = idc.here() start = idaapi.get_item_head(ea) end = idaapi.get_item_end(ea) # reference https://stackoverflow.com/questions/6624453/whats-the-correct-way-to-convert-bytes-to-a-hex-string-in-python-3 # not work in ida7.5 python3.7.7 # data = idc.GetManyBytes(start, end-start).encode('hex') data = idc.GetManyBytes(start, end - start).hex() print("Bytes copied: %s" % data) copy_to_clip(data) return
def activate(self, ctx): """ :param ctx: idaapi.action_activation_ctx_t :return: None """ ea = get_screen_ea() if get_func(ea) is None: print("address = " + hex(ea)) data = get_bytes(ea, 16) guid = str(UUID(bytes_le=data)) else: name, data = extract_guid(ea) guid = str(UUID(bytes_le=data)) print("Local variable EFI_GUID extraction for " + name) print("data = " + " ".join("%02x" % x for x in bytes(data))) print("guid = " + guid) try: import clipboard clipboard.copy(guid) except ImportError: print("clipboard module is not available.")
def decryptor(index, call_addr): decrypted_string = "" current_struct_start = struct_start + 8 * index current_struct_bytes = idc.get_bytes(current_struct_start, 8) print(current_struct_bytes.hex()) #structure parsing and xoring key = int.from_bytes(current_struct_bytes[0:1], byteorder='little', signed=False) length = int.from_bytes(current_struct_bytes[2:4], byteorder='little', signed=False) buffer_string_addr = int.from_bytes(current_struct_bytes[4:8], byteorder='little', signed=False) print(hex(key), hex(length), hex(buffer_string_addr)) #decrypting for i in range(0, length): decrypted_string += chr(key ^ idc.get_wide_byte(buffer_string_addr + i)) print(decrypted_string) #commenting assembly view idc.set_cmt(call_addr, decrypted_string, 0) #commenting decompile view on the same address as assembly view cfunc = idaapi.decompile(call_addr) tl = idaapi.treeloc_t() tl.ea = call_addr tl.itp = idaapi.ITP_SEMI cfunc.set_user_cmt(tl, decrypted_string) cfunc.save_user_cmts()
def find_binary_instruction_start( search_start_location, search_direction, target, min_location=idc.get_inf_attr(idc.INF_MIN_EA), max_location=idc.get_inf_attr(idc.INF_MAX_EA)): """ Description: Given a starting location, target, and direction, find an instruction starting with the target bytes. Input: search_start_location - The EA to start searching at search_direction - either idc.SEARCH_UP or idc.SEARCH_DOWN target - The target as space separated bytes (i.e. '55' for 'push ebp') min_location - The minimum EA to accept results for (default: idc.get_inf_attr(idc.INF_MIN_EA)) max_location - The maximum EA to accept results for (default: idc.get_inf_attr(idc.INF_MAX_EA)) Output: Returns the first matching location if found, otherwise idc.BADADDR """ target = target.upper() while search_start_location < max_location: ea = idc.find_binary(search_start_location, search_direction, target) if (min_location <= ea < max_location and ea == idc.get_item_head(ea) and idc.get_bytes( ea, idc.get_item_size(ea)).encode('hex').upper().startswith( target.replace(' ', ''))): return ea else: search_start_location = ea + (1 if search_direction == idc.SEARCH_DOWN else -1) return idc.BADADDR
def handle_mov(ea, state): """Updates the stack based on a mov instruction. Used by create_stack :param ea: instruction location :param state: the current TraceState :return: None - updates stack or regs """ op1 = get_opnd_replacement(ea, POS_FIRST) if idc.get_operand_type(ea, POS_FIRST) != idc.o_reg: offset = get_operand_value_replacement(ea, POS_FIRST, state) set_stack(offset, ea, POS_SECOND, state) else: type_ = idc.get_operand_type(ea, POS_SECOND) val = None if type_ == idc.o_reg: val = state.get_reg_value(get_opnd_replacement(ea, POS_SECOND)) elif type_ == idc.o_mem: bytes = idc.get_bytes(idc.get_operand_value(ea, POS_SECOND), get_byte_size_of_operand(ea, POS_SECOND)) if bytes: val = 0 for x in range(len(bytes)): val += ord(bytes[x]) << (8 * x) elif type_ == idc.o_imm: val = idc.get_operand_value(ea, POS_SECOND) else: offset = get_operand_value_replacement(ea, POS_SECOND, state) val, ea = state.stack.get(offset, (None, ea)) state.set_reg_value(op1, val, ea)
def resolvePointers(fileRange, pointerRange, verbose=True): """ :param fileRange: tuple of (int, int) representing the file to resolve pointers in :param pointerRange: tuple of (int, int) representing range of pointers to resolve :param verbose: if True, all changes are printed :return: """ if verbose: print("(%07X, %07X): expand unknown arrays" % (fileRange[0], fileRange[1])) expandUnkArrays(*fileRange, verbose=False) ea = fileRange[0] while ea < fileRange[1]: ea = next.unkptr(ea, fileRange[1], rom=True, ui=False, hexOut=False) if ea != idaapi.BADADDR: # get data at ea chars = idc.get_bytes(ea, 4) dword = 0 for i in range(len(chars)): dword += ord(chars[i]) << 8 * i if pointerRange[0] <= dword < pointerRange[1]: if verbose: print('%07X: %07X' % (ea, dword)) idc.op_plain_offset(ea, 0, 0)
def getUnkPointers(fileRange, verbose=True, rom=True): """ reports back all suspect unknown pointers within the file :param fileRange: :param verbose: :return: """ if verbose: print("(%07X, %07X): expand unknown arrays" % (fileRange[0], fileRange[1])) expandUnkArrays(*fileRange, verbose=False) output = [] ea = fileRange[0] while ea < fileRange[1]: ea = next.unkptr(ea, fileRange[1], rom=rom, ui=False, hexOut=False) if ea != idaapi.BADADDR: # get data at ea chars = idc.get_bytes(ea, 4) dword = 0 for i in range(len(chars)): dword += ord(chars[i]) << 8 * i output.append((ea, dword)) if verbose: print("(%07X, %07X): collapsing unknowns " % (fileRange[0], fileRange[1])) collapseUnknowns(*fileRange, verbose=False) return output
def parse_table(ea): table = u64(idc.get_bytes(ea, 8)) addr = table func_table = [] while True: pm4type, opcode, handler = read_entry(addr) if handler == 0: break # get gnm name and packet count gnm_name, packet_count = parse_function(handler) # decompile the handler func = ida_hexrays.decompile(handler) lines = func.get_pseudocode() code_lines = [] for sline in lines: line = ida_lines.tag_remove(sline.line) code_lines.append(line) print('{}\t{} {} {:X} {:08X}'.format(gnm_name, packet_count, pm4type, opcode, handler)) if not gnm_name: gnm_name = 'sub_{:X}'.format(handler) func_table.append( (gnm_name, packet_count, pm4type, opcode, handler, code_lines)) addr += 16 return func_table
def get_displ_reg(arg_inst, opt_index): base_reg = -1 index_reg = -1 disp = 0 # capstone 解码内存引用寄存器 for cs_insn in md.disasm(idc.get_bytes(arg_inst.ea, arg_inst.size), arg_inst.size): cs_opt0 = cs_insn.operands[opt_index] # ps: mov eax, [edi+ecx+0x10] # 基地址寄存器 if cs_opt0.value.mem.base: base_reg = capstone_reg_map[cs_insn.reg_name( cs_opt0.value.mem.base)] # 变地寄存器 if cs_opt0.value.mem.index: index_reg = capstone_reg_map[cs_insn.reg_name( cs_opt0.value.mem.index)] # 偏移 if cs_opt0.value.mem.disp: disp = cs_opt0.value.mem.disp break return base_reg, index_reg, disp
def extract(self): """ Extracts all binary ranges specified in env['binFiles'] into *.bin files in the folder env['binPath'] """ # grab necessary variables from the environment and assert that they were given gameFiles = self.get('gameFiles') binPath = self.get('dismProjPath') + self.get('binPath') if not gameFiles or not binPath: print( 'ERROR: environmental variables for dismProjPath, gameFiles, and binPath' + ' must be provided.') return keys = gameFiles.keys() keys.sort() for file in keys: if '.bin' in file: # get bytes in specified range bytes = idc.get_bytes(gameFiles[file][0], gameFiles[file][1] - gameFiles[file][0]) # write bytes to bin file bpath = binPath + file print("Extracting %s into %s... " % (file, bpath)) binfile = open(bpath, 'wb') binfile.write(bytes) binfile.close() print("Extraction complete!")
def read_memory(segments, ea, size): if IDA_MODULE: return idc.get_bytes(ea, size) for segment_ea, data in segments.items(): if (ea <= segment_ea + len(data)) and (ea >= segment_ea): offset = ea - segment_ea return data[offset:offset + size]
def check_segment_for_pe(seg): """check segment for embedded PE adapted for IDA from: https://github.com/vivisect/vivisect/blob/7be4037b1cecc4551b397f840405a1fc606f9b53/PE/carve.py#L19 args: seg (IDA segment_t) """ seg_max = seg.end_ea mz_xor = [( capa.features.extractors.helpers.xor_static(b"MZ", i), capa.features.extractors.helpers.xor_static(b"PE", i), i, ) for i in range(256)] todo = [] for (mzx, pex, i) in mz_xor: for off in capa.features.extractors.ida.helpers.find_byte_sequence( seg.start_ea, seg.end_ea, mzx): todo.append((off, mzx, pex, i)) while len(todo): off, mzx, pex, i = todo.pop() # The MZ header has one field we will check e_lfanew is at 0x3c e_lfanew = off + 0x3C if seg_max < (e_lfanew + 4): continue newoff = struct.unpack( "<I", capa.features.extractors.helpers.xor_static( idc.get_bytes(e_lfanew, 4), i))[0] peoff = off + newoff if seg_max < (peoff + 2): continue if idc.get_bytes(peoff, 2) == pex: yield (off, i) for nextres in capa.features.extractors.ida.helpers.find_byte_sequence( off + 1, seg.end_ea, mzx): todo.append((nextres, mzx, pex, i))
def _process_segment(seg_beg, seg_end): for addr in range(seg_beg, seg_end, 4): guid_bytes_le = get_bytes(addr, _GUID_SIZE) if guid_bytes_le != _zero_guid_bytes and guid_bytes_le != _ffff_guid_bytes: guid_name = _guids_db.get(guid_bytes_le, None) if guid_name: # Just marks it as a GUID structure guid = GUID(addr=addr, name=guid_name) print("Found %s @ 0x%X" % (guid, addr))
def _getOriginData(self, address, size): res = [] for offset in range(0, size, 64): tmp = get_bytes(address + offset, 64) if tmp == None: res.extend([pack("<Q", get_qword(address + offset + i)) for i in range(0, 64, 8)]) else: res.append(tmp) res = b"".join(res) return res[:size]
def _emit_fnbytes(emit_instr_cb, header, footer, indent, fva=None, warn=True): """Emit function bytes in a format defined by the callback and headers/footers provided. Warns if any instruction operands are not consistent with position-independent code, in which case the user may need to templatize the position-dependent portions. """ fva = fva or idc.here() fva = idc.get_func_attr(fva, idc.FUNCATTR_START) va_end = idc.get_func_attr(fva, idc.FUNCATTR_END) # Operand types observed in position-independent code: optypes_position_independent = set([ ida_ua.o_reg, # 1: General Register (al,ax,es,ds...) ida_ua.o_phrase, # 3: Base + Index ida_ua.o_displ, # 4: Base + Index + Displacement ida_ua.o_imm, # 5: Immediate ida_ua.o_near, # 7: Immediate Near Address ]) # Notably missing because I want to note and handle these if/as they are # encountered: # ida_ua.o_idpspec0 = 8: FPP register # ida_ua.o_idpspec1 = 9: 386 control register # ida_ua.o_idpspec2 = 10: 386 debug register # ida_ua.o_idpspec3 = 11: 386 trace register va = fva nm = idc.get_name(fva) optypes_found = set() s = header.format(name=nm) while va not in (va_end, idc.BADADDR): size = idc.get_item_size(va) the_bytes = idc.get_bytes(va, size) for i in range(0, 8): optype = idc.get_operand_type(va, i) if optype: optypes_found.add(optype) s += indent + emit_instr_cb(va, the_bytes, size) va = idc.next_head(va) s += footer position_dependent = optypes_found - optypes_position_independent if position_dependent: msg = ('This code may have position-dependent operands (optype %s)' % (', '.join([str(o) for o in position_dependent]))) if warn: Warning(msg) else: logger.warn(msg) return s
def try_make_function(function_start, function_end=idc.BADADDR, target_location=None, require_term=True, end_mnem_bytes=None): """ Description: Given a function location, attempt to create a function. If function creation fails, delete any partially created functions. If function creation succeeds, ensure all of the function's bytes are analyzed as code. Input: function_start - The start_ea of the function to create function_end - The end_ea of the function to create. IDA will calculate if not provided. target_location - If provided, fail function creation if it does not include this EA require_term - If provided, fail function creation if the last instruction is not a ret or jmp end_mnem_bytes - If provided, fail function creation if the last instruction is not the provided bytes Instructions are entered as space separated bytes (i.e. '55' for 'push ebp') Output: Returns a tuple (function_start, function_end) for the created function if successful, None otherwise """ if function_start <= function_end: if idc.add_func(function_start, function_end): logger.debug('Created a function 0x%X - 0x%X.' % (function_start, function_end)) if require_term: last_mnem_ea = idc.get_item_head( idaapi.get_func(function_start).end_ea - 1) last_mnem = idc.print_insn_mnem(last_mnem_ea) if (end_mnem_bytes is None and 'ret' not in last_mnem and 'jmp' not in last_mnem) or \ (end_mnem_bytes and idc.get_bytes(last_mnem_ea, idc.get_item_size(last_mnem_ea)).encode('hex').upper() != end_mnem_bytes.upper()): idc.del_func(function_start) logger.debug( 'Deleted function at 0x%X - the function didn\'t end with the correct mnem/bytes.' % function_start) return if target_location is not None: if function_start <= target_location < idaapi.get_func( function_start).end_ea: idc.plan_and_wait(function_start, idaapi.get_func(function_start).end_ea) return function_start, function_end else: idc.del_func(function_start) logger.debug( 'Deleted function at 0x%X - the function didn\'t contain the target location.' % function_start) return else: logger.debug( 'Tried to create a function 0x%X - 0x%X, but IDA wouldn\'t do it.' % (function_start, function_end)) else: logger.debug('The end address was not greater than the start address!')
def __init__(self, ea, info, cs): """Initialization function.""" # Init the node structure node_t.__init__(self) # Check if it's a code instruction try: is_c = is_code(get_flags(ea)) except: is_c = isCode(GetFlags(ea)) if not is_c: raise CodeException # # fill node_t struct # # NodeInfo self.info = NodeInfo() inst_elements = [] try: size = create_insn(ea) bytes = get_bytes(ea, size) except: size = MakeCode(ea) bytes = GetManyBytes(ea, size) (address, size, mnemonic, op_str) = cs.disasm_lite(bytes, ea, count=1).next() self.info.opcode = mnemonic.encode("ascii", "ignore") op_str_ascci = op_str.encode("ascii", "ignore") self.info.inst_str = self.info.opcode + " " + op_str_ascci splitted = op_str_ascci.split(", ") self.info.nargs = 0 if len(splitted) >= 1: self.info.arg1 = splitted[0] self.info.nargs += 1 if len(splitted) >= 2: self.info.arg2 = splitted[1] self.info.nargs += 1 if len(splitted) >= 3: self.info.arg3 = splitted[2] self.info.nargs += 1 # No node will be root but this is acceptable for CFGs self.info.is_root = False self.info.address = ea self.info.has_address = True # node_t self.node_id = self._genid()
def extract_info_from_IDA(self): for xref in idautils.XrefsTo(self.ea): frm = xref.frm if idc.SegName(frm) == '__objc_classrefs': self.classref = frm if idc.SegName(frm) == '__objc_superrefs': self.superref = frm base_ivars = ida_bytes.get_qword(self.info + 0x30) if base_ivars and idc.SegName(base_ivars) == '__objc_const': entrysize = ida_bytes.get_dword(base_ivars) count = ida_bytes.get_dword(base_ivars + 4) ea = base_ivars + 8 for i in range(count): offset = ida_bytes.get_dword(idc.get_qword(ea)) _type = idc.get_bytes(idc.Qword(ea + 0X10), idc.get_item_size(idc.Qword(ea + 0X10)) - 1) _name = idc.get_bytes(idc.Qword(ea + 0X08), idc.get_item_size(idc.Qword(ea + 0X08)) - 1) # self.ivars[offset] = _type self.ivars[_name] = _type ea += entrysize base_props = ida_bytes.get_qword(self.info + 0x40) if base_props and idc.SegName(base_props) == '__objc_const': entrysize = ida_bytes.get_dword(base_props) count = ida_bytes.get_dword(base_props + 4) ea = base_props + 8 for i in range(count): _type = idc.get_bytes(idc.Qword(ea + 0X08), idc.get_item_size(idc.Qword(ea + 0X08)) - 1) _name = idc.get_bytes(idc.Qword(ea), idc.get_item_size(idc.Qword(ea)) - 1) self.props[_name] = _type ea += entrysize base_prots = ida_bytes.get_qword(self.info + 0x28) if base_prots and idc.SegName(base_prots) == '__objc_const': count = ida_bytes.get_qword(base_prots) entrysize = 0x8 p_ea = base_prots + 8 for i in range(count): proto_ea = idc.get_qword(p_ea) self.prots.append(proto_ea) Protocol.add_implementing_class(proto_ea, self.ea) p_ea += entrysize
def getBinary(self): result = b"" segment_starts = [ea for ea in idautils.Segments()] offsets = [] start_len = 0 for start in segment_starts: end = idc.SegEnd(start) result += idc.get_bytes(start, end - start) offsets.append((start, start_len, len(result))) start_len = len(result) return result