def is_mapped(ea, size=1, value=True): """Check if the given address is mapped. Specify a size greater than 1 to check if an address range is mapped. Arguments: ea: The linear address to check. Options: size: The number of bytes at ea to check. Default is 1. value: Only consider an address mapped if it has a value. For example, the contents of a bss section exist but don't have a static value. If value is False, consider such addresses as mapped. Default is True. Notes: This function is currently a hack: It only checks the first and last byte. """ if size < 1: raise ValueError('Invalid argument: size={}'.format(size)) # HACK: We only check the first and last byte, not all the bytes in between. if value: return idc.isLoaded(ea) and (size == 1 or idc.isLoaded(ea + size - 1)) else: return idaapi.getseg(ea) and (size == 1 or idaapi.getseg(ea + size - 1))
def factory(cls, string_location, string_reference, size=INVALID, offset=INVALID, key=INVALID): """ Factory function to generate an EncodedString or EncodedStackString based on type. :param string_location: Data segment pointer for static strings or stack pointer for stack strings. :param string_reference: The location the string is referenced from. This is required to pull the stack frame when string_location is a stack pointer. :param size: The size of the string. Required to use self.get_bytes. :param offset: Used when there is an offset based accessing scheme. :param key: Used when there is a key that can vary by string. """ if idc.isLoaded(string_location): return EncodedString( string_location, string_reference, size=size, offset=offset, key=key) # otherwise assume string_location is a pointer within the stack # (using function_tracingutils's CPU emulator) and create an EncodedStackString object. stack = idc.GetFrame(string_reference) # FIXME: This method isn't always super accurate because... IDA stack_offset = ( string_location + function_tracingutils.RSP_OFFSET + idc.GetFrameLvarSize(string_reference) - function_tracingutils.STACK_BASE ) return EncodedStackString( stack, stack_offset, string_reference=string_reference, size=size, offset=offset, key=key)
def read_enc_value(ea, enc): """ Read encoded value """ if enc == DW_EH_PE_omit: DEBUG("Error in read_enc_val {0:x}".format(ea)) return idc.BADADDR, idc.BADADDR start = ea fmt, mod = enc & 0x0F, enc & 0x70 if fmt == DW_EH_PE_ptr: val = read_pointer(ea) ea += get_address_size_in_bytes() elif fmt in [DW_EH_PE_uleb128, DW_EH_PE_sleb128]: val, ea = read_leb128(ea, fmt == DW_EH_PE_sleb128) if ea - start > 1: make_array(start, ea - start) elif fmt in [DW_EH_PE_sdata2, DW_EH_PE_udata2]: val = read_word(ea) ea += 2 if fmt == DW_EH_PE_sdata2: val = sign_extn(val, 16) elif fmt in [DW_EH_PE_sdata4, DW_EH_PE_udata4]: val = read_dword(ea) ea += 4 if fmt == DW_EH_PE_sdata4: val = sign_extn(val, 32) elif fmt in [DW_EH_PE_sdata8, DW_EH_PE_udata8]: val = read_qword(ea) ea += 8 if f == DW_EH_PE_sdata8: val = sign_extn(val, 64) else: DEBUG("{0:x}: don't know how to handle {1:x}".format(start, enc)) return idc.BADADDR, idc.BADADDR if mod == DW_EH_PE_pcrel: if val != 0: val += start val &= (1 << (get_address_size_in_bits())) - 1 elif mod != DW_EH_PE_absptr: DEBUG("{0:x}: don't know how to handle {1:x}".format(start, enc)) return BADADDR, BADADDR if (enc & DW_EH_PE_indirect) and val != 0: if not idc.isLoaded(val): DEBUG("{0:x}: dereference invalid pointer {1:x}".format( start, val)) return idc.BADADDR, idc.BADADDR val = read_pointer(val) return val, ea
def read_enc_value(ea, enc): """ Read encoded value """ if enc == DW_EH_PE_omit: DEBUG("Error in read_enc_val {0:x}".format(ea)) return idc.BADADDR, idc.BADADDR start = ea fmt, mod = enc&0x0F, enc&0x70 if fmt == DW_EH_PE_ptr: val = read_pointer(ea) ea += get_address_size_in_bytes() elif fmt in [DW_EH_PE_uleb128, DW_EH_PE_sleb128]: val, ea = read_leb128(ea, fmt == DW_EH_PE_sleb128) if ea - start > 1: make_array(start, ea - start) elif fmt in [DW_EH_PE_sdata2, DW_EH_PE_udata2]: val = read_word(ea) ea += 2 if fmt == DW_EH_PE_sdata2: val = sign_extn(val, 16) elif fmt in [DW_EH_PE_sdata4, DW_EH_PE_udata4]: val = read_dword(ea) ea += 4 if fmt == DW_EH_PE_sdata4: val = sign_extn(val, 32) elif fmt in [DW_EH_PE_sdata8, DW_EH_PE_udata8]: val = read_qword(ea) ea += 8 if f == DW_EH_PE_sdata8: val = sign_extn(val, 64) else: DEBUG("{0:x}: don't know how to handle {1:x}".format(start, enc)) return idc.BADADDR, idc.BADADDR if mod == DW_EH_PE_pcrel: if val != 0: val += start val &= (1<<(get_address_size_in_bits())) - 1 elif mod != DW_EH_PE_absptr: DEBUG("{0:x}: don't know how to handle {1:x}".format(start, enc)) return BADADDR, BADADDR if (enc & DW_EH_PE_indirect) and val != 0: if not idc.isLoaded(val): DEBUG("{0:x}: dereference invalid pointer {1:x}".format(start, val)) return idc.BADADDR, idc.BADADDR val = read_pointer(val) return val, ea
def instances(self, reload=False): if reload or not self._inst: xr = self.xrefs(reload) self._inst = {} for x in xr: if not idc.isLoaded(x.frm): continue ins = self.readInst(x.frm) self._inst[ins['address']] = ins return self._inst
def make_function(self, object_version, address): # # call the architecture dependent plugin ########### # self.arch_plugin.make_function_prehook(object_version, address) flags = object_version.get_object_flags() size = object_version.get_size() # create function if not already exist current_flags = idc.GetFlags(address) # if ea is func func = idaapi.get_func(address) if not idaapi.isFunc(current_flags) or (func is not None and (func.startEA != address)): logger.debug( "MakeFunction at 0x%08X : flags=0x%08X, current_flags=0x%08X" % (address, flags, current_flags)) if func is not None: logger.debug( " " "func.startEA[0x%08X]!=address func.endEA[0x%08X]!=(address+size[0x%08X]) " % (func.startEA, func.endEA, size)) if not idc.MakeFunction(address): if not idc.isLoaded(address): logger.error( "Failed at idc.MakeFunction at 0x%08X : data not loaded" % address) else: logger.error("Failed at idc.MakeFunction at 0x%08X" % address) self.clear_function(object_version, address) if not idc.MakeFunction(address): logger.error("Failed at idc.MakeFunction at 0x%08X" % address) # idc.MakeUnknown(address, size, DOUNK_SIMPLE) if idc.AnalyzeArea(address, address + 1) != 1: logger.error("[0x%08X] idc.AnalyzeArea failed" % address) # if(idc.AnalyzeArea(address, address+size) != 1): # logger.error("[0x%08X] idc.AnalyzeArea failed" % address) # if(address == 0x0000000000411558): # raise Exception() if flags is not None: idc.SetFunctionFlags(address, flags) self.set_type(object_version, address) # # call the architecture dependent plugin ########### # self.arch_plugin.make_function_posthook(object_version, address)
def _get_segment_bytes(self, start, end): """ Obtain segment bytes, setting non-loaded bytes to NULL :param int start: segment start EA :param int end: segment end EA :return string: bytes contained in segment """ # Reconstruct the segment, account for bytes which are not loaded. # Can't use xrange() here because we can get a "Python int too large to conver to C long" error seg_range = iter(itertools.count(start).next, end) # a range from start -> end return str( bytearray( idc.Byte(i) if idc.isLoaded(i) else 0 for i in seg_range))
def map_segment(self, address): """ Given an address, map the associated segment into memory so that it can be accesses correctly. >>> cpu_context = ProcessorContext() >>> cpu_context.map_segment(0x1001A32C) :param int address: address within a segment to map """ segStart = idc.SegStart(address) segEnd = idc.SegEnd(address) segSize = utils.align_page_up(segEnd - segStart) segRange = iter(itertools.count(segStart).next, (segStart + segSize)) segBytes = str(bytearray(idc.Byte(i) if idc.isLoaded(i) else 0 for i in segRange)) tracing_cpu_logger.debug( "[map_segment] :: Mapping memory for segment from 0x{:X}::0x{:X}".format(segStart, segStart + segSize)) self.mem_write(segStart, segBytes, False)
def CALL(cpu_context, ip, mnem, opvalues): """ CALL function Attempt to determine the number of arguments passed to the function which are purged on return """ func_ea = opvalues[0].value if not isinstance(func_ea, (int, long)): cpu_logger.debug("CALL 0x{:X} :: call {!r}".format(ip, func_ea)) cpu_logger.debug("Invalid function: {!r}".format(func_ea)) return # For the called function, attempt to locate the function end and examine the "retn" instruction which # will contain the number of bytes to add back to SP. # opvalue1 = idc.GetOperandValue(ip, 0) cpu_logger.debug("CALL 0x{:X} :: call 0x{:X}".format(ip, func_ea)) try: is_loaded = idc.isLoaded(func_ea) except TypeError: is_loaded = False # TODO: Disabled until we can keep track of pointer history. # # Emulate the effects of any known builtin functions. # func_name = idaapi.get_func_name(func_ea) # builtin_func = BUILTINS.get(func_name) # if builtin_func: # try: # args = cpu_context.get_function_args(func_ea) # builtin_func(cpu_context, ip, func_name, args) # except Exception as e: # cpu_logger.warn( # 'Failed to emulate builtin function: {}() at {:#08x} with error: {}'.format( # func_name, ip, e)) # For non-loaded files, reset esp based on number of stack arguments. # (We are assuming the callee is responsible for resetting the stack) if not is_loaded: try: func_data = utils.get_function_data(func_ea) for arg in func_data: loc_type = arg.argloc.atype() # Where was this parameter passed? if loc_type == 1: # ALOC_STACK # reset esp for each stack argument. cpu_context.reg_write("RSP", cpu_context.reg_read("RSP") + cpu_context._byteness) except: # If we can't get function data for non-loaded functions, then we have no way of knowing how to handle # the stack... cpu_logger.debug( "{:#08x} :: Cannot identify function information for value {:#08x}. " "Stack pointer will not be adjusted.".format(ip, func_ea)) return else: # Get address of retn instruction func_end = idc.GetFunctionAttr(func_ea, idc.FUNCATTR_END) if func_end == idc.BADADDR: cpu_logger.debug( "{:#08x} :: Could not retrieve retn instruction for called function: {:#08x}. " "Stack pointer will not be adjusted.".format(ip, func_ea)) return # Find a "retn" and see if we need to adjust rsp. # (All retn's should have the same operand so finding any of them will work). # look for retn address ea = func_end while ea > func_ea: if idc.GetMnem(ea) == "retn": sp_adjust = idc.GetOperandValue(ea, 0) # if retn doesn't adjust the stack, -1 is returned if sp_adjust != -1: cpu_context.reg_write("RSP", cpu_context.reg_read("RSP") + sp_adjust) return ea = idc.PrevHead(ea)