def map(ea, size, newea, **kwds): """Map `size` bytes of data from `ea` into a new segment at `newea`. The keyword `name` can be used to name the segment. """ # grab the file offset and the data we want fpos, data = idaapi.get_fileregion_offset(ea), database.read(ea, size) if len(data) != size: raise E.ReadOrWriteError( u"{:s}.map({:#x}, {:+#x}, {:#x}{:s}) : Unable to read {:#x} bytes from {:#x}." .format( __name__, ea, size, newea, u", {:s}".format(utils.string.kwargs(kwds)) if kwds else '', size, ea)) # rebase the data to the new address res = idaapi.mem2base(data, newea, fpos) if not res: raise E.DisassemblerError( u"{:s}.map({:#x}, {:+#x}, {:#x}{:s}) : Unable to remap {:#x}:{:+#x} to {:#x}." .format( __name__, ea, size, newea, u", {:s}".format(utils.string.kwargs(kwds)) if kwds else '', ea, size, newea)) # now we can create the new segment return new(newea, size, kwds.get("name", "map_{:x}".format(ea)))
def new(name, flags=0): '''Create an enumeration with the specified `name` and `flags` using ``idaapi.add_enum``.''' idx = count() res = idaapi.add_enum(idx, utils.string.to(name), flags) if res == idaapi.BADADDR: raise E.DisassemblerError(u"{:s}.new({!r}, flags={:d}) : Unable to create enumeration named \"{:s}\".".format(__name__, name, flags, utils.string.escape(name, '"'))) return res
def add(cls, enum, name, value, **bitmask): """Add an enumeration member `name` with the specified `value` to the enumeration `enum`. If the int, `bitmask`, is specified then used it as the bitmask for the enumeration. """ eid = by(enum) bmask = bitmask.get('bitmask', idaapi.BADADDR & mask(eid)) res = interface.tuplename(name) if isinstance(name, tuple) else name ok = idaapi.add_enum_member(eid, utils.string.to(res), value, bmask) err = { getattr(idaapi, item): item for item in [ 'ENUM_MEMBER_ERROR_NAME', 'ENUM_MEMBER_ERROR_VALUE', 'ENUM_MEMBER_ERROR_ENUM', 'ENUM_MEMBER_ERROR_MASK', 'ENUM_MEMBER_ERROR_ILLV' ] } if ok in err.keys(): raise E.DisassemblerError( u"{:s}.add({:#x}, {!r}, {:#x}{:s}) : Unable to add member to enumeration due to error {:s}({:d})." .format( '.'.join([__name__, cls.__name__]), eid, name, value, u", {:s}".format(utils.string.kwargs(bitmask)) if bitmask else '', err[ok], ok)) return eid
def remove(cls, mid): '''Remove the enumeration member with the given `mid`.''' eid, value = cls.parent(mid), cls.value(mid) # XXX: is a serial of 0 valid? res = idaapi.del_enum_member(eid, value, 0, idaapi.BADADDR & cls.mask(mid)) if not res: raise E.DisassemblerError(u"{:s}.member.remove({:#x}) : Unable to remove member from enumeration.".format(__name__, mid)) return res
def new(name, flags=0): '''Create an enumeration with the specified ``name`` and ``flags`` using `idaapi.add_enum`.''' idx = count() res = idaapi.add_enum(idx, name, flags) if res == idaapi.BADADDR: raise E.DisassemblerError( "{:s}.new({!r}, flags={:d}) : Unable to create enumeration named {:s}." .format(__name__, name, flags, name)) return res
def __save_file(filename, ea, size, offset=0): path = os.path.abspath(filename) of = idaapi.fopenWB(path) if not of: raise E.DisassemblerError( "{:s}.save_file({!r}, {:#x}, {:+#x}) : Unable to open target file \"{:s}\"." .format(__name__, filename, ea, size, path)) res = idaapi.base2file(of, offset, ea, ea + size) idaapi.eclose(of) return res
def __load_file(filename, ea, size, offset=0): path = os.path.abspath(filename) res = idaapi.open_linput(path, False) if not res: raise E.DisassemblerError( "{:s}.load_file({!r}, {:#x}, {:+#x}) : Unable to create loader_input_t from path \"{:s}\"." .format(__name__, filename, ea, size, path)) ok = idaapi.file2base(res, offset, ea, ea + size, False) idaapi.close_linput(res) return ok
def __load_file(filename, ea, size, offset=0): path = os.path.abspath(filename) # use IDA to open up the file contents # XXX: does IDA support unicode file paths? res = idaapi.open_linput(path, False) if not res: raise E.DisassemblerError( u"{:s}.load_file({!r}, {:#x}, {:+#x}) : Unable to create an `idaapi.loader_input_t` from path \"{:s}\"." .format(__name__, filename, ea, size, path)) # now we can write the file into the specified address as a segment ok = idaapi.file2base(res, offset, ea, ea + size, False) idaapi.close_linput(res) return ok
def __save_file(filename, ea, size, offset=0): path = os.path.abspath(filename) # use IDA to open up a file to write to # XXX: does IDA support unicode file paths? of = idaapi.fopenWB(path) if not of: raise E.DisassemblerError( u"{:s}.save_file({!r}, {:#x}, {:+#x}) : Unable to open target file \"{:s}\"." .format(__name__, filename, ea, size, utils.string.escape(path, '"'))) # now we can write the segment into the file we opened res = idaapi.base2file(of, offset, ea, ea + size) idaapi.eclose(of) return res
def map(ea, size, newea, **kwds): """Map `size` bytes of data from `ea` into a new segment at `newea`. The keyword `name` can be used to name the segment. """ fpos, data = idaapi.get_fileregion_offset(ea), database.read(ea, size) if len(data) != size: raise E.ReadOrWriteError( "{:s}.map({:#x}, {:+#x}, {:#x}) : Unable to read {:#x} bytes from {:#x}." .format(__name__, ea, size, newea, size, ea)) res = idaapi.mem2base(data, newea, fpos) if not res: raise E.DisassemblerError( "{:s}.map({:#x}, {:+#x}, {:#x}) : Unable to remap {:#x}:{:+#x} to {:#x}." .format(__name__, ea, size, newea, ea, size, newea)) return new(newea, size, kwds.get("name', 'map_{:x}".format(ea)))
def add(cls, enum, name, value, **bitmask): """Add an enumeration member `name` with the specified `value` to the enumeration `enum`. If the int, `bitmask`, is specified then used it as the bitmask for the enumeration. """ eid = by(enum) bmask = bitmask.get('bitmask', idaapi.BADADDR & mask(eid)) res = interface.tuplename(name) if isinstance(name, tuple) else name ok = idaapi.add_enum_member(eid, res, value, bmask) err = { getattr(idaapi, n): n for n in ('ENUM_MEMBER_ERROR_NAME', 'ENUM_MEMBER_ERROR_VALUE', 'ENUM_MEMBER_ERROR_ENUM', 'ENUM_MEMBER_ERROR_MASK', 'ENUM_MEMBER_ERROR_ILLV') } if ok in err.viewkeys(): raise E.DisassemblerError( "{:s}.add({:#x}, {!r}, {:#x}, bitmask={!r}) : Unable to add member to enumeration due to error {:s}({:d})." .format('.'.join((__name__, cls.__name__)), eid, name, value, bitmask, err[ok], ok)) return eid
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 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) """ seg = idaapi.get_segm_by_name(name) if seg is not None: raise NameError( "{:s}.new({:#x}, {:+#x}, {!r}{:s}) : A segment with the specified name ({!r}) already exists." .format( __name__, offset, size, name, ", {:s}".format(', '.join( "{:s}={!r}".format(k, v) for k, v in kwds.iteritems())) if kwds else '', name)) 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 ## create a selector with the requested origin if bits == 16: org = kwds.get('org', 0) if org & 0xf > 0: raise E.InvalidTypeOrValueError( "{: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, ", {:s}".format(', '.join( "{:s}={!r}".format(k, v) for k, v in kwds.iteritems())) 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(res) ## 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) # create segment. ripped from idc 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 ok = idaapi.add_segm_ex(seg, name, "", idaapi.ADDSEG_NOSREG | idaapi.ADDSEG_SPARSE) if not ok: ok = idaapi.del_selector(sel) if not ok: logging.warn( "{:s}.new({:#x}, {:+#x}, {!r}{:s}) : Unable to delete the created selector ({:#x}) for the new segment." .format( __name__, offset, size, name, ", {:s}".format(', '.join( "{:s}={!r}".format(k, v) for k, v in kwds.iteritems())) if kwds else '', sel)) raise E.DisassemblerError( "{:s}.new({:#x}, {:+#x}, {!r}{:s}) : Unable to add a new segment.". format( __name__, offset, size, name, ", {:s}".format(', '.join( "{:s}={!r}".format(k, v) for k, v in kwds.iteritems())) if kwds else '')) return seg