def struct_add_ptr(sid, name, offset, count=1, type=None): """Add a pointer to a structure. If sid is a union, offset must be -1. """ ptr_flag = idc.FF_DATA | word_flag(WORD_SIZE) | idaapi.offflag() ret = idc.AddStrucMember(sid, name, offset, ptr_flag, 0, WORD_SIZE) if ret == 0 and type is not None: if offset == -1: offset = struct_member_offset(sid, name) assert offset is not None mid = idc.GetMemberId(sid, offset) idc.SetType(mid, type) return ret
class QMetaObject__d: """ struct QMetaObject::d { // private data const QMetaObject *superdata; const QByteArrayData *stringdata; const uint *data; StaticMetacallFunction static_metacall; const QMetaObject * const *relatedMetaObjects; void *extradata; //reserved for future use } d; """ c_struct = [("superdata", offflag() | FF_DATA | ARCH_F), ("stringdata", offflag() | FF_DATA | ARCH_F), ("data", offflag() | FF_DATA | ARCH_F), ("metacall", offflag() | FF_DATA | ARCH_F), ("relatedMetaObjects", offflag() | FF_DATA | ARCH_F), ("extradata", offflag() | FF_DATA | ARCH_F)] def __init__(self, offset): struct_map(self, self.c_struct, offset) struct_maker(self, offset)
class typemap: """Convert bidirectionally from a pythonic type into an IDA type""" FF_MASK = 0xfff00000 # Mask that specifies the structure's type # FIXME: In some cases FF_nOFF (where n is 0 or 1) does not actually # get auto-treated as an pointer by ida. Instead, it appears to # only get marked as an "offset" and rendered as an integer. integermap = { 1: (idaapi.byteflag(), -1), 2: (idaapi.wordflag(), -1), 3: (idaapi.tribyteflag(), -1), 4: (idaapi.dwrdflag(), -1), 8: (idaapi.qwrdflag(), -1), 10: (idaapi.tbytflag(), -1), 16: (idaapi.owrdflag(), -1), } if hasattr(idaapi, 'ywrdflag'): integermap[32] = getattr(idaapi, 'ywrdflag')(), -1 decimalmap = { 4: (idaapi.floatflag(), -1), 8: (idaapi.doubleflag(), -1), 10: (idaapi.packrealflag(), -1), 12: (idaapi.packrealflag(), -1), } stringmap = { str: (idaapi.asciflag(), idaapi.ASCSTR_TERMCHR), unicode: (idaapi.asciflag(), idaapi.ASCSTR_UNICODE), } charmap = { chr: (idaapi.charflag(), -1), } ptrmap = { sz: (idaapi.offflag() | flg, tid) for sz, (flg, tid) in integermap.iteritems() } typemap = { int: integermap, long: integermap, float: decimalmap, str: stringmap, unicode: stringmap, chr: charmap, type: ptrmap, } # inverted lookup table inverted = {} for s, (f, _) in integermap.items(): inverted[f & FF_MASK] = (int, s) for s, (f, _) in decimalmap.items(): inverted[f & FF_MASK] = (float, s) for s, (f, _) in stringmap.items(): inverted[f & FF_MASK] = (str, s) for s, (f, _) in ptrmap.items(): inverted[f & FF_MASK] = (type, s) del f inverted[idaapi.FF_STRU] = (int, 1) # FIXME: hack for dealing with # structures that have the flag set # but aren't actually structures.. # defaults integermap[None] = integermap[(hasattr(database, 'config') and database.config.bits() or 32) / 8] decimalmap[None] = decimalmap[(hasattr(database, 'config') and database.config.bits() or 32) / 8] ptrmap[None] = ptrmap[(hasattr(database, 'config') and database.config.bits() or 32) / 8] stringmap[None] = stringmap[str] charmap[None] = charmap[chr] @classmethod def dissolve(cls, flag, typeid, size): dt = flag & cls.FF_MASK sf = -1 if idaapi.is_signed_data(flag) else +1 if dt == idaapi.FF_STRU and isinstance(typeid, (int, long)): t = instance(typeid) sz = t.size return t if sz == size else ([t], size // sz) if dt not in cls.inverted: logging.warn( 'typemap.disolve(%r, %r, %r) : Unable to identify a pythonic type' % (dt, typeid, size)) t, sz = cls.inverted[dt] res = t if sz == size else [t, sz * sf] return res if sz == size else (res, size) @classmethod def resolve(cls, type): """Return ida's (flag,typeid,size) given the type (type,size) or (type/instance) (int,4) -- a dword ([int,4],8) -- an array of 8 dwords (str,10) -- an ascii string of 10 characters (int,2) -- a word (chr,4) -- an array of 4 characters """ # FIXME: Array definitions seem awkward, I think they should look # like [type, length] and so an array of 4 words should be # [(int,2), 4] # return idaapi.FF_xxx, typeid, and size given a tuple (type,size) or just a type/instance type, nbytes = type if isinstance(type, tuple) else (type, None) # FIXME: this explicit checking of nbytes being None is sloppy size = 0 if nbytes is None else abs(nbytes) # structure -- structure_t if isinstance(type, structure_t): flag, typeid = idaapi.struflag(), type.id elif type is None: flag, typeid = idaapi.alignflag(), -1 elif isinstance(type, [].__class__): flag, typeid, nb = cls.resolve( tuple(type)) if len(type) > 1 else cls.resolve(*type) size = nb if nbytes is None else (size * nb) # FIXME # defined in typemap -- (type,size) else: table = cls.typemap[type] if type in (int, long, float, type): flag, typeid = table[None if nbytes is None else size] # FIXME else: flag, typeid = table[type] # automatically determine the size for the requested typeid if nbytes is None: opinfo = idaapi.opinfo_t() opinfo.tid = typeid size = idaapi.get_data_type_size(flag, opinfo) elif nbytes < 0: flag |= idaapi.signed_data_flag() return flag, typeid, size
i = 0 for t,nsize in zip(simple_types, simple_sizes): print "t%x:"% ((t|FF_DATA)&0xFFFFFFFF), AddStrucMember(sid, "t%02d"%i, BADADDR, (t|FF_DATA )&0xFFFFFFFF, -1, nsize) i+=1 # Test ASCII type print "ASCII:", AddStrucMember(sid, "tascii", -1, FF_ASCI|FF_DATA, ASCSTR_C, 8) # Test enum type - Add a defined enum name or load MACRO_WMI from a type library. #eid = GetEnum("MACRO_WMI") #print "Enum:", AddStrucMember(sid, "tenum", BADADDR, FF_0ENUM|FF_DATA|FF_DWRD, eid, 4) # Test struc member type msid = GetStrucIdByName("mystr2") if msid != -1: DelStruc(msid) msid = AddStrucEx(-1, "mystr2", 0) print AddStrucMember(msid, "member1", -1, (FF_DWRD|FF_DATA )&0xFFFFFFFF, -1, 4) print AddStrucMember(msid, "member2", -1, (FF_DWRD|FF_DATA )&0xFFFFFFFF, -1, 4) msize = GetStrucSize(msid) print "Struct:", AddStrucMember(sid, "tstruct", -1, FF_STRU|FF_DATA, msid, msize) print "Stroff:", AddStrucMember(sid, "tstroff", -1, stroffflag()|FF_DWRD, msid, 4) # Test offset types print "Offset:", AddStrucMember(sid, "toffset", -1, offflag()|FF_DATA|FF_DWRD, 0, 4) print "Offset:", SetMemberType(sid, 0, offflag()|FF_DATA|FF_DWRD, 0, 4) print "Done"
i = 0 for t,nsize in zip(simple_types, simple_sizes): print "t%x:"% ((t|FF_DATA)&0xFFFFFFFF), add_struc_member(sid, "t%02d"%i, BADADDR, (t|FF_DATA )&0xFFFFFFFF, -1, nsize) i+=1 # Test ASCII type print "ASCII:", add_struc_member(sid, "tascii", -1, FF_STRLIT|FF_DATA, STRTYPE_C, 8) # Test enum type - Add a defined enum name or load MACRO_WMI from a type library. #eid = get_enum("MACRO_WMI") #print "Enum:", add_struc_member(sid, "tenum", BADADDR, FF_0ENUM|FF_DATA|FF_DWORD, eid, 4) # Test struc member type msid = get_struc_id("mystr2") if msid != -1: del_struc(msid) msid = add_struc(-1, "mystr2", 0) print add_struc_member(msid, "member1", -1, (FF_DWORD|FF_DATA )&0xFFFFFFFF, -1, 4) print add_struc_member(msid, "member2", -1, (FF_DWORD|FF_DATA )&0xFFFFFFFF, -1, 4) msize = get_struc_size(msid) print "Struct:", add_struc_member(sid, "tstruct", -1, FF_STRUCT|FF_DATA, msid, msize) print "Stroff:", add_struc_member(sid, "tstroff", -1, stroffflag()|FF_DWORD, msid, 4) # Test offset types print "Offset:", add_struc_member(sid, "toffset", -1, offflag()|FF_DATA|FF_DWORD, 0, 4) print "Offset:", set_member_type(sid, 0, offflag()|FF_DATA|FF_DWORD, 0, 4) print "Done"
# Test ASCII type print "ASCII:", AddStrucMember(sid, "tascii", -1, FF_ASCI | FF_DATA, ASCSTR_C, 8) # Test enum type - Add a defined enum name or load MACRO_WMI from a type library. #eid = GetEnum("MACRO_WMI") #print "Enum:", AddStrucMember(sid, "tenum", BADADDR, FF_0ENUM|FF_DATA|FF_DWRD, eid, 4) # Test struc member type msid = GetStrucIdByName("mystr2") if msid != -1: DelStruc(msid) msid = AddStrucEx(-1, "mystr2", 0) print AddStrucMember(msid, "member1", -1, (FF_DWRD | FF_DATA) & 0xFFFFFFFF, -1, 4) print AddStrucMember(msid, "member2", -1, (FF_DWRD | FF_DATA) & 0xFFFFFFFF, -1, 4) msize = GetStrucSize(msid) print "Struct:", AddStrucMember(sid, "tstruct", -1, FF_STRU | FF_DATA, msid, msize) print "Stroff:", AddStrucMember(sid, "tstroff", -1, stroffflag() | FF_DWRD, msid, 4) # Test offset types print "Offset:", AddStrucMember(sid, "toffset", -1, offflag() | FF_DATA | FF_DWRD, 0, 4) print "Offset:", SetMemberType(sid, 0, offflag() | FF_DATA | FF_DWRD, 0, 4) print "Done"
#eid = get_enum("MACRO_WMI") #print("Enum:", add_struc_member(sid, "tenum", BADADDR, FF_0ENUM|FF_DATA|FF_DWORD, eid, 4)) # Test struc member type msid = get_struc_id("mystr2") if msid != -1: del_struc(msid) msid = add_struc(-1, "mystr2", 0) print( add_struc_member(msid, "member1", -1, (FF_DWORD | FF_DATA) & 0xFFFFFFFF, -1, 4)) print( add_struc_member(msid, "member2", -1, (FF_DWORD | FF_DATA) & 0xFFFFFFFF, -1, 4)) msize = get_struc_size(msid) print("Struct:", add_struc_member(sid, "tstruct", -1, FF_STRUCT | FF_DATA, msid, msize)) print("Stroff:", add_struc_member(sid, "tstroff", -1, stroffflag() | FF_DWORD, msid, 4)) # Test offset types print( "Offset:", add_struc_member(sid, "toffset", -1, offflag() | FF_DATA | FF_DWORD, 0, 4)) print("Offset:", set_member_type(sid, 0, offflag() | FF_DATA | FF_DWORD, 0, 4)) print("Done")
i = 0 for t,nsize in zip(simple_types, simple_sizes): print("t%x:"% ((t|FF_DATA)&0xFFFFFFFF), add_struc_member(sid, "t%02d"%i, BADADDR, (t|FF_DATA )&0xFFFFFFFF, -1, nsize)) i+=1 # Test ASCII type print("ASCII:", add_struc_member(sid, "tascii", -1, FF_STRLIT|FF_DATA, STRTYPE_C, 8)) # Test enum type - Add a defined enum name or load MACRO_WMI from a type library. #eid = get_enum("MACRO_WMI") #print "Enum:", add_struc_member(sid, "tenum", BADADDR, FF_0ENUM|FF_DATA|FF_DWORD, eid, 4) # Test struc member type msid = get_struc_id("mystr2") if msid != -1: del_struc(msid) msid = add_struc(-1, "mystr2", 0) print(add_struc_member(msid, "member1", -1, (FF_DWORD|FF_DATA )&0xFFFFFFFF, -1, 4)) print(add_struc_member(msid, "member2", -1, (FF_DWORD|FF_DATA )&0xFFFFFFFF, -1, 4)) msize = get_struc_size(msid) print("Struct:", add_struc_member(sid, "tstruct", -1, FF_STRUCT|FF_DATA, msid, msize)) print("Stroff:", add_struc_member(sid, "tstroff", -1, stroffflag()|FF_DWORD, msid, 4)) # Test offset types print("Offset:", add_struc_member(sid, "toffset", -1, offflag()|FF_DATA|FF_DWORD, 0, 4)) print("Offset:", set_member_type(sid, 0, offflag()|FF_DATA|FF_DWORD, 0, 4)) print("Done")
class typemap: """Convert bidirectionally from a pythonic type into an IDA type""" FF_MASKSIZE = 0xf0000000 # Mask that select's the flag's size FF_MASK = 0xfff00000 # Mask that select's the flag's repr # FIXME: In some cases FF_nOFF (where n is 0 or 1) does not actually # get auto-treated as an pointer by ida. Instead, it appears to # only get marked as an "offset" and rendered as an integer. integermap = { 1: (idaapi.byteflag(), -1), 2: (idaapi.wordflag(), -1), 3: (idaapi.tribyteflag(), -1), 4: (idaapi.dwrdflag(), -1), 8: (idaapi.qwrdflag(), -1), 10: (idaapi.tbytflag(), -1), 16: (idaapi.owrdflag(), -1), } if idaapi.__version__ >= 7.0: del integermap[3] if hasattr(idaapi, 'ywrdflag'): integermap[32] = getattr(idaapi, 'ywrdflag')(), -1 decimalmap = { 4: (idaapi.floatflag(), -1), 8: (idaapi.doubleflag(), -1), 10: (idaapi.packrealflag(), -1), 12: (idaapi.packrealflag(), -1), } stringmap = { chr: (idaapi.asciflag(), 0), str: (idaapi.asciflag(), idaapi.ASCSTR_TERMCHR), unicode: (idaapi.asciflag(), idaapi.ASCSTR_UNICODE), } ptrmap = { sz: (idaapi.offflag() | flg, tid) for sz, (flg, tid) in integermap.iteritems() } nonemap = {None: (idaapi.alignflag(), -1)} typemap = { int: integermap, long: integermap, float: decimalmap, str: stringmap, unicode: stringmap, chr: stringmap, type: ptrmap, None: nonemap, } # inverted lookup table inverted = {} for s, (f, _) in integermap.items(): inverted[f & FF_MASKSIZE] = (int, s) for s, (f, _) in decimalmap.items(): inverted[f & FF_MASKSIZE] = (float, s) for s, (f, _) in stringmap.items(): inverted[f & FF_MASKSIZE] = (str, s) for s, (f, _) in ptrmap.items(): inverted[f & FF_MASK] = (type, s) del f inverted[idaapi.FF_STRU] = (int, 1) # FIXME: hack for dealing with # structures that have the flag set # but aren't actually structures.. # defaults @classmethod def __newprc__(cls, pnum): info = idaapi.get_inf_structure() bits = 64 if info.is_64bit() else 32 if info.is_32bit() else None if bits is None: return typemap.integermap[None] = typemap.integermap[bits / 8] typemap.decimalmap[None] = typemap.decimalmap[bits / 8] typemap.ptrmap[None] = typemap.ptrmap[bits / 8] typemap.stringmap[None] = typemap.stringmap[str] @classmethod def __ev_newprc__(cls, pnum, keep_cfg): return cls.__newprc__(pnum) @classmethod def dissolve(cls, flag, typeid, size): dt = flag & cls.FF_MASKSIZE sf = -1 if flag & idaapi.FF_SIGN == idaapi.FF_SIGN else +1 if dt == idaapi.FF_STRU and isinstance(typeid, six.integer_types): # FIXME: figure out how to fix this recursive module dependency t = sys.modules.get('structure', __import__('structure')).instance(typeid) sz = t.size return t if sz == size else [t, size // sz] if dt not in cls.inverted: logging.warn( "{:s}.dissolve({!r}, {!r}, {!r}) : Unable to identify a pythonic type." .format('.'.join(('internal', __name__, cls.__name__)), dt, typeid, size)) t, sz = cls.inverted[dt] # if the type and size are the same, then it's a string or pointer type if not isinstance(sz, six.integer_types): count = size // idaapi.get_data_elsize(idaapi.BADADDR, dt, idaapi.opinfo_t()) return [t, count] if count > 1 else t # if the size matches, then we assume it's a single element elif sz == size: return t, (sz * sf) # otherwise it's an array return [(t, sz * sf), size // sz] @classmethod def resolve(cls, pythonType): """Return ida's (flag,typeid,size) given the type (type,size) or (type/instance) (int,4) -- a dword [(int,4),8] -- an array of 8 dwords (str,10) -- an ascii string of 10 characters (int,2) -- a word [chr,4] -- an array of 4 characters """ sz, count = None, 1 # FIXME: figure out how to fix this recursive module dependency # figure out what format pythonType is in if isinstance(pythonType, ().__class__): (t, sz), count = pythonType, 1 table = cls.typemap[t] flag, typeid = table[abs(sz) if t in (int, long, float, type) else t] elif isinstance(pythonType, [].__class__): # an array, which requires us to recurse... res, count = pythonType flag, typeid, sz = cls.resolve(res) elif isinstance( pythonType, sys.modules.get('structure', __import__('structure')).structure_t): # it's a structure, pass it through. flag, typeid, sz = idaapi.struflag( ), pythonType.id, pythonType.size else: # default size that we can lookup in the typemap table table = cls.typemap[pythonType] flag, typeid = table[None] opinfo = idaapi.opinfo_t() opinfo.tid = typeid return flag, typeid, idaapi.get_data_elsize( idaapi.BADADDR, flag, opinfo) return flag | (idaapi.FF_SIGN if sz < 0 else 0), typeid, abs(sz) * count