@@ -44,6 +44,7 @@ def strip(name):
4444
4545
4646class RTTITypeDescriptor (RTTIStruc ):
47+
4748 # create structure
4849 msid = idc .get_struc_id ("RTTITypeDescriptor" )
4950 if msid != ida_idaapi .BADADDR :
@@ -98,7 +99,61 @@ def __init__(self, ea):
9899 return
99100
100101
102+ class RTTIClassHierarchyDescriptor (RTTIStruc ):
103+
104+ CHD_MULTINH = 0x01 # Multiple inheritance
105+ CHD_VIRTINH = 0x02 # Virtual inheritance
106+ CHD_AMBIGUOUS = 0x04 # Ambiguous inheritance
107+
108+ # create structure
109+ msid = idc .get_struc_id ("RTTIClassHierarchyDescriptor" )
110+ if msid != ida_idaapi .BADADDR :
111+ idc .del_struc (msid )
112+ msid = idc .add_struc (0xFFFFFFFF , "RTTIClassHierarchyDescriptor" , False )
113+
114+ # add members
115+ idc .add_struc_member (msid , "signature" , ida_idaapi .BADADDR , ida_bytes .FF_DWORD | ida_bytes .FF_DATA , - 1 , 4 )
116+ idc .add_struc_member (msid , "attribute" , ida_idaapi .BADADDR , ida_bytes .FF_DWORD | ida_bytes .FF_DATA , - 1 , 4 )
117+ idc .add_struc_member (msid , "numBaseClasses" , ida_idaapi .BADADDR , ida_bytes .FF_DWORD | ida_bytes .FF_DATA , - 1 , 4 )
118+ idc .add_struc_member (msid , "pBaseClassArray" , ida_idaapi .BADADDR , ida_bytes .FF_DWORD | ida_bytes .FF_DATA , - 1 , 4 ) # for dummy. the correct type will be applied when the BCA class is created.
119+
120+ # get structure related info
121+ tid = msid
122+ struc = get_struc (tid )
123+ size = idc .get_struc_size (tid )
124+ print ("Completed Registering RTTIClassHierarchyDescriptor" )
125+
126+ def __init__ (self , ea ):
127+ self .ea = ea
128+ self .sig = 0
129+ self .bcaea = ida_idaapi .BADADDR
130+ self .nb_classes = 0
131+ self .flags = ""
132+ self .bca = None
133+
134+ # apply structure type to bytes
135+ ida_bytes .del_items (ea , ida_bytes .DELIT_DELNAMES , self .size )
136+ if ida_bytes .create_struct (ea , self .size , self .tid ):
137+ # Get members of CHD
138+ self .sig = ida_bytes .get_32bit (ea + u .get_moff_by_name (self .struc , "signature" ))
139+ self .bcaea = ida_bytes .get_32bit (ea + u .get_moff_by_name (self .struc , "pBaseClassArray" )) + u .x64_imagebase ()
140+ self .nb_classes = ida_bytes .get_32bit (ea + u .get_moff_by_name (self .struc , "numBaseClasses" ))
141+ self .attribute = ida_bytes .get_32bit (ea + u .get_moff_by_name (self .struc , "attribute" ))
142+
143+ self .bca = RTTIBaseClassArray (self .bcaea , self .nb_classes )
144+
145+ # parse flags
146+ if self .attribute & self .CHD_MULTINH :
147+ self .flags += "M"
148+ if self .attribute & self .CHD_VIRTINH :
149+ self .flags += "V"
150+ if self .attribute & self .CHD_AMBIGUOUS :
151+ self .flags += "A"
152+ #self.flags += " {:#x}".format(self.attribute)
153+
154+
101155class RTTIBaseClassDescriptor (RTTIStruc ):
156+
102157 BCD_NOTVISIBLE = 0x00000001
103158 BCD_AMBIGUOUS = 0x00000002
104159 BCD_PRIVORPROTBASE = 0x00000004
@@ -114,13 +169,13 @@ class RTTIBaseClassDescriptor(RTTIStruc):
114169 msid = idc .add_struc (0xFFFFFFFF , "RTTIBaseClassDescriptor" , False )
115170
116171 # add members
117- u .add_ptr_or_rva_member (msid , "pTypeDescriptor" )
172+ u .add_ptr_or_rva_member (msid , "pTypeDescriptor" , "RTTITypeDescriptor" )
118173 idc .add_struc_member (msid , "numContainerBases" , ida_idaapi .BADADDR , ida_bytes .FF_DWORD | ida_bytes .FF_DATA , - 1 , 4 )
119174 idc .add_struc_member (msid , "mdisp" , ida_idaapi .BADADDR , ida_bytes .FF_DATA | ida_bytes .FF_DWORD , - 1 , 4 ) # 00 PMD Vftable displacement inside class layout
120175 idc .add_struc_member (msid , "pdisp" , ida_idaapi .BADADDR , ida_bytes .FF_DATA | ida_bytes .FF_DWORD , - 1 , 4 ) # 04 PMD Vbtable displacement
121176 idc .add_struc_member (msid , "vdisp" , ida_idaapi .BADADDR , ida_bytes .FF_DATA | ida_bytes .FF_DWORD , - 1 , 4 ) # 08 PMD Vftable displacement inside vbtable
122177 idc .add_struc_member (msid , "attributes" , ida_idaapi .BADADDR , ida_bytes .FF_DWORD | ida_bytes .FF_DATA , - 1 , 4 )
123- u .add_ptr_or_rva_member (msid , "pClassDescriptor" )
178+ u .add_ptr_or_rva_member (msid , "pClassDescriptor" , "RTTIClassHierarchyDescriptor" )
124179
125180 # get structure related info
126181 tid = msid
@@ -140,74 +195,57 @@ def __init__(self, ea):
140195 self .pdisp = u .to_signed32 (ida_bytes .get_32bit (ea + u .get_moff_by_name (self .struc , "pdisp" )))
141196 self .vdisp = u .to_signed32 (ida_bytes .get_32bit (ea + u .get_moff_by_name (self .struc , "vdisp" )))
142197 self .attributes = ida_bytes .get_32bit (ea + u .get_moff_by_name (self .struc , "attributes" ))
143- self .rcd = ida_bytes .get_32bit (ea + u .get_moff_by_name (self .struc , "pClassDescriptor" ))
198+ self .chdea = ida_bytes .get_32bit (ea + u .get_moff_by_name (self .struc , "pClassDescriptor" )) + u . x64_imagebase ( )
144199
145200
146- class RTTIClassHierarchyDescriptor (RTTIStruc ):
147- bases = None
148- CHD_MULTINH = 0x01 # Multiple inheritance
149- CHD_VIRTINH = 0x02 # Virtual inheritance
150- CHD_AMBIGUOUS = 0x04 # Ambiguous inheritance
201+ class RTTIBaseClassArray (RTTIStruc ):
151202
152203 # create structure
153- msid = idc .get_struc_id ("RTTIClassHierarchyDescriptor " )
204+ msid = idc .get_struc_id ("RTTIBaseClassArray " )
154205 if msid != ida_idaapi .BADADDR :
155206 idc .del_struc (msid )
156- msid = idc .add_struc (0xFFFFFFFF , "RTTIClassHierarchyDescriptor " , False )
207+ msid = idc .add_struc (0xFFFFFFFF , "RTTIBaseClassArray " , False )
157208
158209 # add members
159- idc .add_struc_member (msid , "signature" , ida_idaapi .BADADDR , ida_bytes .FF_DWORD | ida_bytes .FF_DATA , - 1 , 4 )
160- idc .add_struc_member (msid , "attribute" , ida_idaapi .BADADDR , ida_bytes .FF_DWORD | ida_bytes .FF_DATA , - 1 , 4 )
161- idc .add_struc_member (msid , "numBaseClasses" , ida_idaapi .BADADDR , ida_bytes .FF_DWORD | ida_bytes .FF_DATA , - 1 , 4 )
162- u .add_ptr_or_rva_member (msid , "pBaseClassArray" )
210+ u .add_ptr_or_rva_member (msid , "arrayOfBaseClassDescriptors" , "RTTIBaseClassDescriptor" , array = True )
163211
164212 # get structure related info
165213 tid = msid
166214 struc = get_struc (tid )
167215 size = idc .get_struc_size (tid )
168- print ("Completed Registering RTTIClassHierarchyDescriptor" )
216+
217+ # correct BCA's pBaseClassArray member type here.
218+ u .set_ptr_or_rva_member (RTTIClassHierarchyDescriptor .tid , "pBaseClassArray" , "RTTIBaseClassArray" )
219+
220+ print ("Completed Registering RTTIBaseClassArray" )
169221
170- def __init__ (self , ea ):
222+ def __init__ (self , ea , nb_classes ):
171223 self .ea = ea
172- self .sig = 0
173- self .bcaea = ida_idaapi .BADADDR
174- self .nb_classes = 0
175- self .flags = ""
224+ # fix the size with the actual size by using nb_classes from CHD since the size depends on each BCA
225+ self .size = 4 * nb_classes
226+
176227 self .bases = []
177228 self .paths = {}
178229 self .depth = 0
179230
180231 # apply structure type to bytes
181232 ida_bytes .del_items (ea , ida_bytes .DELIT_DELNAMES , self .size )
182233 if ida_bytes .create_struct (ea , self .size , self .tid ):
183- # Get members of CHD
184- self .sig = ida_bytes .get_32bit (ea + u .get_moff_by_name (self .struc , "signature" ))
185- self .bcaea = ida_bytes .get_32bit (ea + u .get_moff_by_name (self .struc , "pBaseClassArray" )) + u .x64_imagebase ()
186- self .nb_classes = ida_bytes .get_32bit (ea + u .get_moff_by_name (self .struc , "numBaseClasses" ))
187- self .attribute = ida_bytes .get_32bit (ea + u .get_moff_by_name (self .struc , "attribute" ))
188-
189- # parse flags
190- if self .attribute & self .CHD_MULTINH :
191- self .flags += "M"
192- if self .attribute & self .CHD_VIRTINH :
193- self .flags += "V"
194- if self .attribute & self .CHD_AMBIGUOUS :
195- self .flags += "A"
196- #self.flags += " {:#x}".format(self.attribute)
197-
198- def parse_bca (self , ea ):
234+ pass
235+
236+ def parse_bca (self , ea , nb_classes ):
199237 result_paths = {}
200238 curr_path = []
201239 n_processed = {}
202- for i in range (0 , self . nb_classes ):
203- bcdoff = self . bcaea + i * 4
240+ for i in range (0 , nb_classes ):
241+ bcdoff = ea + i * 4
204242
205243 # apply data type to items in BCA
206- ida_bytes .create_dword (bcdoff , 4 )
207- if u .x64 :
208- ida_offset .op_offset (bcdoff , ida_bytes .OPND_MASK , u .REF_OFF | ida_nalt .REFINFO_RVAOFF , - 1 , 0 , 0 )
209- else :
210- ida_offset .op_offset (bcdoff , ida_bytes .OPND_MASK , u .REF_OFF , - 1 , 0 , 0 )
244+ # ida_bytes.create_dword(bcdoff, 4)
245+ # if u.x64:
246+ # ida_offset.op_offset(bcdoff, ida_bytes.OPND_MASK, u.REF_OFF|ida_nalt.REFINFO_RVAOFF, -1, 0, 0)
247+ # else:
248+ # ida_offset.op_offset(bcdoff, ida_bytes.OPND_MASK, u.REF_OFF, -1, 0, 0)
211249
212250 # get relevant structures
213251 bcdea = ida_bytes .get_32bit (bcdoff ) + u .x64_imagebase ()
@@ -258,7 +296,7 @@ def parse_bca(self, ea):
258296
259297 #print({x:[[z.name for z in y] for y in result_paths[x]] for x in result_paths})
260298 self .paths = result_paths
261-
299+
262300
263301class RTTICompleteObjectLocator (RTTIStruc ):
264302
@@ -272,10 +310,11 @@ class RTTICompleteObjectLocator(RTTIStruc):
272310 idc .add_struc_member (msid , "signature" , ida_idaapi .BADADDR , ida_bytes .FF_DATA | ida_bytes .FF_DWORD , - 1 , 4 )
273311 idc .add_struc_member (msid , "offset" , ida_idaapi .BADADDR , ida_bytes .FF_DATA | ida_bytes .FF_DWORD , - 1 , 4 )
274312 idc .add_struc_member (msid , "cdOffset" , ida_idaapi .BADADDR , ida_bytes .FF_DATA | ida_bytes .FF_DWORD , - 1 , 4 )
275- u .add_ptr_or_rva_member (msid , "pTypeDescriptor" )
276- u .add_ptr_or_rva_member (msid , "pClassDescriptor" )
313+ u .add_ptr_or_rva_member (msid , "pTypeDescriptor" , "RTTITypeDescriptor" )
314+ u .add_ptr_or_rva_member (msid , "pClassDescriptor" , "RTTIClassHierarchyDescriptor" )
277315 if u .x64 :
278- idc .add_struc_member (msid , "pSelf" , ida_idaapi .BADADDR , ida_bytes .FF_DATA | ida_bytes .FF_DWORD | ida_bytes .FF_0OFF , u .mt_rva ().tid , 4 , reftype = ida_nalt .REFINFO_RVAOFF | u .REF_OFF )
316+ u .add_ptr_or_rva_member (msid , "pSelf" , "RTTICompleteObjectLocator" )
317+
279318
280319 # get structure related info
281320 tid = msid
@@ -353,7 +392,7 @@ def parse_msvc_vftable():
353392 if len ([xrea for xrea in u .get_refs_to (RTTIClassHierarchyDescriptor .tid )]) == 0 :
354393 [ida_bytes .create_struct (result [x ].chd .ea , RTTIClassHierarchyDescriptor .size , RTTIClassHierarchyDescriptor .tid , True ) for x in result ]
355394 if len ([xrea for xrea in u .get_refs_to (RTTITypeDescriptor .tid )]) == 0 :
356- [ida_bytes .create_struct (result [x ].td .ea , RTTITypeDescriptor .size , RTTITypeDescriptor .tid , True ) for x in result ]
395+ [ida_bytes .create_struct (result [x ].td .ea , result [ x ]. td .size , RTTITypeDescriptor .tid , True ) for x in result ]
357396
358397 # for refreshing xrefs to get xrefs from COLs to TDs
359398 ida_auto .auto_wait ()
@@ -363,8 +402,16 @@ def parse_msvc_vftable():
363402 col = result [vtable ]
364403
365404 # get BCDs
366- for bcd , depth in col .chd .parse_bca (col .chd .bcaea ):
405+ for bcd , depth in col .chd .bca . parse_bca (col .chd .bca . ea , col . chd . nb_classes ):
367406 pass
407+
408+ # may be this is a bug on IDA.
409+ # ida fails to apply a structure type to bytes under some conditions, although create_struct returns True.
410+ # to avoid that, apply them again.
411+ ida_auto .auto_wait ()
412+ if len ([xrea for xrea in u .get_refs_to (RTTIBaseClassArray .tid )]) == 0 :
413+ [ida_bytes .create_struct (result [x ].chd .bca .ea , result [x ].chd .bca .size , RTTIBaseClassArray .tid , True ) for x in result ]
414+ ida_auto .auto_wait ()
368415
369416 return result
370417
@@ -377,8 +424,8 @@ def display_result(result):
377424 print (" CHD at {:#x}:" .format (col .chd .ea ), hex (col .chd .sig ), hex (col .chd .bcaea ), col .chd .nb_classes , col .chd .flags )
378425
379426 # get BCDs
380- for bcd in col .chd .bases :
381- print (" {}BCD at {:#x}:" .format (" " * bcd .depth * 2 , bcd .ea ), bcd .name , bcd .nb_cbs , bcd .mdisp , bcd .pdisp , bcd .vdisp , bcd .attributes )
427+ for bcd in col .chd .bca . bases :
428+ print (" {}BCD at {:#x}:" .format (" " * bcd .depth * 2 , bcd .ea ), bcd .name , bcd .nb_cbs , bcd .mdisp , bcd .pdisp , bcd .vdisp , bcd .attributes , hex ( bcd . chdea ) )
382429
383430
384431def run_pci (icon = - 1 ):
0 commit comments