def __init__(self, ea=UseCurrentAddress, name=None, index=None): """Wrapper around IDA segments. There are 3 ways to get a segment - by name, ea or index. Only use one. Args: ea - address in the segment name - name of the segment index - index of the segment """ if sum((ea not in (self.UseCurrentAddress, None), name is not None, index is not None,)) > 1: raise ValueError( "Expected only one (ea, name or index). Got (ea={!r}, name={!r}, index={!r})".format(ea, name, index)) elif name is not None: seg = idaapi.get_segm_by_name(name) elif index is not None: seg = idaapi.getnseg(index) elif ea == self.UseCurrentAddress: seg = idaapi.getseg(idc.here()) elif ea is None: raise ValueError("`None` is not a valid address. To use the current screen ea, " "use `Function(ea=Function.UseCurrentAddress)` or supply no `ea`.") else: seg = idaapi.getseg(ea) self._segment = seg
def get_cur_offset(self): ea = idc.ScreenEA() seg = idaapi.getseg(ea) SigmName = idc.SegName(ea) startA = idc.SegStart(ea) self.off_edit.setText(hex(ea - startA).upper()) self.search_edit.setText(SigmName)
def update_content_viewers(self): n = self.GetLineNo() item = self.get_item(n) self.dav.clear() self.hv.clear() self.iv.clear() if item != None and item.type == Item.TYPE_CODE: # get disassembly and hex stream dis = self.payload.da.get_disasm(item.ea) for line in dis: self.dav.add_line(line[0]) self.hv.add_line(line[1]) # get various info seg = idaapi.getseg(item.ea) if seg: name = idaapi.get_true_segm_name(seg) perm = seg.perm ltype = "ld" if seg.is_loader_segm() else "dbg" ea_start = seg.startEA ea_end = seg.endEA perms = "" perms += "R" if perm & idaapi.SEGPERM_READ != 0 else "." perms += "W" if perm & idaapi.SEGPERM_WRITE != 0 else "." perms += "X" if perm & idaapi.SEGPERM_EXEC != 0 else "." self.iv.add_line("<%s> [%X - %X], %s, [%s]" % (name, ea_start, ea_end, ltype, perms)) self.dav.update() self.hv.update() self.iv.update()
def create(offset, size, name, **kwds): '''Create a segment at /offset/ and /size/ and name it /name/ /bits/ can be used to specify the bit size of the segment /comb/ can be used to specify any flags (idaapi.sc*) /align/ can be used to specify paragraph alignment (idaapi.sa*) /org/ specifies the origin of the segment (must be paragraph aligned due to ida) ''' s = idaapi.get_segm_by_name(name) if s is not None: logging.fatal("segment.create(%x, %x, %r, %r) : a segment with the specified name already exists : %s", offset, size, name, kwds, name) return None bits = kwds.get( 'bits', 32 if idaapi.getseg(offset) is None else idaapi.getseg(offset).abits()) # FIXME: use disassembler default bit length instead of 32 if bits == 16: ## create a selector with the requested origin org = kwds.get('org',0) if org&0xf > 0: logging.fatal("segment.create(%x, %x, %r, %r) : origin (.org) is not aligned to the size of a paragraph (0x10):%x", offset, size, name, kwds, org) return None para = offset/16 sel = idaapi.allocate_selector(para) idaapi.set_selector(sel, (para-kwds.get('org',0)/16)&0xffffffff) else: ## auto-create a selector for everything else sel = idaapi.setup_selector(kwds['selector']) if 'selector' in kwds else idaapi.find_free_selector() # create segment. ripped from idc s = idaapi.segment_t() s.startEA = offset s.endEA = offset+size s.sel = sel s.bitness = {16:0,32:1,64:2}[bits] s.comb = kwds.get('comb', idaapi.scPub) # public s.align = kwds.get('align', idaapi.saRelByte) # paragraphs res = idaapi.add_segm_ex(s, name, "", idaapi.ADDSEG_NOSREG|idaapi.ADDSEG_SPARSE) if res == 0: logging.warn("segment.create(%x, %x, %r, %r) : unable to add a new segment", offset, size, name, kwds) res = idaapi.del_selector(sel) #assert res != 0 return None return s
def output_segments(out): """Dump binary segmentation.""" info = idaapi.get_inf_structure() size = "r32" if info.is_32bit else "r64" out.writelines(('(', info.get_proc_name()[1], ' ', size, ' (')) for seg in idautils.Segments(): out.write("\n({} {} {:d} ({:#x} {:d}))".format( idaapi.get_segm_name(seg), "code" if idaapi.segtype(seg) == idaapi.SEG_CODE else "data", idaapi.get_fileregion_offset(seg), seg, idaapi.getseg(seg).size())) out.write("))\n")
def get_import_module_name(address): global module_names global idata_seg_start global idata_seg_end segment_eas = list( idautils.Segments() ) # This hasn't been initialized yet... # if module_names is None: module_names = list() for idata_seg_start in segment_eas: print "Going through segment %08X" % idata_seg_start segment = idaapi.getseg(idata_seg_start) if segment.type != idaapi.SEG_XTRN: continue print "Found idata segment" idata_seg_end = idc.SegEnd(idata_seg_start) parse = re.compile('.*Imports\s+from\s+([\w\d]+\.[\w\d]+).*', re.IGNORECASE) # save the address/module name combinations we discover # modules = list() # Scan the .idata segment looking for the imports from # string and get the address ranges where it applies # for head in idautils.Heads(idata_seg_start, idata_seg_end): for line_id in range(100): line = idc.LineA(head, line_id) if line and 'imports from' in line.lower(): res = parse.match(line) if res: print 'Found import line [%s][%s]' % (line, res.group(1)) modules.append( (head, res.group(1).lower()) ) modules.append( (idata_seg_end, None) ) for idx in range(len(modules)-1): mod = modules[idx] module_names.append( ( (mod[0], modules[idx+1][0]), mod[1] ) ) for addr_range, module_name in module_names: if addr_range[0] <= address < addr_range[1]: return module_name return None
def update_content_viewers(self, n=None): if n is None: n = self.GetLineNo() item = self.get_item(n) self.dav.clear() self.hv.clear() self.iv.clear() if item is not None: if item.type == Item.TYPE_CODE: # get disassembly and hex stream dis = self.payload.da.get_disasm(item.ea) for line in dis: self.dav.add_line(line[0]) self.hv.add_line(line[1]) # get various info seg = idaapi.getseg(item.ea) if seg: name = idaapi.get_true_segm_name(seg) perm = seg.perm ltype = "ld" if seg.is_loader_segm() else "dbg" ea_start = seg.startEA ea_end = seg.endEA perms = "" perms += "R" if perm & idaapi.SEGPERM_READ != 0 else "." perms += "W" if perm & idaapi.SEGPERM_WRITE != 0 else "." perms += "X" if perm & idaapi.SEGPERM_EXEC != 0 else "." self.iv.add_line("<%s> [%X - %X], %s, [%s]" % (name, ea_start, ea_end, ltype, perms)) else: stype = GetStringType(item.ea) if stype is not None: scontent = GetString(item.ea, -1, stype) if scontent != None and len(scontent): self.dav.add_line(idaapi.COLSTR("\"%s\"" % scontent, idaapi.SCOLOR_DSTR)) # length = idaapi.get_max_ascii_length(item.ea, stype, idaapi.ALOPT_IGNHEADS) # self.hv.add_line() else: scontent = GetString(item.ea, -1, ASCSTR_C) if scontent != None and len(scontent): self.dav.add_line("\"%s\"" % scontent) self.dav.update() self.hv.update() self.iv.update()
def enum_segm(self): i = 0 for ea in idautils.Segments(): seg = idaapi.getseg(ea) SigmName = idc.SegName(ea) startA = idc.SegStart(ea) endA = idc.SegEnd(ea) className = idaapi.get_segm_class(seg) seg_radio = SegmRadio(SigmName, startA, endA, className) self.segm.append((SigmName, startA, endA, className)) self.segm_vbox.addWidget(seg_radio) self.segm_vbox.addStretch(1) if i == 0: i = 1 seg_radio.toggle() return self.segm_vbox
def _fix_data_offsets(self): ea = 0 count = 0 print "Fixing unresolved offset xrefs...", while ea != idaapi.BADADDR: (ea, n) = idaapi.find_notype(ea, idaapi.SEARCH_DOWN) if idaapi.decode_insn(ea): for i in range(0, len(idaapi.cmd.Operands)): op = idaapi.cmd.Operands[i] if op.type == idaapi.o_imm and idaapi.getseg(op.value): idaapi.add_dref(ea, op.value, (idaapi.dr_O | idaapi.XREF_USER)) count += 1 print "created %d new data xrefs" % count
def dump_loader_info(output_filename): """Dump information for BAP's loader into output_filename.""" from idautils import Segments import idc idaapi.autoWait() with open(output_filename, 'w+') as out: info = idaapi.get_inf_structure() size = "r32" if info.is_32bit else "r64" out.write("(%s %s (" % (info.get_proc_name()[1], size)) for seg in Segments(): out.write("\n(%s %s %d (0x%X %d))" % ( idaapi.get_segm_name(seg), "code" if idaapi.segtype(seg) == idaapi.SEG_CODE else "data", idaapi.get_fileregion_offset(seg), seg, idaapi.getseg(seg).size())) out.write("))\n")
def find(s=None, x=False, asm_where=None): b, ret = FindInstructions(s, asm_where) if b: # executable segs only? if x: results = [] for ea in ret: seg = idaapi.getseg(ea) if (not seg) or (seg.perm & idaapi.SEGPERM_EXEC) == 0: continue results.append(SearchResult(ea)) else: results = [SearchResult(ea) for ea in ret] title = "Search result for: [%s]" % s idaapi.close_chooser(title) c = SearchResultChoose(results, title) c.choose() else: print ret
def read(self, n=-1): if not self.__idb__: return super(IDBFileIO, self).read(n) else: data = '' read_count = 0 filler_count = 0 # Loop to read n bytes of data across IDB segments, filling # segment gaps with NULL bytes. while n and self.idb_pos <= self.idb_end: segment = idaapi.getseg(self.idb_pos) if not segment: filler_count += 1 self.idb_pos += 1 n -= 1 else: if filler_count: data += "\x00" * filler_count filler_count = 0 if (self.idb_pos + n) > segment.endEA: read_count = segment.endEA - self.idb_pos else: read_count = n try: data += idc.GetManyBytes(self.idb_pos, read_count) except TypeError as e: # This happens when trying to read from uninitialized # segments (e.g., .bss) data += "\x00" * read_count n -= read_count self.idb_pos += read_count if filler_count: data += "\x00" * filler_count filler_count = 0 return data
def addDataSegment(M, start, end, new_eas): if end < start: raise Exception("Start must be before end") seg = idaapi.getseg(start) if not seg: raise Exception("Data must be in a valid segment") # if this is in an executalbe region, # move it to a data section seg_offset = 0 need_move = (seg.perm & idaapi.SEGPERM_EXEC) != 0 if need_move: free_data = findFreeData() seg_offset = free_data - start DEBUG("Data Segment {0:x} moved to: {1:x}\n".format(start, start+seg_offset)) D = M.internal_data.add() D.base_address = start+seg_offset SEGPERM_WRITE = 2 if (seg.perm & SEGPERM_WRITE) == 0: D.read_only = True else: D.read_only = False #D.data = idaapi.get_many_bytes(start, end-start) D.data = readBytesSlowly(start, end) DATA_SEGMENTS.append( (start+seg_offset,end+seg_offset) ) processRelocationsInData(M, D, start, end, new_eas, seg_offset) DEBUG("Adding data seg: {0}: {1}-{2}\n".format( idc.SegName(start), hex(start+seg_offset), hex(end+seg_offset))) return seg_offset
def setupUI(self): ea = idc.ScreenEA() seg = idaapi.getseg(ea) SigmName = idc.SegName(ea) startA = idc.SegStart(ea) endA = idc.SegEnd(ea) className = idaapi.get_segm_class(seg) self.setWindowTitle("Jumper--%s %s %s" % (hex(ea - startA).upper(), SigmName, className)) self.groupBox.setLayout(self.enum_segm()) search_hbox = QHBoxLayout() search_hbox.addWidget(QLabel("search")) search_hbox.addWidget(self.search_edit) offset_hbox = QHBoxLayout() offset_hbox.addWidget(QLabel("offset")) offset_hbox.addWidget(self.off_edit) self.scroll = QScrollArea() self.scroll.setWidgetResizable(True) # Set to make the inner widget resize with scroll area self.scroll.setWidget(self.groupBox) globle_vbox = QVBoxLayout(self) globle_vbox.addWidget(self.scroll) globle_vbox.addLayout(search_hbox) globle_vbox.addLayout(offset_hbox) btn_layout = QHBoxLayout() jump = QPushButton("jump") jump.clicked.connect(self.jump_click) get_offset = QPushButton("offset") get_offset.clicked.connect(self.get_cur_offset) btn_layout.addWidget(jump) btn_layout.addWidget(get_offset) globle_vbox.addLayout(btn_layout) self.search_edit.textChanged.connect(self.search_changed)
def _Assemble(ea, line): """ Please refer to Assemble() - INTERNAL USE ONLY """ if type(line) == types.StringType: lines = [line] else: lines = line ret = [] for line in lines: seg = idaapi.getseg(ea) if not seg: return (False, "No segment at ea") ip = ea - (idaapi.ask_selector(seg.sel) << 4) buf = idaapi.AssembleLine(ea, seg.sel, ip, seg.bitness, line) if not buf: return (False, "Assembler failed: " + line) ea += len(buf) ret.append(buf) if len(ret) == 1: ret = ret[0] return (True, ret)
def get_offset_name(ea): # Try and get the function name try: func = get_func(ea) name = idc.GetTrueName(func.startEA) name = demangle(name, 0x60) # MNG_NOTYPE | MNG_NORETTYPE if name: offset = ea - func.startEA if offset: return '{}+{:X}'.format(name, offset) return name except exceptions.SarkNoFunction: pass # If that failed, use the segment name instead. segment = idaapi.getseg(ea) name = idaapi.get_true_segm_name(segment) offset_format = '{{:0{}X}}'.format(get_native_size() * 2) ea_text = offset_format.format(ea) if name: return '{}:{}'.format(name, ea_text) # Nothing found, simply return the address return ea_text
def single_operand_parser(self, address, op, idx): """Parse a metapc operand.""" # Convenience functions # def has_sib_byte(op): # Does the instruction use the SIB byte? return self.as_byte_value(op.specflag1)==1 def get_sib_scale(op): return (None, 2, 4, 8)[self.as_byte_value(op.specflag2)>>6] def get_sib_scaled_index_reg(op): return self.SIB_INDEX_REGISTERS[(self.as_byte_value(op.specflag2)>>3)&0x7] def get_sib_base_reg(op): # # [ [7-6] [5-3] [2-0] ] # MOD/RM = ( (mod_2 << 6) | (reg_opcode_3 << 3) | rm_3 ) # There's not MOD/RM made available by IDA!? # # [ [7-6] [5-3] [2-0] ] # SIB = ( (scale_2 << 6) | (index_3 << 3) | base ) # op.specflag2 # # instruction = op + modrm + sib + disp + imm # # If MOD is zero there's no base register, otherwise it's EBP # But IDA exposes no MOD/RM. # Following a discussion in IDA's forums: # http://www.hex-rays.com/forum/viewtopic.php?f=8&t=1424&p=8479&hilit=mod+rm#p8479 # checking for it can be done in the following manner: # SIB_byte = self.as_byte_value(op.specflag2) return self.SIB_BASE_REGISTERS[ SIB_byte & 0x7] def get_segment_prefix(op): seg_idx = (op.specval>>16) if seg_idx == 0: return None if (op.specval>>16) < len(self.REGISTERS[0]) : seg_prefix = self.REGISTERS[0][op.specval>>16] + ':' else: seg_prefix = op.specval&0xffff # This must return a string in case a segment register selector is used # or and int/long of a descriptor itself. # return seg_prefix def parse_phrase(op, has_displacement=False): """Parse the expression used for indexed memory access. Returns its AST as a nested list of lists. """ # Check the addressing mode using in this segment segment = idaapi.getseg(address) if segment.bitness != 1: raise Exception( 'Not yet handling addressing modes other than 32bit!') base_reg = get_sib_base_reg(op) scaled_index_reg = get_sib_scaled_index_reg(op) scale = get_sib_scale(op) if scale: # return nested list for reg+reg*scale if base_reg != '': # The last values in each tuple indicate the # preferred display position of each element. # base_reg + (scale_reg * scale) # if scaled_index_reg == '': return [ self.NODE_TYPE_OPERATOR_PLUS, [self.NODE_TYPE_REGISTER, base_reg, 0] ] return [ self.NODE_TYPE_OPERATOR_PLUS, [self.NODE_TYPE_REGISTER, base_reg, 0], [self.NODE_TYPE_OPERATOR_TIMES, [self.NODE_TYPE_REGISTER, scaled_index_reg, 0], [self.NODE_TYPE_VALUE, scale, 1], 1 ] ] else: # If there's no base register and # mod == 01 or mod == 10 (=> operand has displacement) # then we need to add EBP if has_displacement: return [ self.NODE_TYPE_OPERATOR_PLUS, [ self.NODE_TYPE_REGISTER, 'ebp', 0], [ self.NODE_TYPE_OPERATOR_TIMES, [self.NODE_TYPE_REGISTER, scaled_index_reg, 0], [self.NODE_TYPE_VALUE, scale, 1], 1 ] ] return [ self.NODE_TYPE_OPERATOR_PLUS, [ self.NODE_TYPE_OPERATOR_TIMES, [self.NODE_TYPE_REGISTER, scaled_index_reg, 0], [self.NODE_TYPE_VALUE, scale, 1], 0 ] ] else: # return nested list for reg+reg if base_reg == '': if scaled_index_reg != '': if has_displacement: return [ self.NODE_TYPE_OPERATOR_PLUS, [ self.NODE_TYPE_REGISTER, 'ebp', 0], [ self.NODE_TYPE_REGISTER, scaled_index_reg, 1 ] ] return [ self.NODE_TYPE_OPERATOR_PLUS, [self.NODE_TYPE_REGISTER, scaled_index_reg, 0 ] ] else: if has_displacement: return [self.NODE_TYPE_OPERATOR_PLUS, [self.NODE_TYPE_REGISTER, 'ebp', 0] ] return [ ] else: if scaled_index_reg != '': return [ self.NODE_TYPE_OPERATOR_PLUS, [self.NODE_TYPE_REGISTER, base_reg, 0], [self.NODE_TYPE_REGISTER, scaled_index_reg, 1 ] ] else: return [ self.NODE_TYPE_OPERATOR_PLUS, [self.NODE_TYPE_REGISTER, base_reg, 0] ] # Operand parsing # if op.type == OPERAND_TYPE_NO_OPERAND: return None segment = idaapi.getseg(address) addressing_mode = segment.bitness # Start creating the AST, the root entry is always the width of the # operand operand = [self.OPERAND_WIDTH[ self.as_byte_value( op.dtyp ) ]] # If the operand indicates a displacement and it does # the indexing through the SIB the it might be referring # a variable on the stack and an attempt to retrieve it # is made. # # Compose the rest of the AST # if op.type == OPERAND_TYPE_DISPLACEMENT: # A displacement operatior might refer to a variable... # var_name = None # Try to get any stack name that might have been assigned # to the variable. # flags = idc.GetFlags(address) if (idx==0 and idc.isStkvar0(flags)) or ( idx==1 and idc.isStkvar1(flags)): var_name = self.get_operand_stack_variable_name(address, op, idx) if has_sib_byte(op) is True: # when SIB byte set, process the SIB indexing phrase = parse_phrase(op, has_displacement=True) else: phrase = [ self.NODE_TYPE_OPERATOR_PLUS, [self.NODE_TYPE_REGISTER, self.REGISTERS[addressing_mode+1][op.reg], 0] ] if var_name: value = arch.ExpressionNamedValue(long(op.addr), var_name) else: value = op.addr # Calculate the index of the value depending on how many components # we have in the phrase # idx_of_value = len( phrase ) - 1 operand.extend([ [ get_segment_prefix(op), [self.NODE_TYPE_DEREFERENCE, phrase+[ [self.NODE_TYPE_VALUE, value, idx_of_value] ] ] ] ]) elif op.type == OPERAND_TYPE_REGISTER: operand.extend([ [self.NODE_TYPE_REGISTER, self.REGISTERS[self.as_byte_value(op.dtyp)][op.reg], 0]]) elif op.type == OPERAND_TYPE_MEMORY: addr_name = self.get_address_name(op.addr) if addr_name: value = arch.ExpressionNamedValue(long(op.addr), addr_name) else: value = op.addr if has_sib_byte(op) is True: # when SIB byte set, process the SIB indexing phrase = parse_phrase(op) idx_of_value = len( phrase ) - 1 operand.extend([ [ get_segment_prefix(op), [self.NODE_TYPE_DEREFERENCE, phrase+[[self.NODE_TYPE_VALUE, value, idx_of_value]] ] ] ]) else: operand.extend([ [ get_segment_prefix(op), [self.NODE_TYPE_DEREFERENCE, [self.NODE_TYPE_VALUE, value, 0] ] ] ]) elif op.type == OPERAND_TYPE_IMMEDIATE: width = self.OPERAND_WIDTH[self.as_byte_value(op.dtyp)] if width == arch.Arch.NODE_TYPE_OPERATOR_WIDTH_BYTE_1: value = op.value&0xff elif width == arch.Arch.NODE_TYPE_OPERATOR_WIDTH_BYTE_2: value = op.value&0xffff elif width == arch.Arch.NODE_TYPE_OPERATOR_WIDTH_BYTE_4: value = op.value&0xffffffff else: value = op.value operand.extend([[self.NODE_TYPE_VALUE, value, 0]]) elif op.type in (OPERAND_TYPE_NEAR, OPERAND_TYPE_FAR): addr_name = self.get_address_name(op.addr) if addr_name: value = arch.ExpressionNamedValue(long(op.addr), addr_name) else: value = op.addr seg_prefix = get_segment_prefix(op) if isinstance(seg_prefix, str): operand.extend([ [ seg_prefix, [self.NODE_TYPE_VALUE, value, 0] ]]) elif isinstance(seg_prefix, (int, long)): operand.extend([ [ self.NODE_TYPE_OPERATOR_SEGMENT_GEN, [self.NODE_TYPE_VALUE, seg_prefix, 0], [self.NODE_TYPE_VALUE, value, 1] ]] ) elif op.type == OPERAND_TYPE_PHRASE: if has_sib_byte(op) is True: phrase = parse_phrase(op) # Detect observed cases (in GCC compiled sshd) where GCC's instruction # encoding would be parsed into a phrase with an addition of a single # register, without any other summands. # In those cases, if there's a name associated to the zero such as # a stack variable, we will add a zero to the sum. We do that to have # an expression to which alias an expression substitution (in the past # we were removing the addition altogether) # If there's no name we will remove the redundant 0 # # # This case has been observed for the encoding of [esp] where the tree # would be "[" -> "+" -> "esp". # # if phrase[0] == self.NODE_TYPE_OPERATOR_PLUS and len(phrase) == 2: var_name = self.get_operand_stack_variable_name(address, op, idx) if var_name: value = arch.ExpressionNamedValue(0, var_name) phrase.append( [self.NODE_TYPE_VALUE, value, 1] ) else: phrase = phrase[1] operand.extend([ [get_segment_prefix(op), [self.NODE_TYPE_DEREFERENCE, phrase] ]] ) else: operand.extend([ [get_segment_prefix(op), [self.NODE_TYPE_DEREFERENCE, [self.NODE_TYPE_REGISTER, self.REGISTERS[addressing_mode+1][op.phrase], 0] ] ]]) elif op.type == OPERAND_TYPE_IDPSPEC0: # The operand refers to the TR* registers operand.extend([ [self.NODE_TYPE_REGISTER, 'tr%d' % op.reg, 0]]) elif op.type == OPERAND_TYPE_IDPSPEC1: # The operand refers to the DR* registers operand.extend([ [self.NODE_TYPE_REGISTER, 'dr%d' % op.reg, 0]]) elif op.type == OPERAND_TYPE_IDPSPEC2: # The operand refers to the CR* registers operand.extend([ [self.NODE_TYPE_REGISTER, 'cr%d' % op.reg, 0]]) elif op.type == OPERAND_TYPE_IDPSPEC3: # The operand refers to the FPU register stack operand.extend([ [self.NODE_TYPE_REGISTER, 'st(%d)' % op.reg, 0]]) elif op.type == OPERAND_TYPE_IDPSPEC4: # The operand is a MMX register operand.extend([ [self.NODE_TYPE_REGISTER, 'mm%d' % op.reg, 0]]) elif op.type == OPERAND_TYPE_IDPSPEC5: # The operand is a MMX register operand.extend([ [self.NODE_TYPE_REGISTER, 'xmm%d' % op.reg, 0]]) # If no other thing that a width, i.e. ['b2'] is retrieved # we assume there was no operand... this is a hack but I've seen # IDA pretend there's a first operand like this: # # fld ['b2'], ['b4', ['ds', ['[', ['+', ['$', 'edx'], [...]]]]] # # So, in these cases I want no first operand... #if len(operand)==1: # return None return operand
def segment(cls): '''Return the current segment.''' ea = cls.address() return idaapi.getseg(ea)
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.next_head(ea) if idaapi.get_func(ea) or idc.is_align(idc.get_full_flags(ea)): max_location = ea elif ea == idc.BADADDR: max_location = idaapi.getseg(location).end_ea max_location = min(max_location, idaapi.getseg(location).end_ea) 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.get_item_size(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 check_fmt_function(name, addr): """ Check if the format string argument is not valid """ function_head = idc.get_func_attr(addr, idc.FUNCATTR_START) while True: addr = idc.prev_head(addr) op = idc.print_insn_mnem(addr).lower() dst = idc.print_operand(addr, 0) if op in ("ret", "retn", "jmp", "b") or addr < function_head: return c = idc.get_cmt(addr, 0) if c and c.lower() == "format": break elif name.endswith(("snprintf_chk", )): if op in ("mov", "lea") and dst.endswith( ("r8", "r8d", "[esp+10h]")): break elif name.endswith(("sprintf_chk", )): if op in ("mov", "lea") and (dst.endswith( ("rcx", "[esp+0Ch]", "R3")) or dst.endswith("ecx") and BITS == 64): break elif name.endswith(("snprintf", "fnprintf")): if op in ("mov", "lea") and (dst.endswith( ("rdx", "[esp+8]", "R2")) or dst.endswith("edx") and BITS == 64): break elif name.endswith( ("sprintf", "fprintf", "dprintf", "printf_chk")): if op in ("mov", "lea") and (dst.endswith( ("rsi", "[esp+4]", "R1")) or dst.endswith("esi") and BITS == 64): break elif name.endswith("printf"): if op in ("mov", "lea") and (dst.endswith( ("rdi", "[esp]", "R0")) or dst.endswith("edi") and BITS == 64): break # format arg found, check its type and value # get last oprend op_index = idc.generate_disasm_line(addr, 0).count(",") op_type = idc.get_operand_type(addr, op_index) opnd = idc.print_operand(addr, op_index) if op_type == idc.o_reg: # format is in register, try to track back and get the source _addr = addr while True: _addr = idc.prev_head(_addr) _op = idc.print_insn_mnem(_addr).lower() if _op in ("ret", "retn", "jmp", "b") or _addr < function_head: break elif _op in ("mov", "lea", "ldr") and idc.print_operand( _addr, 0) == opnd: op_type = idc.get_operand_type(_addr, 1) opnd = idc.print_operand(_addr, 1) addr = _addr break if op_type == idc.o_imm or op_type == idc.o_mem: # format is a memory address, check if it's in writable segment op_addr = idc.get_operand_value(addr, op_index) seg = idaapi.getseg(op_addr) if seg: if not seg.perm & idaapi.SEGPERM_WRITE: # format is in read-only segment return print("0x%X: Possible Vulnerability: %s, format = %s" % (addr, name, opnd)) return ["0x%X" % addr, name, opnd]
def get_addressing(self): seg = idaapi.getseg(self.start) return seg.bitness
def CallStackWalk(nn): class Result: """ Class holding the result of one call stack item Each call stack item instance has the following attributes: caller = ea of caller displ = display string sp = stack pointer """ def __init__(self, caller, sp): self.caller = caller self.sp = sp f = idaapi.get_func(caller) self.displ = "%08x: " % caller if f: self.displ += idc.GetFunctionName(caller) t = caller - f.startEA if t > 0: self.displ += "+" + hex(t) else: self.displ += hex(caller) self.displ += " [" + hex(sp) + "]" def __str__(self): return self.displ # get stack pointer sp = GetRegValue("RSP") seg = idaapi.getseg(sp) if not seg: return (False, "Could not locate stack segment!") stack_seg = Seg(seg) word_size = 2 ** (seg.bitness + 1) callers = [] sp = cpu.Esp - word_size while sp < stack_seg.endEA: sp += word_size ptr = idautils.GetDataList(sp, 1, word_size).next() seg = idaapi.getseg(ptr) # only accept executable segments if (not seg) or ((seg.perm & idaapi.SEGPERM_EXEC) == 0): continue # try to find caller caller = IsPrevInsnCall(ptr) # we have no recognized caller, skip! if caller is None: continue # do we have a debug name that is near? if nn: ret = nn.find(caller) if ret: ea = ret[0] # function exists? f = idaapi.get_func(ea) if not f: # create function idc.MakeFunction(ea, idaapi.BADADDR) # get the flags f = idc.GetFlags(caller) # no code there? if not isCode(f): MakeCode(caller) callers.append(Result(caller, sp)) # return (True, callers)
def get_class(self): seg = idaapi.getseg(self.addr) if not seg: return None return idaapi.get_segm_class()
def get_type(self): seg = idaapi.getseg(self.addr) if not seg: return None return seg.type
def run_yara_on_segments(rule_text, names=None, excluded_names=None, start_eas=None, excluded_eas=None, callback_func=_yara_callback): """ Description: Applies yara rule to the bytes in the specified segments and returns raw results. Segments may be specified by name or start EA, but one or the other is required. Alternatively, names or start EAs may be provided to exclude. In this case all other segments will be scanned. Clears the matches each time to prevent duplicates. Input: names - The names of the target segments excluded_names - The names of the excluded segments start_eas - The start EAs of the target segments excluded_eas - The start EAs of the excluded segments callback_func - A pointer to the callback function for YARA's matching to use Output: Returns a list of YARA's match results with items (location, description) """ global _YARA_MATCHES, FROM_FILE _YARA_MATCHES = [] FROM_FILE = False if names is None and excluded_names is None and start_eas is None and excluded_eas is None: raise Exception( "Either segment names, start EAs, excluded names, or excluded EAs are required to YARA scan by segment." ) if (names and excluded_names) or (start_eas and excluded_eas): raise Exception( "Do not specify names and excluded names or start eas and excluded eas." ) results = [] if names: for name in names: results.extend( run_yara_on_segment(rule_text, name=name, callback_func=callback_func)) elif start_eas: for start_ea in start_eas: results.extend( run_yara_on_segment(rule_text, start_ea=start_ea, callback_func=callback_func)) else: segs_eas = list(idautils.Segments()) if excluded_names: for seg_ea in segs_eas: seg_name = idaapi.get_segm_name(idaapi.getseg(seg_ea)) if seg_name not in excluded_names: results.extend( run_yara_on_segment(rule_text, name=seg_name, callback_func=callback_func)) elif excluded_eas: for seg_ea in segs_eas: if seg_ea not in excluded_eas: results.extend( run_yara_on_segment(rule_text, start_ea=seg_ea, callback_func=callback_func)) _YARA_MATCHES = results # For conformity sake, make sure _YARA_MATCHES is set with all results return _YARA_MATCHES
def get_bitness(ea): seg = idaapi.getseg(ea) if not seg: seg = idaapi.getseg(idautils.Segments().next()) bitness = seg.bitness return {0: 16, 1: 32, 2: 64}[bitness]
def _initialize_page(self, n, new_page): if n in self._initialized: return False self._initialized.add(n) new_page_addr = n * self._page_size initialized = False if self.state is not None: self.state.scratch.push_priv(True) #return True if self._memory_backer is None: pass elif isinstance(self._memory_backer, cle.Clemory): # first, find the right clemory backer for addr, backer in self._memory_backer.cbackers if self.byte_width == 8 else ( (x, y) for x, _, y in self._memory_backer.stride_repr): start_backer = new_page_addr - addr if isinstance(start_backer, BV): continue if start_backer < 0 and abs(start_backer) >= self._page_size: continue if start_backer >= len(backer): continue # find permission backer associated with the address # fall back to read-write if we can't find any... flags = IdaPage.PROT_READ | IdaPage.PROT_WRITE for start, end in self._permission_map: if start <= new_page_addr < end: flags = self._permission_map[(start, end)] break snip_start = max(0, start_backer) write_start = max(new_page_addr, addr + snip_start) write_size = self._page_size - write_start % self._page_size if self.byte_width == 8: snip = _ffi.buffer(backer)[snip_start:snip_start + write_size] mo = SimMemoryObject(claripy.BVV(snip), write_start, byte_width=self.byte_width) self._apply_object_to_page(n * self._page_size, mo, page=new_page) else: for i, byte in enumerate(backer): mo = SimMemoryObject(claripy.BVV( byte, self.byte_width), write_start + i, byte_width=self.byte_width) self._apply_object_to_page(n * self._page_size, mo, page=new_page) new_page.permissions = claripy.BVV(flags, 3) initialized = True elif len(self._memory_backer) <= self._page_size: for i in self._memory_backer: if new_page_addr <= i and i <= new_page_addr + self._page_size: if isinstance(self._memory_backer[i], claripy.ast.Base): backer = self._memory_backer[i] elif isinstance(self._memory_backer[i], bytes): backer = claripy.BVV(self._memory_backer[i]) else: backer = claripy.BVV(self._memory_backer[i], self.byte_width) mo = SimMemoryObject(backer, i, byte_width=self.byte_width) self._apply_object_to_page(n * self._page_size, mo, page=new_page) initialized = True elif len(self._memory_backer) > self._page_size: for i in range(self._page_size): try: if isinstance(self._memory_backer[i], claripy.ast.Base): backer = self._memory_backer[i] elif isinstance(self._memory_backer[i], bytes): backer = claripy.BVV(self._memory_backer[i]) else: backer = claripy.BVV(self._memory_backer[i], self.byte_width) mo = SimMemoryObject(backer, new_page_addr + i, byte_width=self.byte_width) self._apply_object_to_page(n * self._page_size, mo, page=new_page) initialized = True except KeyError: pass # page from debugger try: seg = idaapi.getseg( new_page_addr) ### CHANGE TO SUPPORT OTHER DEBUGGERS if seg is not None: perms = 0 if seg.perm & idaapi.SEGPERM_EXEC: perms += IdaPage.PROT_EXEC if seg.perm & idaapi.SEGPERM_WRITE: perms += IdaPage.PROT_WRITE if seg.perm & idaapi.SEGPERM_READ: perms += IdaPage.PROT_READ new_page.permissions = claripy.BVV(perms, 3) #print "permissions setted %x %d" % (new_page_addr, perms) initialized = True setattr(new_page, "from_ida_dbg", True) except: pass if self.state is not None: self.state.scratch.pop_priv() return initialized
def byAddress(ea): '''Return the segment_t that holds the specified /ea/''' s = idaapi.getseg(ea) if s is None: raise Exception, "segment.byAddress(%x):unable to locate segment"% ea return s
def get_bitness(ea): bitness = idaapi.getseg(ea).bitness return {0: 16, 1: 32, 2: 64}[bitness]
def InsNotInTextSection(i): seg_name = idaapi.get_segm_name(idaapi.getseg(i)) return seg_name != ".text", seg_name
def _set_segment_color(self, ea, color) -> None: seg = idaapi.getseg(ea) seg.color = COLOR_NORMAL seg.update()
def segment(cls): """Current segment""" ea = cls.address() return idaapi.getseg(ea)
def single_operand_parser(self, address, op, idx): """Parse a ARM operand.""" def constraint_value(value): if value>2**16: return -(2**32-value) return value def parse_register_list(bitfield, bit_field_width=32): """Parse operand representing a list of registers.""" operand = [self.NODE_TYPE_OPERATOR_LIST] i = 0 for idx in range(32): if bitfield&(2**idx): operand.extend([[self.NODE_TYPE_REGISTER, self.REGISTERS[idx], i]]) i=i+1 return operand def parse_register_list_floating_point(register, count): """Parse operand representing a list of registers.""" operand = [self.NODE_TYPE_OPERATOR_LIST] for idx in range(register, register+count): operand.extend([[self.NODE_TYPE_REGISTER, 'D%d' % idx , 0]]) return operand ### Operand parsing ### if op.type == OPERAND_TYPE_NO_OPERAND: return None segment = idaapi.getseg(address) addressing_mode = segment.bitness # Start creating the AST, the root entry is always the width of the operand operand = [self.OPERAND_WIDTH[self.as_byte_value(op.dtyp)]] # Compose the rest of the AST if op.type == OPERAND_TYPE_DISPLACEMENT: # At this point we have to parse specific bits of the instruction # ourselves because IDA does not provide all the required data. val = idc.Dword(address) p = (val >> 24) & 1 w = (val >> 21) & 1 value = constraint_value(op.addr) phrase = [self.NODE_TYPE_OPERATOR_COMMA, [ self.NODE_TYPE_REGISTER, self.REGISTERS[op.reg], 0]] if idc.GetMnem(address) in ["LDR", "STR"] and idc.ItemSize(address) > 2: if p == 0 and w == 0: # Situation: [ ... ], VALUE operand.extend( [ [ self.NODE_TYPE_OPERATOR_COMMA, [ self.NODE_TYPE_DEREFERENCE, [ self.NODE_TYPE_REGISTER, self.REGISTERS[op.reg], 0] , ], [ self.NODE_TYPE_VALUE, value, 1 ] ] ]) else: # Situation: [ ... ] or [ ... ]! # We want to avoid [R1 + 0]! situations, so we explicitly # remove the +0 phrase if it exists. if value != 0: inner = [self.NODE_TYPE_DEREFERENCE,phrase+[ [self.NODE_TYPE_VALUE, value, 1]] ] else: inner = [self.NODE_TYPE_DEREFERENCE,[self.NODE_TYPE_REGISTER, self.REGISTERS[op.reg], 0]] if p == 1 and w == 1: operand.extend([[self.NODE_TYPE_OPERATOR_EXCMARK, inner]]) else: operand.extend([inner]) else: if value != 0: operand.extend([[self.NODE_TYPE_DEREFERENCE,phrase+[ [self.NODE_TYPE_VALUE, value, 1]]]]) else: operand.extend([[self.NODE_TYPE_DEREFERENCE,[self.NODE_TYPE_REGISTER, self.REGISTERS[op.reg], 0]]]) elif op.type == OPERAND_TYPE_REGISTER: if idc.GetMnem(address) in ["STM", "LDM"]: val = idc.Dword(address) w = (val >> 21) & 1 if w == 1: operand.extend([[self.NODE_TYPE_OPERATOR_EXCMARK,[self.NODE_TYPE_REGISTER, self.REGISTERS[op.reg], 0]]]) else: operand.extend([[self.NODE_TYPE_REGISTER, self.REGISTERS[op.reg], 0]]) else: try: operand.extend([[self.NODE_TYPE_REGISTER, self.REGISTERS[op.reg], 0]]) except Exception, excp: print '%08x: UNSUPPORTED OPERAND REGISTER at %08x: idx: %d' % (address, address, op.reg)
def new(offset, size, name, **kwds): """Create a segment at `offset` with `size` and name it according to `name`. The keyword `bits` can be used to specify the bit size of the segment The keyword `comb` can be used to specify any flags (idaapi.sc*) The keyword `align` can be used to specify paragraph alignment (idaapi.sa*) The keyword `org` specifies the origin of the segment (must be paragraph aligned due to ida) """ res = utils.string.to(name) # find the segment according to the name specified by the user seg = idaapi.get_segm_by_name(res) if seg is not None: raise E.DuplicateItemError(u"{:s}.new({:#x}, {:+#x}, \"{:s}\"{:s}) : A segment with the specified name (\"{:s}\") already exists.".format(__name__, offset, size, utils.string.escape(name, '"'), u", {:s}".format(utils.string.kwargs(kwds)) if kwds else '', utils.string.escape(name, '"'))) # FIXME: use disassembler default bit length instead of 32 bits = kwds.get( 'bits', 32 if idaapi.getseg(offset) is None else idaapi.getseg(offset).abits()) ## create a selector with the requested origin if bits == 16: org = kwds.get('org',0) if org & 0xf > 0: raise E.InvalidTypeOrValueError(u"{:s}.new({:#x}, {:+#x}, {!r}{:s}) : The specified origin ({:#x}) is not aligned to the size of a paragraph (0x10).".format(__name__, offset, size, name, u", {:s}".format(utils.string.kwargs(kwds)) if kwds else '', org)) para = offset/16 sel = idaapi.allocate_selector(para) idaapi.set_selector(sel, (para-kwds.get('org',0)/16)&0xffffffff) ## if the user specified a selector, then use it elif 'sel' in kwds or 'selector' in kwds: sel = kwds.get('sel', kwds.get('selector', idaapi.find_free_selector())) ## choose the paragraph size defined by the user elif 'para' in kwds or 'paragraphs' in kwds: para = kwds.get('paragraph', kwds.get('para', 1)) sel = idaapi.setup_selector(para) ## find a selector that is 1 paragraph size, elif idaapi.get_selector_qty(): sel = idaapi.find_selector(1) # otherwise find a free one and set it. else: sel = idaapi.find_free_selector() idaapi.set_selector(sel, 1) # populate the segment_t using code ripped from the idc module seg = idaapi.segment_t() seg.startEA = offset seg.endEA = offset+size seg.sel = sel seg.bitness = {16:0,32:1,64:2}[bits] seg.comb = kwds.get('comb', idaapi.scPub) # public seg.align = kwds.get('align', idaapi.saRelByte) # paragraphs # now we can add our segment_t to the database res = utils.string.to(name) ok = idaapi.add_segm_ex(seg, res, "", idaapi.ADDSEG_NOSREG|idaapi.ADDSEG_SPARSE) if not ok: ok = idaapi.del_selector(sel) if not ok: logging.warn(u"{:s}.new({:#x}, {:+#x}, {!r}{:s}) : Unable to delete the created selector ({:#x}) for the new segment.".format(__name__, offset, size, name, u", {:s}".format(utils.string.kwargs(kwds)) if kwds else '', sel)) raise E.DisassemblerError(u"{:s}.new({:#x}, {:+#x}, {!r}{:s}) : Unable to add a new segment.".format(__name__, offset, size, name, u", {:s}".format(utils.string.kwargs(kwds)) if kwds else '')) return seg
'func_ptr', 'call_code', 'is_rep_call', 'input_size_1', 'input_size_2', 'output_size_1', 'output_size_2', 'unkw' ]) HypercallDefine = namedtuple('HypercallDefine', ['define', 'hypercall_name', 'call_code']) # Hypercall table alway seems to appear in segment "CONST" hypercall_dispatch_table = idaapi.get_segm_by_name("CONST").startEA print '[+] Hypercall Dispatch Table: ' + hex(hypercall_dispatch_table) # Find +X segment segX_start = 0 segX_end = 0 for ea in idautils.Segments(): seg = idaapi.getseg(ea) if seg and (seg.perm & idaapi.SEGPERM_EXEC): SigmName = idc.SegName(ea) print '[+] Segments with +X permission: ' + SigmName segX_start = seg.startEA segX_end = seg.endEA # Loop through hypercall table hypercalls = [] valid_hypercall = True addr = hypercall_dispatch_table while valid_hypercall: func_ptr = idaapi.get_qword(addr) # Set struct field sizes in IDA in the HypercallDispatchFormat format if APPLY_TO_IDB: MakeQword(addr)
def load_file(li, neflags, format): # Read in the bFLT header fields li.seek(0) (magic, version, entry, data_start, data_end, bss_end, stack_size, reloc_start, reloc_count, flags) = struct.unpack(">IIIIIIIIII", li.read(4 * 10)) # Check for the GZIP flag. # The loader doesn't de-compress GZIP'd files, as these can be easily decompressed with external tools prior to loading the file into IDA if (flags & FLAGS_GZIP) == FLAGS_GZIP: Warning( "Code/data is GZIP compressed. You probably want to decompress the bFLT file with the flthdr or gunzip_bflt utilities before loading it into IDA." ) # Load the file data into IDA li.file2base(BFLT_HEADER_SIZE, BFLT_HEADER_SIZE, data_end, True) # Set default processor idaapi.set_processor_type(DEFAULT_CPU, SETPROC_ALL) # Add the .text .data and .bss segments idaapi.add_segm(0, BFLT_HEADER_SIZE, data_start, ".text", "CODE") idaapi.add_segm(0, data_start, data_end, ".data", "DATA") idaapi.add_segm(0, data_end, bss_end, ".bss", "BSS") if DEBUG: print "Created File Segments: " print "\t.text 0x%.8X - 0x%.8X" % (BFLT_HEADER_SIZE, data_start) print "\t.data 0x%.8X - 0x%.8X" % (data_start, data_end) print "\t.bss 0x%.8X - 0x%.8X" % (data_end, bss_end) # Entry point is at the beginning of the .text section idaapi.add_entry(entry, entry, "_start", 1) # Explicitly set 32 bit addressing on .text segment idaapi.set_segm_addressing(idaapi.getseg(entry), 1) # prepare structure for set_fixup() fd = idaapi.fixup_data_t() fd.type = idaapi.FIXUP_OFF32 # Is there a global offset table? if (flags & FLAGS_GOTPIC) == FLAGS_GOTPIC: # Add a reptable comment and name the offset so that all references to GOT are obvious MakeRptCmt(data_start, "GLOBAL_OFFSET_TABLE") MakeName(data_start, "GOT") if DEBUG: print "Global Offset Table detected, patching..." # GOT starts at the beginning of the data section; loop through the data section, patching up valid GOT entries. i = data_start while i < data_end: # Get the next GOT entry li.seek(i) got_entry = struct.unpack("<I", li.read(4))[0] # The last GOT entry is -1 if got_entry == 0xFFFFFFFF: if DEBUG: print "Finished processing Global Offset Table." break # All other non-zero entries are valid GOT entries elif got_entry > 0: # The actual data is located at <original GOT entry> + <BFLT_HEADER_SIZE> new_entry = got_entry + BFLT_HEADER_SIZE if DEBUG: print "Replacing GOT entry value 0x%.8X with 0x%.8X at offset 0x%.8X" % ( got_entry, new_entry, i) # Replace the GOT entry with the correct pointer idaapi.put_long(i, new_entry) # add info about relocation to help analyzer fd.off = new_entry idaapi.set_fixup(i, fd) # Make each GOT entry a DWORD MakeDword(i) # Point i at the next GOT entry address i = i + 4 # Patch relocation addresses for i in range(0, reloc_count): try: # Get the next relocation entry. # Relocation entry = <address of bytes to be patched> - <BFLT_HEADER_SIZE> li.seek(reloc_start + (i * 4)) reloc_offset = struct.unpack(">I", li.read(4))[0] + BFLT_HEADER_SIZE # Sanity check, make sure the relocation offset is in a defined segment if reloc_offset < bss_end: try: # reloc_offset + base_offset == <pointer to actual data> - <BFLT_HEADER_SIZE> li.seek(reloc_offset) reloc_val = struct.unpack(">I", li.read(4))[0] if reloc_val == 0: # skip zero relocs # see fs/binfmt_flat.c if DEBUG: print "Skipping zero reloc at (0x%.8X)" % reloc_offset continue reloc_data_offset = reloc_val + BFLT_HEADER_SIZE if DEBUG: print "Patching reloc: (0x%.8X) == 0x%.8X" % ( reloc_offset, reloc_data_offset) # Replace pointer at reloc_offset with the address of the actual data idaapi.put_long(reloc_offset, reloc_data_offset) # add info about relocation to help analyzer fd.off = reloc_data_offset idaapi.set_fixup(reloc_offset, fd) except Exception, e: print "Error patching relocation entry #%d: %s" % (i, str(e)) elif DEBUG: print "Relocation entry #%d outside of defined file sections, skipping..." % i
def check_fmt_function(name, addr): """ Check if the format string argument is not valid """ function_head = GetFunctionAttr(addr, idc.FUNCATTR_START) while True: addr = idc.PrevHead(addr) op = GetMnem(addr).lower() dst = GetOpnd(addr, 0) if op in ("ret", "retn", "jmp", "b") or addr < function_head: return c = GetCommentEx(addr, 0) if c and c.lower() == "format": break elif name.endswith(("snprintf_chk",)): if op in ("mov", "lea") and dst.endswith(("r8", "r8d", "[esp+10h]")): break elif name.endswith(("sprintf_chk",)): if op in ("mov", "lea") and (dst.endswith(("rcx", "[esp+0Ch]", "R3")) or dst.endswith("ecx") and BITS == 64): break elif name.endswith(("snprintf", "fnprintf")): if op in ("mov", "lea") and (dst.endswith(("rdx", "[esp+8]", "R2")) or dst.endswith("edx") and BITS== 64): break elif name.endswith(("sprintf", "fprintf", "dprintf", "printf_chk")): if op in ("mov", "lea") and (dst.endswith(("rsi", "[esp+4]", "R1")) or dst.endswith("esi") and BITS == 64): break elif name.endswith("printf"): if op in ("mov", "lea") and (dst.endswith(("rdi", "[esp]", "R0")) or dst.endswith("edi") and BITS == 64): break # format arg found, check its type and value # get last oprend op_index = GetDisasm(addr).count(",") op_type = GetOpType(addr, op_index) opnd = GetOpnd(addr, op_index) if op_type == o_reg: # format is in register, try to track back and get the source _addr = addr while True: _addr = idc.PrevHead(_addr) _op = GetMnem(_addr).lower() if _op in ("ret", "retn", "jmp", "b") or _addr < function_head: break elif _op in ("mov", "lea", "ldr") and GetOpnd(_addr, 0) == opnd: op_type = GetOpType(_addr, 1) opnd = GetOpnd(_addr, 1) addr = _addr break if op_type == o_imm or op_type == o_mem: # format is a memory address, check if it's in writable segment op_addr = GetOperandValue(addr, op_index) seg = idaapi.getseg(op_addr) if seg: if not seg.perm & idaapi.SEGPERM_WRITE: # format is in read-only segment return print "0x%X: Possible Vulnerability: %s, format = %s" % (addr, name, opnd) return ["0x%X" % addr, name, opnd]
def analyze (payload): for n in xrange (payload.get_number_of_items()): ea = payload.get_item(n).ea seg = idaapi.getseg(ea) if seg and ((seg.perm & idaapi.SEGPERM_EXEC) != 0): payload.get_item(n).type = Item.TYPE_CODE
def __call__(self): s = idaapi.getseg(self.ea) idaapi.set_segm_class(s, self.sclass)
def parse_phrase(op, has_displacement=False): """Parse the expression used for indexed memory access. Returns its AST as a nested list of lists. """ # Check the addressing mode using in this segment segment = idaapi.getseg(address) if segment.bitness != 1: raise Exception( 'Not yet handling addressing modes other than 32bit!') base_reg = get_sib_base_reg(op) scaled_index_reg = get_sib_scaled_index_reg(op) scale = get_sib_scale(op) if scale: # return nested list for reg+reg*scale if base_reg != '': # The last values in each tuple indicate the # preferred display position of each element. # base_reg + (scale_reg * scale) # if scaled_index_reg == '': return [ self.NODE_TYPE_OPERATOR_PLUS, [self.NODE_TYPE_REGISTER, base_reg, 0] ] return [ self.NODE_TYPE_OPERATOR_PLUS, [self.NODE_TYPE_REGISTER, base_reg, 0], [self.NODE_TYPE_OPERATOR_TIMES, [self.NODE_TYPE_REGISTER, scaled_index_reg, 0], [self.NODE_TYPE_VALUE, scale, 1], 1 ] ] else: # If there's no base register and # mod == 01 or mod == 10 (=> operand has displacement) # then we need to add EBP if has_displacement: return [ self.NODE_TYPE_OPERATOR_PLUS, [ self.NODE_TYPE_REGISTER, 'ebp', 0], [ self.NODE_TYPE_OPERATOR_TIMES, [self.NODE_TYPE_REGISTER, scaled_index_reg, 0], [self.NODE_TYPE_VALUE, scale, 1], 1 ] ] return [ self.NODE_TYPE_OPERATOR_PLUS, [ self.NODE_TYPE_OPERATOR_TIMES, [self.NODE_TYPE_REGISTER, scaled_index_reg, 0], [self.NODE_TYPE_VALUE, scale, 1], 0 ] ] else: # return nested list for reg+reg if base_reg == '': if scaled_index_reg != '': if has_displacement: return [ self.NODE_TYPE_OPERATOR_PLUS, [ self.NODE_TYPE_REGISTER, 'ebp', 0], [ self.NODE_TYPE_REGISTER, scaled_index_reg, 1 ] ] return [ self.NODE_TYPE_OPERATOR_PLUS, [self.NODE_TYPE_REGISTER, scaled_index_reg, 0 ] ] else: if has_displacement: return [self.NODE_TYPE_OPERATOR_PLUS, [self.NODE_TYPE_REGISTER, 'ebp', 0] ] return [ ] else: if scaled_index_reg != '': return [ self.NODE_TYPE_OPERATOR_PLUS, [self.NODE_TYPE_REGISTER, base_reg, 0], [self.NODE_TYPE_REGISTER, scaled_index_reg, 1 ] ] else: return [ self.NODE_TYPE_OPERATOR_PLUS, [self.NODE_TYPE_REGISTER, base_reg, 0] ]
def is_writable(self, offset): """Determine if memory address is writable""" self.ret = bool(idaapi.getseg(offset).perm & idaapi.SEGPERM_WRITE) return self.ret
def __call__(self): s = idaapi.getseg(self.ea) idaapi.set_segm_name(s, self.name.encode('utf-8'))
def is_rw_ea(ea): seg = idaapi.getseg(ea) return seg.perm & idaapi.SEGPERM_WRITE and seg.perm & idaapi.SEGPERM_READ
def section_end(i): sec = idaapi.getseg(i) assert sec, "no section for 0x%x" % i return sec.endEA
def __call__(self): s = idaapi.getseg(self.ea) idaapi.set_segm_name(s, self.name)
def single_operand_parser(self, address, op, idx): """Parse a PPC operand.""" def constraint_value(value): if value>2**16: return -(2**32-value) return value # Operand parsing # if op.type == OPERAND_TYPE_NO_OPERAND: return None #print '>>>', hex(address), idx, op.type segment = idaapi.getseg(address) addressing_mode = segment.bitness # Start creating the AST, the root entry is always the width of the # operand operand = [self.OPERAND_WIDTH[self.as_byte_value(op.dtyp)]] # Compose the rest of the AST # if op.type == OPERAND_TYPE_DISPLACEMENT: # A displacement operatior might refer to a variable... # var_name = None # Try to get any name that might have been assigned to the # variable. It's only done if the register is: # sp/esp (4) os bp/ebp (5) # flags = idc.GetFlags(address) if (idx==0 and idc.isStkvar0(flags)) or ( idx==1 and idc.isStkvar1(flags)): var_name = self.get_operand_stack_variable_name(address, op, idx) #if has_sib_byte(op) is True: # when SIB byte set, process the SIB indexing # phrase = parse_phrase(op) #else: phrase = [ self.NODE_TYPE_OPERATOR_PLUS, [self.NODE_TYPE_REGISTER, self.REGISTERS[self.as_byte_value(op.reg)], 0]] if var_name: value = arch.ExpressionNamedValue(long(op.addr), var_name) else: value = constraint_value(op.addr) operand.extend([ [self.NODE_TYPE_DEREFERENCE, phrase+[ [self.NODE_TYPE_VALUE, value, 1]] ] ]) elif op.type == OPERAND_TYPE_REGISTER: operand.extend([ [self.NODE_TYPE_REGISTER, self.REGISTERS[self.as_byte_value(op.reg)], 1]]) elif op.type == OPERAND_TYPE_MEMORY: addr_name = self.get_address_name(op.addr) if addr_name: value = arch.ExpressionNamedValue(long(op.addr), addr_name) else: value = op.addr operand.extend([ [self.NODE_TYPE_DEREFERENCE, [self.NODE_TYPE_VALUE, value, 0]] ]) elif op.type == OPERAND_TYPE_IMMEDIATE: # Keep the value's size # if self.as_byte_value(op.dtyp) == 0: mask = 0xff elif self.as_byte_value(op.dtyp) == 1: mask = 0xffff else: mask = 0xffffffff operand.extend([[self.NODE_TYPE_VALUE, op.value&mask, 0]]) elif op.type in (OPERAND_TYPE_NEAR, OPERAND_TYPE_FAR): addr_name = self.get_address_name(op.addr) if addr_name: value = arch.ExpressionNamedValue(long(op.addr), addr_name) else: value = op.addr operand.extend([[self.NODE_TYPE_VALUE, value, 0]]) elif op.type == OPERAND_TYPE_PHRASE: print '***Dunno how to parse PHRASE' operand.extend([[self.NODE_TYPE_SYMBOL, 'UNK_PHRASE(val:%d, reg:%d, type:%d)' % ( op.value, self.as_byte_value(op.reg), op.type), 0]]) elif op.type == OPERAND_TYPE_IDPSPEC0: # Handle Special Purpose Registers # register = self.SPR_REGISTERS.get( op.value, 'UNKNOWN_REGISTER(val:%x)' % op.value) operand.extend([ [self.NODE_TYPE_REGISTER, register, 0]]) elif op.type == OPERAND_TYPE_IDPSPEC1: #print '***Dunno how to parse OPERAND_TYPE_IDPSPEC1' #operand.extend([[self.NODE_TYPE_SYMBOL, # 'UNK_IDPSPEC1(val:%d, reg:%d, type:%d)' % ( # op.value, op.reg, op.type), 0]]) operand.extend([ [self.NODE_TYPE_REGISTER, self.REGISTERS[self.as_byte_value(op.reg)], 1]]) operand.extend([ [self.NODE_TYPE_REGISTER, self.REGISTERS[self.as_byte_value(op.specflag1)], 2]]) elif op.type == OPERAND_TYPE_IDPSPEC2: # IDSPEC2 is operand type for all rlwinm and rlwnm # instructions which are in general op reg, reg, byte, byte, byte # or eqivalent. simplified mnemonics sometimes take less than # five arguments. # # Keep the value's size # if self.as_byte_value(op.dtyp) == 0: mask = 0xff elif self.as_byte_value(op.dtyp) == 1: mask = 0xffff else: mask = 0xffffffff operand_1 = [] operand_2 = [] operand_3 = [] # Get the object representing the instruction's data. # It varies between IDA pre-5.7 and 5.7 onwards, the following check # will take care of it (for more detail look into the similar # construct in arch.py) # if hasattr(idaapi, 'cmd' ): idaapi.decode_insn(address) ida_instruction = idaapi.cmd else: idaapi.ua_code(address) ida_instruction = idaapi.cvar.cmd if (ida_instruction.auxpref & 0x0020): #print "SH" operand_1 = [self.OPERAND_WIDTH[self.as_byte_value(op.dtyp)]] operand_1.extend([[self.NODE_TYPE_VALUE, self.as_byte_value(op.reg)&mask, 0]]) else: operand_1 = [self.OPERAND_WIDTH[self.as_byte_value(op.dtyp)]] operand_1.extend([[self.NODE_TYPE_REGISTER, self.REGISTERS[self.as_byte_value(op.reg)], 0]]) #print operand_1 if (ida_instruction.auxpref & 0x0040): #print "MB" operand_2 = [self.OPERAND_WIDTH[self.as_byte_value(op.dtyp)]] operand_2.extend([[self.NODE_TYPE_VALUE, self.as_byte_value(op.specflag1)&mask, 0]]) #print operand_2 if (ida_instruction.auxpref & 0x0080): #print "ME" operand_3 = [self.OPERAND_WIDTH[self.as_byte_value(op.dtyp)]] operand_3.extend([[self.NODE_TYPE_VALUE, self.as_byte_value(op.specflag2)&mask, 0]]) #print operand_3 operand = [operand_1] #operand = operand_1 if (ida_instruction.auxpref & 0x0040): #print "MB2" operand.append(operand_2) if (ida_instruction.auxpref & 0x0080): #print "ME2" operand.append(operand_3) #print operand # operand = operand_1 #print operand #print '>>>', hex(address), idx, op.type, op.reg #operand.extend([[self.NODE_TYPE_OPERATOR_COMMA, [self.NODE_TYPE_VALUE, op.reg&mask, 0], [self.NODE_TYPE_VALUE, self.as_byte_value(op.specflag1)&mask, 1], [self.NODE_TYPE_VALUE, self.as_byte_value(op.specflag2)&mask, 2]]]) elif op.type == OPERAND_TYPE_IDPSPEC3: # CR registers # operand.extend([ [self.NODE_TYPE_REGISTER, self.CR_REGISTERS[self.as_byte_value(op.reg)], 0]]) elif op.type == OPERAND_TYPE_IDPSPEC4: # The bit in the CR to check for # operand.extend([[self.NODE_TYPE_REGISTER, self.as_byte_value(op.reg), 0]]) elif op.type == OPERAND_TYPE_IDPSPEC5: # Device Control Register, implementation specific operand.extend([[self.NODE_TYPE_REGISTER, 'DCR(%x)' % op.value, 0]]) return operand
def get_segm_name(ea, align=10): seg = idaapi.get_segm_name(idaapi.getseg(ea)) line = idaapi.add_spaces(seg, align) return idaapi.COLSTR(line, idaapi.SCOLOR_SEGNAME)
def search_pointers(self): # HACK: A separate flag is used to track user canceling the search, # because multiple calls to idaapi.wasBreak() do not properly # detect cancellations. breakFlag = False # Show wait dialog idaapi.show_wait_box("Searching writable function pointers...") for m in self.modules: ################################################################### # Locate all of the CALL and JMP instructions in the current module # which use an immediate operand. # List of call/jmp pointer calls in a given module ptr_calls = list() # Iterate over segments in the module # BUG: Iterating over all loaded segments is more stable than looking up by address for n in xrange(idaapi.get_segm_qty()): seg = idaapi.getnseg(n) # Segment in a selected modules if seg and seg.startEA >= m.addr and seg.endEA <= (m.addr + m.size): # Locate executable segments # NOTE: Each module may have multiple executable segments # TODO: Search for "MOV REG, PTR # CALL REG" if seg.perm & idaapi.SEGPERM_EXEC: # Search all instances of CALL /2 imm32/64 - FF 15 # TODO: Alternative pointer calls using SIB: FF 14 E5 11 22 33 44 - call dword/qword ptr [0x44332211] # FF 14 65 11 22 33 44 # FF 14 25 11 22 33 44 call_ea = seg.startEA while True: call_ea = idaapi.find_binary(call_ea + 1, seg.endEA, "FF 15", 16, idaapi.SEARCH_DOWN) if call_ea == idaapi.BADADDR: break ptr_calls.append(call_ea) # Search all instances of JMP /2 imm32/64 - FF 25 # TODO: Alternative pointer calls using SIB: FF 24 E5 11 22 33 44 - jmp dword/qword ptr [0x44332211] # FF 24 65 11 22 33 44 # FF 24 25 11 22 33 44 call_ea = seg.startEA while True: call_ea = idaapi.find_binary(call_ea + 1, seg.endEA, "FF 25", 16, idaapi.SEARCH_DOWN) if call_ea == idaapi.BADADDR: break ptr_calls.append(call_ea) ################################################################### # Extract all of the function pointers and make sure they are # are writable. # List of writable function pointer objects in a given module ptrs = list() for call_ea in ptr_calls: # Decode CALL/JMP instruction # NOTE: May result in invalid disassembly of split instructions insn_size = idaapi.decode_insn(call_ea) if insn_size: insn = idaapi.cmd insn_op1 = insn.Operands[0].type # Verify first operand is a direct memory reference if insn.Operands[0].type == idaapi.o_mem: # Get operand address ptr_ea = insn.Operands[0].addr # Apply pointer offset ptr_ea -= self.ptrOffset # Locate segment where the pointer is located ptr_seg = idaapi.getseg(ptr_ea) # Make sure a valid segment writeable segment was found if ptr_seg and ptr_seg.perm & idaapi.SEGPERM_WRITE: # Get pointer charset ptr_charset = self.sploiter.get_ptr_charset(ptr_ea) # Filter the pointer if not self.filterP2P: if ptr_charset == None: continue if self.ptrNonull and not "nonull" in ptr_charset: continue if self.ptrUnicode and not "unicode" in ptr_charset: continue if self.ptrAscii and not "ascii" in ptr_charset: continue if self.ptrAsciiPrint and not "asciiprint" in ptr_charset: continue if self.ptrAlphaNum and not "alphanum" in ptr_charset: continue if self.ptrNum and not "numeric" in ptr_charset: continue if self.ptrAlpha and not "alpha" in ptr_charset: continue # Increment the fptr counter # Get pointer disassembly insn_disas = idc.GetDisasmEx(call_ea, idaapi.GENDSM_FORCE_CODE) # Add pointer to the list ptr = Ptr(m.file, ptr_ea, self.ptrOffset, ptr_charset, call_ea, insn_disas) ptrs.append(ptr) ################################################################### # Cache Pointers to Pointers ptr_ea_prefix_cache = dict() if self.searchP2P: # CACHE: Running repeated searches over the entire memory space is # very expensive. Let's cache all of the addresses containing # bytes corresponding to discovered function pointers in a # single search and simply reference this cache for each # function pointer. Specifically running idaapi.find_binary() # is much more expensive than idaapi.dbg_read_memory(). # # NOTE: For performance considerations, the cache works on a per # module basis, but could be expanded for the entire memory # space. # # prefix_offset - how many bytes of discovered function # pointers to cache. # # Example: For function pointers 0x00401234, 0x00404321, 0x000405678 # we are going to use prefix_offset 2, so we will cache all of the # values located at addresses 0x0040XXXX if self.sploiter.addr64: pack_format = "<Q" addr_bytes = 8 prefix_offset = 6 else: pack_format = "<I" addr_bytes = 4 prefix_offset = 2 # Set of unique N-byte address prefixes to search in memory ea_prefix_set = set() for ptr in ptrs: ptr_ea = ptr.ptr_ea ptr_bytes = struct.pack(pack_format, ptr_ea) ptr_bytes = ptr_bytes[-prefix_offset:] ea_prefix_set.add(ptr_bytes) # Search the module for all bytes corresponding to the prefix # and use them as candidates for pointers-to-pointers for ea_prefix in ea_prefix_set: # NOTE: Make sure you search using 44 33 22 11 format and not 11223344 ea_prefix_str = " ".join(["%02x" % ord(b) for b in ea_prefix]) # Initialize search parameters for a given module ea = m.addr maxea = m.addr + m.size while True: ea = idaapi.find_binary(ea + 1, maxea, ea_prefix_str, 16, idaapi.SEARCH_DOWN) if ea == idaapi.BADADDR: break p2p_ea = ea - (addr_bytes - prefix_offset) dbg_mem = read_module_memory(p2p_ea, addr_bytes) ptr_ea_prefix = unpack(pack_format, dbg_mem)[0] if ptr_ea_prefix in ptr_ea_prefix_cache: ptr_ea_prefix_cache[ptr_ea_prefix].add(p2p_ea) else: ptr_ea_prefix_cache[ptr_ea_prefix] = set([p2p_ea, ]) # Detect search cancellation, but allow the loop below # to run to create already cached/found function pointers # Canceled if breakFlag or idaapi.wasBreak(): breakFlag = True break # Canceled if breakFlag or idaapi.wasBreak(): breakFlag = True break ################################################################### # Locate Pointer to Pointers for ptr in ptrs: ptr_ea = ptr.ptr_ea # Locate pointers-to-pointers for a given function pointer in the cache if self.searchP2P and ptr_ea in ptr_ea_prefix_cache: for p2p_ea in ptr_ea_prefix_cache[ptr_ea]: # Apply pointer-to-pointer offset p2p_ea -= self.p2pOffset p2p_charset = self.sploiter.get_ptr_charset(p2p_ea) # Filter the pointer if self.filterP2P: if p2p_charset == None: continue if self.ptrNonull and not "nonull" in p2p_charset: continue if self.ptrUnicode and not "unicode" in p2p_charset: continue if self.ptrAscii and not "ascii" in p2p_charset: continue if self.ptrAsciiPrint and not "asciiprint" in p2p_charset: continue if self.ptrAlphaNum and not "alphanum" in p2p_charset: continue if self.ptrNum and not "numeric" in p2p_charset: continue if self.ptrAlpha and not "alpha" in p2p_charset: continue # Copy existing pointer object to modify it for the particular p p2p = copy.copy(ptr) p2p.p2p_ea = p2p_ea p2p.p2p_offset = self.p2pOffset p2p.p2p_charset = p2p_charset # Apppend p2p specific pointer object to the global list self.ptrs.append(p2p) # Exceeded maximum number of pointers if self.maxPtrs and len(self.ptrs) >= self.maxPtrs: breakFlag = True print "[idasploiter] Maximum number of pointers exceeded." break # Simply append pointer object to the global list else: self.ptrs.append(ptr) # Exceeded maximum number of pointers if self.maxPtrs and len(self.ptrs) >= self.maxPtrs: breakFlag = True print "[idasploiter] Maximum number of pointers exceeded." break if breakFlag or idaapi.wasBreak(): breakFlag = True break # Canceled # NOTE: Only works when started from GUI not script. if breakFlag or idaapi.wasBreak(): breakFlag = True print "[idasploiter] Canceled." break print "[idasploiter] Found %d total pointers." % len(self.ptrs) idaapi.hide_wait_box()
def is_seg_init(ea): return idaapi.get_segm_name(idaapi.getseg(ea)).startswith('.init')
def new(offset, size, name, **kwds): """Create a segment at `offset` with `size` and name it according to `name`. The keyword `bits` can be used to specify the bit size of the segment The keyword `comb` can be used to specify any flags (idaapi.sc*) The keyword `align` can be used to specify paragraph alignment (idaapi.sa*) The keyword `org` specifies the origin of the segment (must be paragraph aligned due to ida) """ res = utils.string.to(name) # find the segment according to the name specified by the user seg = idaapi.get_segm_by_name(res) if seg is not None: raise E.DuplicateItemError( u"{:s}.new({:#x}, {:+#x}, \"{:s}\"{:s}) : A segment with the specified name (\"{:s}\") already exists." .format( __name__, offset, size, utils.string.escape(name, '"'), u", {:s}".format(utils.string.kwargs(kwds)) if kwds else '', utils.string.escape(name, '"'))) # FIXME: use disassembler default bit length instead of 32 bits = kwds.get( 'bits', 32 if idaapi.getseg(offset) is None else idaapi.getseg(offset).abits()) ## create a selector with the requested origin if bits == 16: org = kwds.get('org', 0) if org & 0xf > 0: raise E.InvalidTypeOrValueError( u"{:s}.new({:#x}, {:+#x}, {!r}{:s}) : The specified origin ({:#x}) is not aligned to the size of a paragraph (0x10)." .format( __name__, offset, size, name, u", {:s}".format( utils.string.kwargs(kwds)) if kwds else '', org)) para = offset // 16 sel = idaapi.allocate_selector(para) idaapi.set_selector(sel, (para - kwds.get('org', 0) // 16) & 0xffffffff) ## if the user specified a selector, then use it elif 'sel' in kwds or 'selector' in kwds: sel = kwds.get('sel', kwds.get('selector', idaapi.find_free_selector())) ## choose the paragraph size defined by the user elif 'para' in kwds or 'paragraphs' in kwds: para = kwds.get('paragraph', kwds.get('para', 1)) sel = idaapi.setup_selector(para) ## find a selector that is 1 paragraph size, elif idaapi.get_selector_qty(): sel = idaapi.find_selector(1) # otherwise find a free one and set it. else: sel = idaapi.find_free_selector() idaapi.set_selector(sel, 1) # populate the segment_t for versions of IDA prior to 7.0 if idaapi.__version__ < 7.0: seg = idaapi.segment_t() seg.startEA, seg.endEA = offset, offset + size # now for versions of IDA 7.0 and newer else: seg = idaapi.segment_t() seg.start_ea, seg.end_ea = offset, offset + size # assign the rest of the necessary attributes seg.sel = sel seg.bitness = {16: 0, 32: 1, 64: 2}[bits] seg.comb = kwds.get('comb', idaapi.scPub) # public seg.align = kwds.get('align', idaapi.saRelByte) # paragraphs # now we can add our segment_t to the database res = utils.string.to(name) ok = idaapi.add_segm_ex(seg, res, "", idaapi.ADDSEG_NOSREG | idaapi.ADDSEG_SPARSE) if not ok: ok = idaapi.del_selector(sel) if not ok: logging.warning( u"{:s}.new({:#x}, {:+#x}, {!r}{:s}) : Unable to delete the created selector ({:#x}) for the new segment." .format( __name__, offset, size, name, u", {:s}".format( utils.string.kwargs(kwds)) if kwds else '', sel)) raise E.DisassemblerError( u"{:s}.new({:#x}, {:+#x}, {!r}{:s}) : Unable to add a new segment." .format( __name__, offset, size, name, u", {:s}".format(utils.string.kwargs(kwds)) if kwds else '')) return seg
def by_address(ea): '''Return the segment that contains the specified `ea`.''' seg = idaapi.getseg(interface.address.within(ea)) if seg is None: raise E.SegmentNotFoundError(u"{:s}.by_address({:#x}) : Unable to locate segment containing the specified address.".format(__name__, ea)) return seg
def by_address(ea): '''Return the segment that contains the specified ``ea``.''' s = idaapi.getseg(interface.address.within(ea)) if s is None: raise LookupError("{:s}.by_address({:x}) : Unable to locate segment".format(__name__, ea)) return s
# Triple recursion limit. sys.setrecursionlimit(3 * sys.getrecursionlimit()) plt_seg = None plt_start = 0 plt_end = 0 segments = list(idautils.Segments()) exec_segments = list() for segment in segments: if idc.SegName(segment) == ".plt": plt_seg = segment plt_start = idc.SegStart(plt_seg) plt_end = idc.SegEnd(plt_seg) permissions = idaapi.getseg(segment).perm if permissions & idaapi.SEGPERM_EXEC: exec_segments.append(segment) allowed_xref_types = [ IDA_XrefTypes.Code_Far_Call, IDA_XrefTypes.Code_Near_Call, IDA_XrefTypes.Code_Far_Jump, IDA_XrefTypes.Code_Near_Jump, IDA_XrefTypes.Data_Offset ] start_time = time.time() # Import existing ssa file if exists in order to be able to process idb # in multiple steps. export_ssa_file = idc.GetInputFile() + "_ssa.pb2" export_ssa_dict = dict()
def create_got_fix(cls): idaapi.add_segm(0, 0x90000000, 0x90000001, '.got', 'DATA') seg = idaapi.getseg(0x90000000) idaapi.set_visible_segm(seg, False)
def print_section_list(): for s in idautils.Segments(): seg = idaapi.getseg(s) print(" {name:\"%s\", begin:0x%x, end:0x%x}," % (idc.SegName(s), idc.SegStart(s), idc.SegEnd(s)))
def byAddress(ea): '''Return the segment_t that holds the specified /ea/''' s = idaapi.getseg(ea) if s is None: raise Exception, "segment.byAddress(%x):unable to locate segment" % ea return s