def trans_cb_addr_to_IDA(addr): try: cb = sark.CodeBlock(addr) if cb: return cb.startEA return idaapi.BADADDR except: return idaapi.BADADDR
def btn_mark_color(self): sender = self.parent.sender() cb = sark.CodeBlock() if sender is self.btn_mark_neutral: cb.color = col_t2ida(self.plugin.col_neutral) elif sender is self.btn_mark_visited: cb.color = col_t2ida(self.plugin.col_visited) elif sender is self.btn_mark_unreachable: cb.color = col_t2ida(self.plugin.col_unreachable)
def coverage(pin_bb_log_file): base = idaapi.get_imagebase() covered_functions = set() for bb in bb_read_pin_logs(pin_bb_log_file): sark.CodeBlock(bb.start + base).color = 0xffff00 sark_fn = sark.Function(bb.start + base) covered_functions.add(sark_fn.name) all_functions = set() for fn in sark.functions(): all_functions.add(fn.name) print "function coverage summary! coverage {:.0f}%".format( float(len(covered_functions)) / float(len(all_functions)) * 100)
def get_func_hash(ea): m = md5.new() ea = sark.Function(ea).start_ea blk = sark.CodeBlock(ea) went_over_blks = set() rem_blks = [blk] while len(rem_blks): blk = rem_blks[0] rem_blks = rem_blks[1:] m.update('s') m.update(struct.pack(">L", blk.start_ea)) for n_blk in blk.next: m.update(struct.pack(">L", n_blk.start_ea)) if n_blk.start_ea not in went_over_blks: rem_blks += [n_blk] went_over_blks.add(blk.start_ea) return m.digest()
def analyzeFunctionBlock(self, block_ea): """Return pairs indicating function calls (or fptr refs) from the lines in the basic block instance. Args: block_ea (int): basic block ea Return Value: (ordered) list of tuples: [<address of function ref (src), referenced address of the function (dest)>, ] """ function_calls = [] try: func_start = sark.Function(block_ea).start_ea block_lines = sark.CodeBlock(block_ea).lines except Exception: return function_calls # scan each of the lines for line in block_lines: instr_pos = line.ea call_candidates = set() # Data Refs (strings, fptrs) for ref in line.drefs_from: # Check for a string (finds un-analyzed strings too) str_const = self.disas.stringAt(ref) if str_const is not None and len(str_const) >= MIN_STR_SIZE: continue # Check for an fptr try: call_candidates.add(sark.Function(ref).start_ea) except sark.exceptions.SarkNoFunction: continue # Check for a function call for cref in line.crefs_from: try: if (cref == func_start and line.insn.is_call ) or sark.Function(cref).start_ea != func_start: call_candidates.add(sark.Function(cref).start_ea) except sark.exceptions.SarkNoFunction: continue # handle each ref for ref in call_candidates: # record the call function_calls.append((instr_pos, sark.Function(ref).start_ea)) # return the result return function_calls
def analyzeIslandFunction(self, blocks): """Analyze a given island function, and creates a canonical representation for it. Args: blocks (list): ordered list of code blocks (as returned from searchIslands()) Return Value: IslandContext object representing the analyzed island """ island_start = blocks[0].startEA func = sark.Function(island_start) func_start = func.startEA context = islandContext()(self.funcNameInner(func.name), island_start) for block in blocks: for line in sark.CodeBlock(block.startEA).lines: # Numeric Constants data_refs = list(line.drefs_from) for oper in filter(lambda x: x.type.is_imm, line.insn.operands): if oper.imm not in data_refs: context.recordConst(oper.imm) # Data Refs (strings, fptrs) for ref in data_refs: # Check for a string (finds un-analyzed strings too) str_const = self.disas.stringAt(ref) if str_const is not None and len( str_const) >= MIN_STR_SIZE: context.recordString(str_const) continue # Check for an fptr called_func = self.disas.funcAt(ref) if called_func is not None: context.recordCall(self.disas.funcStart(called_func)) # Code Refs (calls) for cref in line.crefs_from: called_func = self.disas.funcAt(cref) if called_func is None: continue called_func_start = self.disas.funcStart(called_func) if (cref == func_start and line.insn.is_call ) or called_func_start != func_start: context.recordCall(called_func_start) return context
def CodeBlock(ea): cb = sark.CodeBlock(ea) #fix next and prev blocks - must be in func next = [] prev = [] for e_cb in cb.next: if sark.Function(e_cb.start_ea).start_ea == sark.Function( cb.start_ea).start_ea: next += [e_cb] for e_cb in cb.prev: if sark.Function(e_cb.start_ea).start_ea == sark.Function( cb.start_ea).start_ea: prev += [e_cb] class new_cb(object): pass ncb = new_cb() ncb.start_ea = cb.start_ea ncb.end_ea = cb.end_ea ncb.next = next ncb.prev = prev return ncb
def analyzeFunction(self, func_ea, src_mode): """Analyze a given function, and creates a canonical representation for it. Args: func_ea (int): effective address of the wanted function src_mode (bool): True iff analyzing a self-compiled source file, otherwise analyzing a binary function Return Value: FunctionContext object representing the analyzed function """ func = sark.Function(func_ea) if src_mode: context = sourceContext()(self.funcNameInner( func.name), 0) # Index is irrelevant for the source analysis else: context = binaryContext()(func_ea, self.funcNameInner( func.name), 0) # The index will be adjusted later, manually func_start = func.start_ea instr_count = 0 call_candidates = set() code_hash = md5() for line in func.lines: instr_count += 1 # Numeric Constants data_refs = list(line.drefs_from) for oper in [x for x in line.insn.operands if x.type.is_imm]: if oper.imm not in data_refs: context.recordConst(oper.imm) # Data Refs (strings, fptrs) for ref in data_refs: # Check for a string (finds un-analyzed strings too) str_const = self.disas.stringAt(ref) if str_const is not None and len(str_const) >= MIN_STR_SIZE: context.recordString(str_const) continue # Check for an fptr called_func = self.disas.funcAt(ref) if called_func is not None: call_candidates.add(self.disas.funcStart(called_func)) elif src_mode: call_candidates.add(ref) continue # Code Refs (calls and unknowns) for cref in line.crefs_from: called_func = self.disas.funcAt(cref) if called_func is None: continue called_func_start = self.disas.funcStart(called_func) if (cref == func_start and line.insn.is_call) or called_func_start != func_start: call_candidates.add(called_func_start) # in binary mode don't let the call_candidates expand too much if not src_mode: [context.recordCall(x) for x in call_candidates] call_candidates = set() # hash the instruction (only in source mode) else: # two cases: # 1. No linker fixups, hash the binary - easy case # 2. Linker fixups, hash the text (includes the symbol name that the linker will use too) has_fixups = False # data variables for dref in line.drefs_from: if sark.Line(dref).name in self.disas.exports(): has_fixups = True break # external code functions if not has_fixups: for cref in line.crefs_from: if sark.Line(cref).name in self.disas.exports(): has_fixups = True break # case #2 if has_fixups: code_hash.update(line.disasm.encode("utf-8")) # case #1 else: code_hash.update(line.bytes) # check all the call candidates together if src_mode: for candidate in call_candidates: ref_func = None called_func = self.disas.funcAt(candidate) if called_func is not None: ref_func = self.disas.funcName(called_func) risky = False else: ref_func = self.disas.nameAt(candidate) risky = True # check if known or unknown if sark.Line(candidate).disasm.split(" ")[0].lower() in ( "extrn", "extern", "import"): context.recordUnknown(ref_func, is_fptr=risky) elif not risky: context.recordCall(ref_func) # set the function's hash context.setHash(code_hash.hexdigest()) context.setFrame(func.frame_size) context.setInstrCount(instr_count) # Now, record the code blocks flow = idaapi.FlowChart(func.func_t) for block in flow: try: context.recordBlock( len(list(sark.CodeBlock(block.start_ea).lines))) except Exception: # happens with code outside of a function continue context.blocks.sort(reverse=True) # Now add the flow analysis context.setCallOrder(self.disas.analyzeFunctionGraph( func_ea, src_mode)) return context
def fun(addr, color): cb = sark.CodeBlock(addr) if cb: cb.color = color
def fun(): cb[0] = sark.CodeBlock()
def _get_block_ranges(eas, reg): ranges = [] blks = set() for ea in eas: blk_ea = sark.CodeBlock(ea).start_ea blks |= set([blk_ea]) #for blk_ea in blks: for blk_ea in sorted(list(blks)): # four possible ranges: # 1. start till change # 2. change till end # 3. change till change - in case all references are in one block # 4. start till end # notice that 1,2 may both happen in a block possibility_one__found_ref = False possibility_one_two__found_change = False possibility_one__first_change_ea = None possibility_two__last_change_ea = None possibility_two__ref_after_last_change_ea = None possibility_three__first_ref_after_change_ea = None possibility_three__first_change_after_ref_ea = None possibility_four__no_change = True s_addr = None blk = sark.CodeBlock(blk_ea) for l in blk.lines: if (l.ea in eas): #needs to be in range if possibility_one_two__found_change and ( possibility_two__ref_after_last_change_ea is None): possibility_two__ref_after_last_change_ea = l.ea if (possibility_one_two__found_change) and ( possibility_three__first_change_after_ref_ea is None ) and (possibility_three__first_ref_after_change_ea is None): possibility_three__first_ref_after_change_ea = l.ea possibility_one__found_ref = True #elif (l.ea not in eas) and (reg in oregami_gen.proc_ops.get_regs(l.ea)): #needs to be not in range elif (l.ea not in eas) and (oregami_gen.proc_ops.is_load( l.ea, reg) or oregami_gen.proc_ops.is_store( l.ea, reg)): #needs to be not in range if (not possibility_one_two__found_change) and ( possibility_one__found_ref): possibility_one__first_change_ea = l.ea if (possibility_three__first_ref_after_change_ea is not None ) and (possibility_three__first_change_after_ref_ea is None): possibility_three__first_change_after_ref_ea = l.ea possibility_two__ref_after_last_change_ea = None possibility_one_two__found_change = True possibility_four__no_change = False # possibility 1 - found change after only references if possibility_one__first_change_ea is not None: ranges += [(blk.start_ea, possibility_one__first_change_ea)] debug('p1: %x:%x' % (ranges[-1][0], ranges[-1][1])) # possibility 2 - found only references after change if possibility_two__ref_after_last_change_ea is not None: ranges += [(possibility_two__ref_after_last_change_ea, blk.end_ea)] debug('p2: %x:%x' % (ranges[-1][0], ranges[-1][1])) # possibility 3 - found sequrence change->ref->change if (possibility_three__first_ref_after_change_ea is not None) and (possibility_three__first_change_after_ref_ea is not None): ranges += [(possibility_three__first_ref_after_change_ea, possibility_three__first_change_after_ref_ea)] debug('p3: %x:%x' % (ranges[-1][0], ranges[-1][1])) # possibility 4 - no change happened if possibility_four__no_change: ranges += [(blk.start_ea, blk.end_ea)] debug('p4: %x:%x' % (ranges[-1][0], ranges[-1][1])) return ranges
def _get_block_ranges(eas, reg): ranges = [] blks = set() for ea in eas: blk_ea = sark.CodeBlock(ea).start_ea blks |= {blk_ea} # for blk_ea in blks: for blk_ea in sorted(list(blks)): # four possible ranges: # 1. start till change # 2. change till end # 3. change till change - in case all references are in one block # 4. start till end # notice that 1,2 may both happen in a block pos1__found_ref = False pos1_2__found_change = False pos1__first_change_ea = None pos2__ref_after_last_change_ea = None pos3__first_ref_after_change_ea = None pos3__first_change_after_ref_ea = None pos4__no_change = True blk = sark.CodeBlock(blk_ea) for line in blk.lines: opbits = RegInstruction(line.ea).get_reg_op_bits( reg, op_mask=UsageBits.OP_RW | UsageBits.USAGE_MASK) if line.ea in eas: # needs to be in range if pos1_2__found_change and \ (pos2__ref_after_last_change_ea is None): pos2__ref_after_last_change_ea = line.ea if pos1_2__found_change and \ (pos3__first_change_after_ref_ea is None) and \ (pos3__first_ref_after_change_ea is None): pos3__first_ref_after_change_ea = line.ea pos1__found_ref = True # needs to be not in range elif ((line.ea not in eas) and bool(opbits & UsageBits.USAGE_EXPLICIT) and bool(opbits & UsageBits.OP_RW)): if (not pos1_2__found_change) and pos1__found_ref: pos1__first_change_ea = line.ea if (pos3__first_ref_after_change_ea is not None) and \ (pos3__first_change_after_ref_ea is None): pos3__first_change_after_ref_ea = line.ea pos2__ref_after_last_change_ea = None pos1_2__found_change = True pos4__no_change = False # possibility 1 - found change after only references if pos1__first_change_ea is not None: ranges += [(blk.start_ea, pos1__first_change_ea)] logger.debug('p1: %x:%x' % (ranges[-1][0], ranges[-1][1])) # possibility 2 - found only references after change if pos2__ref_after_last_change_ea is not None: ranges += [(pos2__ref_after_last_change_ea, blk.end_ea)] logger.debug('p2: %x:%x' % (ranges[-1][0], ranges[-1][1])) # possibility 3 - found sequrence change->ref->change if (pos3__first_ref_after_change_ea is not None) and \ (pos3__first_change_after_ref_ea is not None): ranges += [(pos3__first_ref_after_change_ea, pos3__first_change_after_ref_ea)] logger.debug('p3: %x:%x' % (ranges[-1][0], ranges[-1][1])) # possibility 4 - no change happened if pos4__no_change: ranges += [(blk.start_ea, blk.end_ea)] logger.debug('p4: %x:%x' % (ranges[-1][0], ranges[-1][1])) return ranges