185 lines
7.1 KiB
Python
185 lines
7.1 KiB
Python
import idaapi
|
|
import idc
|
|
|
|
|
|
class LocalType:
|
|
def __init__(self, name, members_ordinals, hint, is_selected=False, is_typedef=False, is_enum=False, is_union=False):
|
|
self.name = name
|
|
self.members_ordinals = members_ordinals
|
|
self.hint = hint
|
|
self.is_selected = is_selected
|
|
self.is_typedef = is_typedef
|
|
self.is_enum = is_enum
|
|
self.is_union = is_union
|
|
|
|
def __call__(self):
|
|
return self.name, self.members_ordinals
|
|
|
|
def __str__(self):
|
|
return "<{0}, {1}>".format(self.name, self.members_ordinals)
|
|
|
|
def __repr__(self):
|
|
return self.__str__()
|
|
|
|
@property
|
|
def name_and_color(self):
|
|
if self.is_selected:
|
|
return self.name, 0x0000FF
|
|
elif self.is_typedef:
|
|
return self.name, 0x99FFFF
|
|
elif self.is_enum:
|
|
return self.name, 0x33FF33
|
|
elif self.is_union:
|
|
return self.name, 0xCCCC00
|
|
return self.name, 0xffdd99
|
|
|
|
|
|
class StructureGraph:
|
|
# TODO:Enum types display
|
|
def __init__(self, ordinal_list=None):
|
|
self.ordinal_list = ordinal_list if ordinal_list else xrange(1, idc.GetMaxLocalType())
|
|
self.local_types = {}
|
|
self.edges = []
|
|
self.final_edges = []
|
|
self.visited_downward = []
|
|
self.visited_upward = []
|
|
self.downward_edges = {}
|
|
self.upward_edges = {}
|
|
self.initialize_nodes()
|
|
self.calculate_edges()
|
|
|
|
def change_selected(self, selected):
|
|
self.visited_downward = []
|
|
self.visited_upward = []
|
|
self.final_edges = []
|
|
for ordinal in self.ordinal_list:
|
|
self.local_types[ordinal].is_selected = False
|
|
self.ordinal_list = set(self.local_types).intersection(selected)
|
|
for ordinal in self.ordinal_list:
|
|
self.local_types[ordinal].is_selected = True
|
|
|
|
@staticmethod
|
|
def get_ordinal(tinfo):
|
|
while tinfo.is_ptr() or tinfo.is_array():
|
|
tinfo.remove_ptr_or_array()
|
|
if tinfo.is_udt():
|
|
return tinfo.get_ordinal()
|
|
elif tinfo.is_enum():
|
|
return tinfo.get_ordinal()
|
|
elif tinfo.is_typeref():
|
|
typeref_ordinal = tinfo.get_ordinal()
|
|
if typeref_ordinal:
|
|
typeref_tinfo = StructureGraph.get_tinfo_by_ordinal(typeref_ordinal)
|
|
if typeref_tinfo.is_typeref() or typeref_tinfo.is_udt() or typeref_tinfo.is_ptr():
|
|
return typeref_ordinal
|
|
else:
|
|
return 0
|
|
|
|
@staticmethod
|
|
def get_members_ordinals(tinfo):
|
|
ordinals = []
|
|
if tinfo.is_udt():
|
|
udt_data = idaapi.udt_type_data_t()
|
|
tinfo.get_udt_details(udt_data)
|
|
for udt_member in udt_data:
|
|
ordinal = StructureGraph.get_ordinal(udt_member.type)
|
|
if ordinal:
|
|
ordinals.append(ordinal)
|
|
return ordinals
|
|
|
|
@staticmethod
|
|
def get_tinfo_by_ordinal(ordinal):
|
|
local_typestring = idc.GetLocalTinfo(ordinal)
|
|
if local_typestring:
|
|
p_type, fields = local_typestring
|
|
local_tinfo = idaapi.tinfo_t()
|
|
local_tinfo.deserialize(idaapi.cvar.idati, p_type, fields)
|
|
return local_tinfo
|
|
return None
|
|
|
|
def initialize_nodes(self):
|
|
for ordinal in xrange(1, idc.GetMaxLocalType()):
|
|
# if ordinal == 15:
|
|
# import pydevd
|
|
# pydevd.settrace("localhost", port=12345, stdoutToServer=True, stderrToServer=True)
|
|
|
|
local_tinfo = StructureGraph.get_tinfo_by_ordinal(ordinal)
|
|
if not local_tinfo:
|
|
return
|
|
name = idc.GetLocalTypeName(ordinal)
|
|
|
|
if local_tinfo.is_typeref():
|
|
typeref_ordinal = local_tinfo.get_ordinal()
|
|
members_ordinals = []
|
|
if typeref_ordinal:
|
|
typeref_tinfo = StructureGraph.get_tinfo_by_ordinal(typeref_ordinal)
|
|
if typeref_tinfo.is_typeref() or typeref_tinfo.is_udt() or typeref_tinfo.is_ptr():
|
|
members_ordinals = [typeref_ordinal]
|
|
cdecl_typedef = idaapi.print_tinfo(None, 4, 5, 0x3, local_tinfo, None, None)
|
|
self.local_types[ordinal] = LocalType(name, members_ordinals, cdecl_typedef, is_typedef=True)
|
|
elif local_tinfo.is_udt():
|
|
# udt_data = idaapi.udt_type_data_t()
|
|
# local_tinfo.get_udt_details(udt_data)
|
|
members_ordinals = StructureGraph.get_members_ordinals(local_tinfo)
|
|
cdecl_typedef = idaapi.print_tinfo(None, 4, 5, 0x1, local_tinfo, None, None)
|
|
self.local_types[ordinal] = LocalType(name, members_ordinals, cdecl_typedef, is_union=local_tinfo.is_union())
|
|
elif local_tinfo.is_ptr():
|
|
typeref_ordinal = StructureGraph.get_ordinal(local_tinfo)
|
|
members_ordinals = [typeref_ordinal] if typeref_ordinal else []
|
|
cdecl_typedef = idaapi.print_tinfo(None, 4, 5, 0x2, local_tinfo, None, None)
|
|
self.local_types[ordinal] = LocalType(
|
|
name,
|
|
members_ordinals,
|
|
cdecl_typedef + ' *',
|
|
is_typedef=True
|
|
)
|
|
elif local_tinfo.is_enum():
|
|
cdecl_typedef = idaapi.print_tinfo(None, 4, 5, 0x21, local_tinfo, None, None)
|
|
self.local_types[ordinal] = LocalType(name, [], cdecl_typedef, is_enum=True)
|
|
|
|
self.ordinal_list = set(self.ordinal_list).intersection(self.local_types)
|
|
for ordinal in self.ordinal_list:
|
|
self.local_types[ordinal].is_selected = True
|
|
|
|
def calculate_edges(self):
|
|
for first in self.local_types.keys():
|
|
for second in self.local_types[first].members_ordinals:
|
|
self.edges.append((first, second))
|
|
|
|
self.downward_edges = {key: [] for key in self.local_types.keys()}
|
|
self.upward_edges = {key: [] for key in self.local_types.keys()}
|
|
|
|
for key, value in self.edges:
|
|
self.downward_edges[key].append(value)
|
|
self.upward_edges[value].append(key)
|
|
|
|
def generate_final_edges_down(self, node):
|
|
if node not in self.visited_downward:
|
|
self.visited_downward.append(node)
|
|
else:
|
|
return
|
|
for next_node in self.downward_edges[node]:
|
|
self.final_edges.append((node, next_node))
|
|
for next_node in self.downward_edges[node]:
|
|
self.generate_final_edges_down(next_node)
|
|
|
|
def generate_final_edges_up(self, node):
|
|
if node not in self.visited_upward:
|
|
self.visited_upward.append(node)
|
|
else:
|
|
return
|
|
for next_node in self.upward_edges[node]:
|
|
self.final_edges.append((next_node, node))
|
|
for next_node in self.upward_edges[node]:
|
|
self.generate_final_edges_up(next_node)
|
|
|
|
def get_nodes(self):
|
|
for ordinal in self.ordinal_list:
|
|
if ordinal in self.local_types:
|
|
self.generate_final_edges_down(ordinal)
|
|
self.generate_final_edges_up(ordinal)
|
|
return set([node for nodes in self.final_edges for node in nodes])
|
|
|
|
def get_edges(self):
|
|
return self.final_edges
|