def make_head(ea): flags = idc.GetFlags(ea) if not idc.isHead(flags): idc.SetFlags(ea, flags | idc.FF_DATA) idaapi.autoWait() return is_head(ea) return True
def make_xref(from_ea, to_ea, xref_constructor, xref_size): """Force the data at `from_ea` to reference the data at `to_ea`.""" if not idc.GetFlags(to_ea) or is_invalid_ea(to_ea): DEBUG(" Not making reference (A) from {:x} to {:x}".format( from_ea, to_ea)) return make_head(from_ea) if is_code(from_ea): _CREFS_FROM[from_ea].add(to_ea) _CREFS_TO[to_ea].add(from_ea) else: _DREFS_FROM[from_ea].add(to_ea) _DREFS_TO[to_ea].add(from_ea) # If we can't make a head, then it probably means that we're at the # end of the binary, e.g. the last thing in the `.extern` segment. if not make_head(from_ea + xref_size): assert idc.BADADDR == idc.SegStart(from_ea + xref_size) idaapi.do_unknown_range(from_ea, xref_size, idc.DOUNK_EXPAND) xref_constructor(from_ea) if not is_code_by_flags(from_ea): idc.add_dref(from_ea, to_ea, idc.XREF_USER | idc.dr_O) else: DEBUG(" Not making reference (B) from {:x} to {:x}".format( from_ea, to_ea))
def make_array(ea, size): if ea != idc.BADADDR and ea != 0: flags = idc.GetFlags(ea) if not idc.isByte(flags) or idc.ItemSize(ea) != 1: idc.MakeUnknown(ea, 1, idc.DOUNK_SIMPLE) idc.MakeByte(ea) idc.MakeArray(ea, size)
def getSize(self, withPool=False): """ Computes the size of the function the first time this is called, and caches that computation for later Parsed Comment commands: <endpool> specifies the last element in the pool. That element's size is included in the pool. to specify a function has no pool at all, put the comment command at its last instruction. :param withPool: (bool) somewhat of a heuristic. Computes the pool size as simply the amount of bytes since the function's code portion finished (endEA) until a new code head is detected :return: Returns the size of the Function in bytes: EndEA - StartEA (if no pool selected, otherwise + pool) """ if not withPool: return self.func.end_ea - self.func.start_ea head = self.func.end_ea # check if the function is set to have no pool instSize = self.isThumb() and 2 or 4 endCmt = idc.Comment(self.func.end_ea - instSize) if endCmt and '<endpool>' in endCmt: return self.func.end_ea - self.func.start_ea while not idc.isCode(idc.GetFlags(head)): # manual pool computation, trust and assume that this is the last element in the pool! if idc.Comment(head) and '<endpool>' in idc.Comment(head): head += idc.get_item_size(head) break # advance to next data element head += idc.get_item_size(head) return head - self.func.start_ea
def yacheck_apply_struct(self): addrs = yaunit.load('apply_struct') for k in range(-1, 4): # retrieve struct id addr = addrs[k + 1] sid = idc.GetStrucIdByName('apply_struct_%x' % (k + 1)) self.assertNotEqual(sid, idaapi.BADADDR) # begin to check if something is applied flags = idaapi.get_flags_novalue(addr) self.assertTrue(idaapi.isStroff(flags, 1)) ti = idaapi.opinfo_t() flags = idc.GetFlags(addr) self.assertTrue(idaapi.get_opinfo(addr, 1, flags, ti)) # apply struct only if k == -1: # check struct is applied self.assertEqual(ti.path.ids[0], sid) continue # check union is selected & applied at target address uid = idc.GetStrucIdByName('apply_union_%x' % (k + 1)) self.assertNotEqual(uid, idaapi.BADADDR) fid = idc.GetMemberId(uid, k) self.assertNotEqual(fid, -1) # check union is applied self.assertEqual([x for x in ti.path.ids if x], [sid, fid])
def post_analysis_stuff(self, results): if results.has_formula(): self.action_selector.addItem(self.parent.HIGHLIGHT_CODE) self.action_selector.addItem(self.parent.GRAPH_DEPENDENCY) self.formula_area.setText(self.parent.results.formula) if results.has_values(): self.action_selector.addItem(self.parent.DISASS_UNKNOWN_TARGET) self.action_selector.setEnabled(True) self.action_button.setEnabled(True) report = HTMLReport() report.add_title("Results", size=3) report.add_table_header(["address", "assertion", "status", "values"]) addr = make_cell("%x" % results.target) status = make_cell(results.get_status(), color=results.color, bold=True) vals = "" for value in results.values: flag = idc.GetFlags(value) typ = self.type_to_string(flag) vals += "%x type:%s seg:%s fun:%s<br/>" % ( value, typ, idc.SegName(value), idc.GetFunctionName(value)) report.add_table_line([ addr, make_cell(cgi.escape(results.query)), status, make_cell(vals) ]) report.end_table() data = report.generate() self.result_area.setHtml(data)
def heatmap_trace(self): try: index = self.traces_tab.currentIndex() trace = self.core.traces[self.id_map[index]] if self.heatmaped: self.heatmap_button.setText("Heatmap") color = lambda x: 0xffffff else: self.heatmap_button.setText("Heatmap undo") self.heatmap_button.setFlat(True) hit_map = trace.address_hit_count color_map = self.compute_step_map(set(hit_map.values())) print color_map color = lambda x: color_map[hit_map[x]] for inst in trace.instrs.values(): if idc.isCode(idc.GetFlags(inst.address)): c = color(inst.address) idc.SetColor(inst.address, idc.CIC_ITEM, c) if not self.heatmaped: self.heatmap_button.setFlat(False) self.heatmaped = True else: self.heatmaped = False except KeyError: print "No trace found"
def crefs_from(ea, only_one=False, check_fixup=True): flags = idc.GetFlags(ea) if not idc.isCode(flags): return fixup_ea = idc.BADADDR seen = False has_one = only_one if check_fixup: fixup_ea = idc.GetFixupTgtOff(ea) if not is_invalid_ea(fixup_ea) and is_code(fixup_ea): seen = only_one has_one = True yield fixup_ea if has_one and _stop_looking_for_xrefs(ea): return for target_ea in _xref_generator(ea, idaapi.get_first_cref_from, idaapi.get_next_cref_from): if target_ea != fixup_ea and not is_invalid_ea(target_ea): seen = only_one yield target_ea if seen: return if not seen and ea in _CREFS_FROM: for target_ea in _CREFS_FROM[ea]: seen = only_one yield target_ea if seen: return
def disassemble_from_trace(self): try: index = self.traces_tab.currentIndex() trace = self.core.traces[self.id_map[index]] self.disassemble_button.setFlat(True) found_match = False for k, inst in trace.instrs.items(): if k in trace.metas: for name, arg1, arg2 in trace.metas[k]: if name == "wave": self.parent.log("LOG", "Wave n°%d encountered at (%s,%x) stop.." % (arg1, k, inst.address)) prev_inst = trace.instrs[k-1] idc.MakeComm(prev_inst.address, "Jump into Wave %d" % arg1) self.disassemble_button.setFlat(False) return # TODO: Check that the address is in the address space of the program if not idc.isCode(idc.GetFlags(inst.address)): found_match = True # TODO: Add an xref with the previous instruction self.parent.log("LOG", "Addr:%x not decoded as an instruction" % inst.address) if idc.MakeCode(inst.address) == 0: self.parent.log("ERROR", "Fail to decode at:%x" % inst.address) else: idaapi.autoWait() self.parent.log("SUCCESS", "Instruction decoded at:%x" % inst.address) if not found_match: self.parent.log("LOG", "All instruction are already decoded") self.disassemble_button.setFlat(False) except KeyError: print "No trace found to use"
def getOrigDisasm(self): # type: () -> str """ Gets the original disassembly without any further applied transformations However, the formatting is different from the original and is more convenient for parsing :return: the disassembly """ flags = idc.GetFlags(self.ea) if idc.isCode(flags): disasm = idc.GetDisasm(self.ea) disasm = self._filterComments(disasm) disasm = disasm.replace(' ', ' ') elif idc.isStruct(flags): disasm = self._getStructDisasm() # disasm = "INVALID" elif idc.isAlign(flags): disasm = idc.GetDisasm(self.ea) disasm = self._convertAlignDisasm(disasm) elif idc.isASCII(flags): content = self.getContent() numNewLines = content.count(0x0A) if numNewLines > 1: disasm = '.ascii "' else: disasm = '.asciz "' for i in range(len(content)): if content[i] == 0x00: disasm += '"' elif chr(content[i]) == '"': disasm += '\\\"' elif chr(content[i]) == '\\': disasm += '\\\\' elif content[i] == 0x0A: disasm += '\\n' numNewLines -= 1 if numNewLines > 1: disasm += '"\n\t.ascii "' elif numNewLines == 1: disasm += '"\n\t.asciz "' elif chr(content[i]) == ' ': disasm += ' ' elif not chr(content[i]).isspace(): disasm += chr(content[i]) else: # TODO [INVALID] arm-none-eabi doesn't recognize \xXX? \x seems to become a byte. disasm += '\\x%02X' % content[i] elif idc.isData(flags): disasm = self._getDataDisasm() else: disasm = idc.GetDisasm(self.ea) disasm = self._filterComments(disasm) disasm = disasm.replace(' ', ' ') # parse force command if '<force>' in self.getComment(): comment = self.getComment() disasm = comment[comment.index('<force> ') + len('<force> '):] return disasm
def _process_stubs_section(segstart, make_thunk, next_stub): """Process all the functions in a __stubs section.""" segend = idc.SegEnd(segstart) # We'll go through each address and check if it has a reference. If it does, it is likely a # stub. As long as the address doesn't already have a stub name, process it. for ea in idau.Addresses(segstart, segend, step=1): if idc.isRef(idc.GetFlags(ea)) and not stub_name_target(idau.get_ea_name(ea)): _process_possible_stub(ea, make_thunk, next_stub)
def decode_here_clicked(self): inst = idc.here() if not idc.isCode(idc.GetFlags(inst)): print "Not code instruction" else: raw = idc.GetManyBytes(inst, idc.NextHead(inst) - inst) s = to_hex(raw) self.decode_ir(s)
def make_code(start, end): for i in range((end - start) / 4): addr = start + (i * 4) if not idc.isCode(idc.GetFlags(addr)): idaapi.do_unknown_range(addr, 4, 0) idaapi.auto_make_code(addr) idc.MakeCode(addr) return
def valid_oreans_macro_entry(address): if idc.isCode( idc.GetFlags(address)) and get_mnemonic(address) == ENTRY_MNEM: jump_location_address = get_jump_destination(address) if (jump_location_address >= OREANS_SEGMENT.startEA) and ( jump_location_address <= OREANS_SEGMENT.endEA): return True return False
def get_function_xrefs_at_ea(base_address, ea, function_xrefs, minSegAddress, maxSegAddress): # TODO: we should look at the operand number xrefCode = idc.Rfirst0(ea) # code xref while xrefCode != idc.BADADDR: if (idc.GetFlags(xrefCode) & idc.FF_FUNC) == idc.FF_FUNC: function_xrefs[ea - base_address] = GetItemContaining(xrefCode) xrefCode = idc.Rnext0(ea, xrefCode)
def scan_data_for_code_refs(begin_ea, end_ea, read_func, read_size): """Read in 4- or 8-byte chunks of data, and try to see if they look like pointers into the code.""" global POSSIBLE_CODE_REFS for ea in xrange(begin_ea, end_ea, read_size): qword = read_func(ea) if idc.isCode(idc.GetFlags(qword)): POSSIBLE_CODE_REFS.add(qword)
def read_bytes_slowly(start, end): bytestr = [] for i in xrange(start, end): if idc.hasValue(idc.GetFlags(i)): bt = idc.Byte(i) bytestr.append(chr(bt)) else: bytestr.append("\x00") return "".join(bytestr)
def is_end_of_flow(self, instruction): """Return whether the last instruction processed end the flow.""" next_addr = instruction.ip + idc.ItemSize(instruction.ip) next_addr_flags = idc.GetFlags(next_addr) if idc.isCode(next_addr_flags) and idc.isFlow(next_addr_flags): return False return True
def have_string(self, operand): if operand[0] != 'a': return False loc_addr = idc.LocByName(operand) if idc.GetString(loc_addr) != '' and idc.isData(idc.GetFlags(loc_addr)): return True else: return False
def disassemble_new_targets(self, enabled): for value in self.results.values: flag = idc.GetFlags(value) if not idc.isCode(flag) and idc.isUnknown(flag): res = idc.MakeCode(value) if res == 0: print "Try disassemble at:" + hex(value) + " KO" #TODO: Rollback ? else: print "Try disassemble at:" + hex(value) + " Success !"
def setBPs(self): """ Set breakpoints on all CALL and RET instructions in all of the executable sections. """ for seg_ea in idautils.Segments(): for head in idautils.Heads(seg_ea, idc.SegEnd(seg_ea)): if idc.isCode(idc.GetFlags(head)): # Add BP if instruction is a CALL if is_call(head): self.addBP(head)
def _isFunctionPointer(self, firstLineSplitDisasm): """ Identifies the construct 'DCD <funcName>' as a function pointer entry! The function Name is checked in the database for confirmation! This actually extend to none-identified functions, because it only checks if the location is valid code. :param firstLineSplitDisasm: list of space and comma split operands in the instruction. ['DCD', 'sub_DEADBEEF+1'] :return: """ return len(firstLineSplitDisasm) >= 2 and firstLineSplitDisasm[0] == 'DCD' \ and idc.isCode(idc.GetFlags(idc.get_name_ea(0, firstLineSplitDisasm[1])))
def fix_code(start_address, end_address): # Todo: There might be some data in the range of codes. offset = start_address while offset <= end_address: offset = idc.NextAddr(offset) flags = idc.GetFlags(offset) if not idc.isCode(flags): # Todo: Check should use MakeCode or MakeFunction # idc.MakeCode(offset) idc.MakeFunction(offset)
def compute_nb_instr(self): #return 1000 count = 0 start, stop = self.seg_mapping[ ".text"] #TODO: Iterate all segs writable current = start while current <= stop: if idc.isCode(idc.GetFlags(current)): count += 1 current = idc.NextHead(current, stop) return count
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 getBlocks(self, function_offset): blocks = [] function_chart = idaapi.FlowChart(idaapi.get_func(function_offset)) for block in function_chart: extracted_block = [] for instruction in idautils.Heads(block.startEA, block.endEA): if idc.isCode(idc.GetFlags(instruction)): extracted_block.append(instruction) if extracted_block: blocks.append(extracted_block) return sorted(blocks)
def load_symbols_from_ida(self): for ea, name in idautils.Names(): flag = idc.GetFlags(ea) if not idc.hasUserName(flag): continue seg_ea = idc.SegStart(ea) seg_name = idc.SegName(ea) if seg_name not in self.sections: continue sym_type = 'function' if idc.isCode(flag) else 'object' self.symbols[name] = (seg_name, ea - seg_ea, sym_type)
def yacheck_reference_views(self): eas = yaunit.load('reference_views') idx = 0 for ea in eas: (operand, is_num, reference) = tests[idx] idx += 1 ti = idaapi.opinfo_t() f = idc.GetFlags(ea) self.assertTrue(idaapi.get_opinfo(ea, operand, f, ti)) self.assertTrue(ti.ri.type()) self.assertEqual(ti.ri.base, reference)
def find_function_ends(location, end_mnem_bytes=None): """ Description: Identifies all possible function ends before the next function or Align. Input: location - The EA to search after end_mnem_bytes - Try to end functions on a particular instruction Instructions are entered as space separated bytes (i.e. 'C2' for 'retn') 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 'retn' Output: ends - A list of function end EAs sorted: end_mnem_bytes, retn, jmp """ # foreach target bytes: # step instructions down # if instruction matches the target bytes, add to the corresponding output list # if we hit a function or an align, quit # return ends in the order: # end_nmem_bytes # retn # jmp # others, sorted ascending max_location = None ea = location while max_location is None: ea = idc.NextHead(ea) if idaapi.get_func(ea) or idc.isAlign(idc.GetFlags(ea)): max_location = ea elif ea == idc.BADADDR: max_location = idaapi.getseg(location).endEA max_location = min(max_location, idaapi.getseg(location).endEA) targets = ['C3', 'C2', 'E9', 'EA', 'EB'] if end_mnem_bytes: targets.insert(0, end_mnem_bytes) ends = {} for target in targets: function_ends = [] ea = find_binary_instruction_start(location, idc.SEARCH_DOWN, target, max_location=max_location) while ea != idc.BADADDR: if ea > max_location: break else: function_ends.append(ea) ea = find_binary_instruction_start(ea + 11, idc.SEARCH_DOWN, target, max_location=max_location) ends[target] = function_ends return [end + idc.ItemSize(end) for end in ((ends[end_mnem_bytes] if end_mnem_bytes else []) + sorted(ends['C3'] + ends['C2']) + sorted(itertools.chain.from_iterable(ends[target] for target in targets[-3:])))]
def compute_nb_instr(self): return 0 # FIXME: by iterating all segments count = 0 start, stop = self.seg_mapping[ ".text"] # TODO: Iterate all executable segs current = start while current <= stop: if idc.isCode(idc.GetFlags(current)): count += 1 current = idc.NextHead(current, stop) return count