def is_invalid_ea(ea): """Returns `True` if `ea` is not valid, i.e. it doesn't point into any valid segment.""" if (idc.BADADDR == ea) or \ (idc.get_segm_name(ea) == "LOAD"): return True try: idc.get_segm_attr(idc.get_segm_start(ea), idc.SEGATTR_TYPE) return False # If we get here, then it must be a valid ea! except: return True
def get_bytes(name_or_addr): """ Obtains segment bytes for the segment in which EA is contained or by segment name. This will be on demand and segment bytes will be cached if they have not already been obtained :param string|int name_or_addr: either the name of a segment or an EA within a segment :return bytes: bytes which are contained with the segment """ seg_start = get_start(name_or_addr) seg_bytes = _cache.get(seg_start) if seg_bytes is None: seg_end = idc.get_segm_attr(seg_start, idc.SEGATTR_END) # This check will make an adjustment to seg_end based on whether the previous address has a value # or not. In some instances, seg_end will throw us into an adjacent section which has data and # we'll end up getting bad values here. if idc.is_loaded(seg_end) and not idc.is_loaded(seg_end - 1): seg_end -= 1 # Need to find the actual end address of the section data since IDA returns addresses that have # no data... while not idc.is_loaded(seg_end): seg_end -= 1 seg_bytes = _obtain_bytes(seg_start, seg_end) _cache[seg_start] = seg_bytes return seg_bytes
def is_code(ea): if is_invalid_ea(ea): return False seg_ea = idc.get_segm_start(ea) seg_type = idc.get_segm_attr(seg_ea, idc.SEGATTR_TYPE) return (seg_type == idc.SEG_CODE)
def processDataSegs(): funcdata = {} datafunc = {} for n in xrange(idaapi.get_segm_qty()): seg = idaapi.getnseg(n) ea = seg.startEA segtype = idc.get_segm_attr(ea, idc.SEGATTR_TYPE) if segtype in [idc.SEG_DATA, idc.SEG_BSS]: start = idc.get_segm_start(ea) end = idc.get_segm_end(ea) cur = start while cur <= end: refs = [v for v in DataRefsTo(cur)] for fea in refs: name = get_unified_funcname(fea) if len(name) == 0: continue if name not in funcdata: funcdata[name] = [cur] else: funcdata[name].append(cur) if cur not in datafunc: datafunc[cur] = [name] else: datafunc[cur].append(name) cur = NextHead(cur) return funcdata, datafunc
def get_all_func(): num = 0 content = [] for func in idautils.Functions(): seg_perm = idc.get_segm_attr(func,SEGATTR_PERM) # 段属性 if(5 !=seg_perm): continue seg_name = idc.get_segm_name(func) # 段名 if(".plt" == seg_name): continue func_name = idc.get_func_name(func) # 函数名 func_flags = hex(idc.get_func_attr(func,FUNCATTR_FLAGS))# 函数信息 func_head = hex(idc.get_func_attr(func,FUNCATTR_START)) # 函数头 func_end = hex(idc.get_func_attr(func,FUNCATTR_END)) # 函数尾 l = [] l.append(num) l.append(seg_name) l.append(seg_perm) l.append(func_name) l.append(func_flags) l.append(func_head) l.append(func_end) content.append(l) num += 1 #print(l) return content
def _is_extern_seg(seg): """Returns `True` if `seg` refers to a segment with external variable or function declarations.""" if not seg: return False seg_type = idc.get_segm_attr(seg.start_ea, idc.SEGATTR_TYPE) return seg_type == idc.SEG_XTRN
def _get_memory(self): result = bytearray() segment_starts = [ea for ea in idautils.Segments()] offsets = [] start_len = 0 for start in segment_starts: end = idc.get_segm_attr(start, idc.SEGATTR_END) result += ida_bytes.get_bytes(start, end - start) offsets.append((start, start_len, len(result))) start_len = len(result) return bytes(result), offsets
def getx86CodeSize_ida7(ea=None): ''' For a given EA, finds the code size. Returns 16 for-16bit, 32 for 32-bit, or 64 for 64-bit. If no EA is given, searches through all segments for a code segment to use. ''' if ea is None: for seg in idautils.Segments(): if idc.get_segm_attr(seg, idc.SEGATTR_TYPE) == idc.SEG_CODE: ea = seg break if ea is None: raise RuntimeError('Could not find code segment to use for getx86CodeSize') bitness = idc.get_segm_attr(ea, idc.SEGATTR_BITNESS) if bitness == 0: return 16 elif bitness == 1: return 32 elif bitness == 2: return 64 raise RuntimeError('Bad bitness')
def getx86CodeSize_ida7(ea=None): ''' For a given EA, finds the code size. Returns 16 for-16bit, 32 for 32-bit, or 64 for 64-bit. If no EA is given, searches through all segments for a code segment to use. ''' if ea is None: for seg in idautils.Segments(): if idc.get_segm_attr(seg, idc.SEGATTR_TYPE) == idc.SEG_CODE: ea = seg break if ea is None: raise RuntimeError( 'Could not find code segment to use for getx86CodeSize') bitness = idc.get_segm_attr(ea, idc.SEGATTR_BITNESS) if bitness == 0: return 16 elif bitness == 1: return 32 elif bitness == 2: return 64 raise RuntimeError('Bad bitness')
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 is_external_segment_by_flags(ea): """Returns `True` if IDA believes that `ea` belongs to an external segment.""" try: seg_ea = idc.get_segm_start(ea) seg_type = idc.get_segm_attr(seg_ea, idc.SEGATTR_TYPE) if seg_type == idc.SEG_XTRN: _EXTERNAL_SEGMENTS.add(seg_ea) return True else: return False except: return False
def _is_executable_seg(seg): """Returns `True` a segment's data is executable.""" if 0 != (seg.perm & ida_segment.SEGPERM_EXEC): return True seg_type = idc.get_segm_attr(seg.start_ea, idc.SEGATTR_TYPE) if seg_type in (idc.SEG_CODE, idc.SEG_XTRN): return True sclass = ida_segment.get_segm_class(seg) if sclass: return "CODE" in sclass or "XTRN" in sclass return False
def _get_segments(self, attr): segments = [] start = idc.BADADDR end = idc.BADADDR seg = idc.get_first_seg() while seg != idc.BADADDR: if idc.get_segm_attr(seg, idc.SEGATTR_TYPE) == attr: start = idc.get_segm_start(seg) end = idc.get_segm_end(seg) segments.append((start, end)) seg = idc.get_next_seg(seg) return segments
def get_start(name_or_addr): """ Retrieves the starting address for the segment containing the given name or address. :param string|int name_or_addr: either the name of a segment or an EA within a segment """ if isinstance(name_or_addr, str): segment = ida_segment.get_segm_by_name(name_or_addr) if segment is None: raise AssertionError( "could not find segment for {}".format(name_or_addr)) return segment.start_ea elif isinstance(name_or_addr, numbers.Number): return idc.get_segm_attr(name_or_addr, idc.SEGATTR_START) else: raise ValueError("Invalid value: {}".format(name_or_addr))
def segment_start(self, val): """ Retrieves the start EA for given name or EA within a segment. :param string|int val: either the name of a segment or an EA within a segment """ if isinstance(val, str): segment = idaapi.get_segm_by_name(val) if segment is None: raise AssertionError( "could not find segment for {}".format(val)) return segment.start_ea elif isinstance(val, numbers.Number): return idc.get_segm_attr(val, idc.SEGATTR_START) else: raise ValueError('Invalid value: {}'.format(val))
def processExternalSegs(): funcdata = {} datafunc = {} for n in xrange(idaapi.get_segm_qty()): seg = idaapi.getnseg(n) ea = seg.startEA segtype = idc.get_segm_attr(ea, idc.SEGATTR_TYPE) if segtype in [idc.SEG_XTRN]: start = idc.get_segm_start(ea) #idc.SegStart(ea) end = idc.get_segm_end(ea) #idc.SegEnd(ea) cur = start while cur <= end: name = get_unified_funcname(cur) funcdata[name] = hex(cur) cur = idc.next_head(cur) return funcdata
def segment_bytes(self, val): """ Will obtain segment bytes for the segment in which EA is contained or by segment name. This will be on demand and segment bytes will be cached if they have not already been obtained :param string|int val: either the name of a segment or an EA within a segment :return string: bytes which are contained with the segment """ seg_start = self.segment_start(val) seg_bytes = self.segments.get(seg_start) if seg_bytes is None: seg_end = idc.get_segm_attr(seg_start, idc.SEGATTR_END) seg_bytes = self._get_segment_bytes(seg_start, seg_end) self.segments[seg_start] = seg_bytes return seg_bytes
def get_bytes(name_or_addr): """ Obtains segment bytes for the segment in which EA is contained or by segment name. This will be on demand and segment bytes will be cached if they have not already been obtained :param string|int name_or_addr: either the name of a segment or an EA within a segment :return bytes: bytes which are contained with the segment """ seg_start = get_start(name_or_addr) seg_bytes = _cache.get(seg_start) if seg_bytes is None: seg_end = idc.get_segm_attr(seg_start, idc.SEGATTR_END) seg_bytes = _obtain_bytes(seg_start, seg_end) _cache[seg_start] = seg_bytes return seg_bytes
def dostuff(): count = 0 adr = idaapi.get_imagebase() end = idc.get_segm_attr(adr, idc.SEGATTR_END) while(adr < end): ins = idc.GetMnem(adr) ln = idc.GetOpnd(adr, 1)[1:] if ins == "MOV" and idc.GetOpnd(adr, 0) == "W8" and int(ln, 16) < 0xFFF and int(ln, 16) > 0xA and "AA" not in ln: #there are comments at top rite? #-ftrivial-auto-var-init=pattern SetColor(adr, CIC_ITEM, LINE_COLOR) if ins == "MOVE": hash = (idc.GetOpnd(adr, 1)[1:]) if len(str(hash)) >= 16 and len(str(hash)) < 20 and hash > 0xF000000000000000: file = decodehash(hash) if file != -1: isn = "WMSA "+file set_manual_insn(adr, isn) SetColor(adr, CIC_ITEM, FILE_COLOR) count+=1 adr+=4 print "[WMSA] Total hashes decoded (non-unique) : " + str(count)
def load_file(fd, neflags, format): global prologues global br_flag size = 0 base_addr = 0 ea = 0 nfunc = 0 idaapi.set_processor_type("arm", ida_idp.SETPROC_LOADER_NON_FATAL) idaapi.get_inf_structure().lflags |= idaapi.LFLG_64BIT if (neflags & idaapi.NEF_RELOAD) != 0: return 1 fd.seek(0, idaapi.SEEK_END) size = fd.tell() segm = idaapi.segment_t() segm.bitness = 2 # 64-bit segm.start_ea = 0 segm.end_ea = size if br_flag == false: idaapi.add_segm_ex(segm, "iBoot", "CODE", idaapi.ADDSEG_OR_DIE) else: idaapi.add_segm_ex(segm, "SecureROM", "CODE", idaapi.ADDSEG_OR_DIE) fd.seek(0) fd.file2base(0, 0, size, false) idaapi.add_entry(0, 0, "start", 1) ida_funcs.add_func(ea) print("[+] Marked as code") # heuristic while (true): mnemonic = idc.print_insn_mnem(ea) if "LDR" in mnemonic: base_str = idc.print_operand(ea, 1) base_addr = int(base_str.split("=")[1], 16) break ea += 4 print("[+] Rebasing to address 0x%x" % (base_addr)) idaapi.rebase_program(base_addr, idc.MSF_NOFIX) segment_start = base_addr segment_end = idc.get_segm_attr(segment_start, idc.SEGATTR_END) ea = segment_start print("[+] Searching and defining functions") for prologue in prologues: while ea != ida_idaapi.BADADDR: ea = ida_search.find_binary(ea, segment_end, prologue, 16, ida_search.SEARCH_DOWN) if ea != ida_idaapi.BADADDR: if len(prologue) < 8: ea = ea - 2 if (ea % 4) == 0 and ida_bytes.get_full_flags(ea) < 0x200: # print("[+] Defining a function at 0x%x" % (ea)) ida_funcs.add_func(ea) nfunc = nfunc + 1 ea = ea + 4 idc.plan_and_wait(segment_start, segment_end) print("[+] Identified %d new functions" % (nfunc)) print("[+] Looking for interesting functions") find_interesting(segment_start, segment_end) return 1
def is_code_segment(ea): return idc.get_segm_attr(ea, idc.SEGATTR_TYPE) == idc.SEG_CODE
def get_bitness_bytes(addr): if idc.get_segm_attr(addr, idc.SEGATTR_BITNESS) == 2: return 8 return 4
def is_read_only_segment(ea): mask_perms = idaapi.SEGPERM_WRITE | idaapi.SEGPERM_READ perms = idc.get_segm_attr(ea, idc.SEGATTR_PERM) return idaapi.SEGPERM_READ == (perms & mask_perms)
def segment_filter(self, s_ea): """ Discard extern segments """ if idc.get_segm_attr(s_ea, idc.SEGATTR_TYPE) != idc.SEG_XTRN and \ idc.get_segm_name(s_ea) != self.config.entropy['segm_name']: return True return False
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")
idc.plan_and_wait(segment_start, segment_end) print("[+] Identified %d new functions" % (nfunc)) print("[+] Looking for interesting functions") find_interesting(segment_start, segment_end) return 1 # for easy testing if __name__ == "__main__": print("[+] find_interesting():") for seg in idautils.Segments(): st = ida_segment.getseg(seg) name = idaapi.get_segm_name(st) if name == "iBoot" or name == "SecureROM" or name == "iBEC" \ or name == "BootRom" or name == "LLB": segm_start = st.start_ea segm_end = idc.get_segm_attr(segm_start, idc.SEGATTR_END) find_interesting(segm_start, segm_end) break # ida_pro.qexit() # EOF
def get_segm_attr(seg_ea, attr): if idaapi.IDA_SDK_VERSION <= 699: retval = idc.GetSegmentAttr(seg_ea, attr) else: retval = idc.get_segm_attr(seg_ea, attr) return retval
def filter_writable_segment(ea): return not idc.get_segm_attr(ea, idc.SEGATTR_PERM) & 2
import idautils import idc # Locate function signatures. # # based on: https://reverseengineering.stackexchange.com/a/14726 # func_sigs maps from function address to a record of the function's name and # type. func_sigs = {} func_addrs = [] for seg in idautils.Segments(): # Skip extern segment; as used by IDA for external functions. if idc.get_segm_attr(seg, SEGATTR_TYPE) == idc.SEG_XTRN: #print("skipping segment ", idc.get_segm_name(seg)) continue for fn in idautils.Functions(seg, idc.get_segm_end(seg)): func_addr = fn func_name = idc.get_name(func_addr) if func_name is None: func_name = "" func_type = idc.get_type(func_addr) if func_type is None: func_type = "" func_sig = {"func_name": func_name, "func_type": func_type} func_sigs[func_addr] = func_sig func_addrs.append(func_addr) # Sort function addresses to be used as key. func_addrs.sort()
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 list( map(lambda x: x if type(x) == int else 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"], ida_name.SN_FORCE) 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) == idc.SEG_CODE: 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("[*] searching for crypto constants in immediate operand") funcs = idautils.Functions() for f in funcs: flags = idc.get_func_flags(f) if (not flags & (idc.FUNC_LIB | idc.FUNC_THUNK)): ea = f f_end = idc.get_func_attr(f, idc.FUNCATTR_END) while (ea < f_end): imm_operands = [] insn = ida_ua.insn_t() ida_ua.decode_insn(insn, ea) for i in range(len(insn.ops)): if insn.ops[i].type == ida_ua.o_void: break if insn.ops[i].type == ida_ua.o_imm: imm_operands.append(insn.ops[i].value) if len(imm_operands) == 0: ea = idc.find_code(ea, idc.SEARCH_DOWN) continue for const in operand_consts: if const["value"] in imm_operands: print(("0x%0" + str(digits) + "X: found immediate operand constants for %s") % (ea, const["algorithm"])) cmt = idc.get_cmt(ea, 0) if cmt: idc.set_cmt(ea, cmt + ' ' + const["name"], 0) else: idc.set_cmt(ea, const["name"], 0) break ea = idc.find_code(ea, idc.SEARCH_DOWN) print("[*] finished")
def get_bitness(addr): ptr = bits32 if idc.get_segm_attr(addr, idc.SEGATTR_BITNESS) == 2: ptr = bits64 return ptr
def def_functions(s_start): num_added_functions = 0 s_addr = s_start s_end = idc.get_segm_attr(s_start, SEGATTR_END) #idc.SegEnd(segm) print("0x%08x 0x%08x" % (s_start, s_end)) while (s_addr < s_end): print("Testing address 0x%08x" % s_addr) #optimization assumes that function chunks are consecutive (no "function-in-function" monkey business) if (idaapi.get_func(s_addr)): next_func = idc.get_next_func(s_addr) ea = s_addr for c in idautils.Chunks(s_addr): #only use chunks in lookahead that do not jump over the next function and that are not smaller than where we are atm. if (c[1] > ea) and (c[1] <= next_func): ea = c[1] if ea == s_addr: s_addr += 2 else: s_addr = ea #s_addr += 4 continue else: #This is not a good optimization, there WILL be data refs to function start addresses sometimes. ''' if sum(1 for _ in (CodeRefsTo(s_addr, 1))) != 0: s_addr += 4 continue ''' #also add STMFD if ((idc.print_insn_mnem(s_addr) == "STM") and ("SP!" in idc.print_operand(s_addr, 0)) and ("LR" in idc.print_operand(s_addr, 1))) or ( ((idc.print_insn_mnem(s_addr) == "PUSH") or (idc.print_insn_mnem(s_addr) == "PUSH.W") or (idc.print_insn_mnem(s_addr) == "STR.W")) and ("LR" in idc.print_operand(s_addr, 0))): print("Found function at 0x%08x" % s_addr) ida_funcs.add_func(s_addr) f = idaapi.get_func(s_addr) if (type(f) == type(None)): print("Failed to create function! Undefined instructions?") s_addr += 2 else: num_added_functions += 1 ea = -1 for c in idautils.Chunks(s_addr): if c[1] > ea: ea = c[1] if ea != -1: s_addr = ea #failed? else: s_addr += 2 else: s_addr += 2 print("finished segment") return num_added_functions