I'm relatively new to python. However one thing that i liked was
ctypes style structs. Unfortunately you can't use ctypes structs to
interact with the IDA database, in IDAPython (for obvious reasons).
You can always copy the data to a buffer and use that. But then you
can't use pointers.
Anyway i decided to create this script. I think this style of
structure access would be a good addition to IDAPython. This is proof
of concept code.
import idc
def CreateArrayType(typ, length):
"""Creates a new Array type"""
name = "%.200s_Array_%i" % (typ.__name__, length)
return ArrayType_Type(name, (Array_Type,), {"_length_": length,
"_type_": typ})
def POINTER(typ):
"""Creates a new pointer type """
name = "LP_%s" % typ.__name__
return type(name, (Pointer_Type,), {"_type_": typ})
class ArrayType_Type(type):
"""metatype for the Array Objects"""
def __init__(self, name, bases, attrs):
if self.isArrayType(attrs):
setattr(self, "_size_", self._type_._size_* self._length_)
def isArrayType(self, attrs):
length = attrs.get('_length_')
if length:
return True
return False
def __mul__(self, length):
return CreateArrayType(self, length)
#similar to CData object in ctypes
class IDAData(object):
_address_ = 0
_size_ = 0 #size of block in bytes
#Just return self if we don't have a _type_ to grab
#and update the address for the type
def getfunc(self, address):
self._address_ = address
return self
class Array_Type(IDAData):
def __init__(self):
self.typ = self._type_()
def __getitem__(self, index):
if index < 0 or index >= self._length_:
raise IndexError()
offset = index * self._type_._size_
return self.typ.getfunc(self._address_ + offset)
def __len__(self):
return self._length_
class IDASimpleType(IDAData):
__metaclass__ = ArrayType_Type
class IDAField(object):
"""A data descriptor that sets and returns values
normally and prints a message logging their access.
"""
def __init__(self, name ,offset, typ):
self.name = name
self.offset = offset
self.typ = typ()
def __get__(self, obj, objtype):
if obj:
return self.typ.getfunc(obj._address_ + self.offset)
return self
def __set__(self, obj, val):
raise NotImplementedError()
def __repr__(self):
return "<Field type=%s, ofs=%d>" % (type(self.typ).__name__,
self.offset)
class StructType_Type(type):
def __init__(self, name, bases, attrs):
fields = attrs.get('_fields_')
if fields:
offset = 0
for fieldName, typ in fields:
setattr(IDAStructure, fieldName, IDAField(fieldName,
offset, typ))
offset += typ._size_
#the last offset is also the size
setattr(self, "_size_", offset)
def __mul__(self, length):
return CreateArrayType(self, length)
class IDAStructure(IDAData):
__metaclass__ = StructType_Type
def __init__(self):
pass
def setAddress(self, address):
self._address_ = address
class ida_int(IDASimpleType):
_type_ = "i"
_size_ = 4
def getfunc(self, address):
return idc.Dword(address)
class ida_b(IDASimpleType):
_type_ = "b"
_size_ = 1
def getfunc(self, address):
return idc.Byte(address)
class ida_c(IDASimpleType):
_type_ = "c"
_size_ = 1
def getfunc(self, address):
return chr(idc.Byte(address))
class ida_char_p(IDASimpleType):
_type_ = "z"
_size_ = 4
def getfunc(self, address):
return idc.GetString(idc.Dword(address), -1, idc.ASCSTR_C)
class Pointer_Type(IDASimpleType):
_size_ = 4
def __init__(self):
self.typ = self._type_()
def getfunc(self,address):
addr = idc.Dword(address)
print hex(addr)
return self.typ.getfunc(addr)
class Entry(IDAStructure):
_fields_ = [("name", ida_char_p),
("index", ida_int),
("size", ida_int),
("unk", ida_int*2)]
class Fields(IDAStructure):
_address_ = 0x00C144D0
_fields_ = [("entrys", Entry*6)]
def main():
fields = Fields()
for entry in fields.entrys:
print
entry.name, "=", entry.index
main()