Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 34 additions & 20 deletions vtable_structs.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import idc
import idautils
import idaapi
import ida_typeinf
import ctypes
import time

Expand Down Expand Up @@ -215,12 +216,12 @@ def get_class_from_ea(classtype, ea):
bytestr = idaapi.get_bytes(ea, ctypes.sizeof(classtype))
return classtype.from_buffer_copy(bytestr)

def add_struc_ex(name):
strucid = idaapi.get_struc_id(name)
if strucid == idc.BADADDR:
strucid = idaapi.add_struc(idc.BADADDR, name)
# def add_struc_ex(name):
# strucid = idc.get_struc_id(name)
# if strucid == idc.BADADDR:
# strucid = idc.add_struc(idc.BADADDR, name, 0)

return strucid
# return strucid

# Anything past Classname::
# Thank you CTFPlayer::SOCacheUnsubscribed...
Expand Down Expand Up @@ -394,27 +395,40 @@ def calc_member_tinfo(vfunc):
InfoCache.tinfos[vfunc.funcref.ea] = tinfo
return tinfo

def add_struc_new(name):
tid = idaapi.get_named_type_tid(name)
if tid != idaapi.BADADDR:
# The struct already exists.
print("Struct {!r} Already exists!".format(name))

tid = idaapi.tinfo_t.create_udt(idaapi.BADADDR, name, 0)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runtime error


if tid == idaapi.BADADDR:
print(f"{tid} Struct creation failed.")
else:
print(f"creating struct {tid}")

return tid

def create_structs(data):
# Now this is an awesome API function that we most certainly need
idaapi.begin_type_updating(idaapi.UTP_STRUCT)

for classname, vtables in data.items():
classstrucid = add_struc_ex(classname)
classstruc = idaapi.get_struc(classstrucid)
classstrucid = add_struc_new(classname)

for thisoffs, vfuncs in vtables.items():
thisoffs = abs(thisoffs)
postfix = f"_{thisoffs:04X}" if thisoffs != 0 else ""
structype = f"{classname}{postfix}{idaapi.VTBL_SUFFIX}"
structype = idaapi.validate_name(structype, idaapi.VNT_TYPE, idaapi.SN_IDBENC)

vtablestrucid = add_struc_ex(structype)
vtablestruc = idaapi.get_struc(vtablestrucid)
vtablestrucid = add_struc_new(structype)
for i, vfunc in enumerate(vfuncs):
offs = i * ctypes.sizeof(ea_t)
targetname = vfunc.funcref.sname

currmem = idaapi.get_member(vtablestruc, offs)
currmem = idc.get_member_id(vtablestrucid, offs)
if currmem:
# memname = idaapi.get_member_name(currmem.id)
# # Can have a postfix so we use in operator
Expand Down Expand Up @@ -446,35 +460,35 @@ def create_structs(data):
opinfo.ri.base = 0
opinfo.ri.tdelta = 0

serr = idaapi.add_struc_member(vtablestruc, targetname, offs, FF_PTR|idc.FF_0OFF, opinfo, ctypes.sizeof(ea_t))
serr = idc.add_struc_member(vtablestrucid, targetname, offs, FF_PTR|idc.FF_0OFF, opinfo, ctypes.sizeof(ea_t))
# Failed, so there was either an invalid name or a name collision
if serr == idaapi.STRUC_ERROR_MEMBER_NAME:
targetname = idaapi.validate_name(targetname, idaapi.VNT_IDENT, idaapi.SN_IDBENC)
serr = idaapi.add_struc_member(vtablestruc, targetname, offs, FF_PTR|idc.FF_0OFF, opinfo, ctypes.sizeof(ea_t))
serr = idc.add_struc_member(vtablestrucid, targetname, offs, FF_PTR|idc.FF_0OFF, opinfo, ctypes.sizeof(ea_t))
if serr == idaapi.STRUC_ERROR_MEMBER_NAME:
targetname = f"{targetname}_{offs:X}"
serr = idaapi.add_struc_member(vtablestruc, targetname, offs, FF_PTR|idc.FF_0OFF, opinfo, ctypes.sizeof(ea_t))
serr = idc.add_struc_member(vtablestrucid, targetname, offs, FF_PTR|idc.FF_0OFF, opinfo, ctypes.sizeof(ea_t))

if serr != idaapi.STRUC_ERROR_MEMBER_OK:
print(vtablestruc, vtablestrucid)
print(vtablestrucid, vtablestrucid)
print(f"Failed to add member {classname}::{vfunc.funcref.sname} ({targetname}) at offset {offs:#x} -> {serr}")
continue

tinfo = calc_member_tinfo(vfunc)
if tinfo is not None:
mem = idaapi.get_member(vtablestruc, offs)
idaapi.set_member_tinfo(vtablestruc, mem, 0, tinfo, 0)
mem = idc.get_member_id(vtablestrucid, offs)
idaapi.set_member_tinfo(vtablestrucid, mem, 0, tinfo, 0)

vmember = idaapi.get_member(classstruc, thisoffs)
vmember = idc.get_member_id(classstrucid, thisoffs)
if not vmember:
if idaapi.add_struc_member(classstruc, f"{idaapi.VTBL_MEMNAME}{postfix}", thisoffs, idc.FF_DATA | FF_PTR, None, ctypes.sizeof(ea_t)) == idaapi.STRUC_ERROR_MEMBER_OK:
if idc.add_struc_member(classstrucid, f"{idaapi.VTBL_MEMNAME}{postfix}", thisoffs, idc.FF_DATA | FF_PTR, None, ctypes.sizeof(ea_t)) == idaapi.STRUC_ERROR_MEMBER_OK:
global STRUCTS
STRUCTS += 1
tinfo = idaapi.tinfo_t()
if idaapi.guess_tinfo(tinfo, vtablestrucid) != idaapi.GUESS_FUNC_FAILED:
mem = idaapi.get_member(classstruc, thisoffs)
mem = idc.get_member_id(classstrucid, thisoffs)
tinfo.create_ptr(tinfo)
idaapi.set_member_tinfo(classstruc, mem, 0, tinfo, 0)
idaapi.set_member_tinfo(classstrucid, mem, 0, tinfo, 0)

def read_vtables_linux():
WaitBox.show("Parsing typeinfo")
Expand Down