@@ -30,21 +30,25 @@ def __init__(self, bv: BinaryView, delphi_version: int, address: int):
3030 self ._class_name = ''
3131 self ._instance_size = 0
3232 self ._parent_vmt = 0
33+ self ._table_list : Mapping [int , str ] = {}
3334 self ._virtual_methods : Mapping [int , str ] = {}
3435
3536 if not self ._check_self_ptr ():
3637 return
3738
38- if not self ._parse_name ():
39+ if not self ._resolve_name ():
3940 return
4041
41- if not self ._parse_instance_size ():
42+ if not self ._resolve_instance_size ():
4243 return
4344
44- if not self ._parse_parent_vmt ():
45+ if not self ._resolve_parent_vmt ():
4546 return
4647
47- if not self ._parse_virtual_methods ():
48+ if not self ._resolve_table_list ():
49+ return
50+
51+ if not self ._resolve_virtual_methods ():
4852 return
4953
5054 self ._is_valid = True
@@ -57,7 +61,9 @@ def __repr__(self):
5761 def __str__ (self ):
5862 if not self ._is_valid :
5963 return f'<InvalidVmt address=0x{ self ._vmt_address :08X} >'
60- return f'<{ self ._class_name } start=0x{ self .start :08X} instance_size=0x{ self ._instance_size :X} >'
64+
65+ return (f'<{ self ._class_name } start=0x{ self .start :08X} '
66+ f'instance_size=0x{ self ._instance_size :X} >' )
6167
6268
6369 ## Properties
@@ -82,6 +88,10 @@ def instance_size(self) -> int:
8288 def parent_vmt (self ) -> int :
8389 return self ._parent_vmt
8490
91+ @property
92+ def table_list (self ) -> Mapping [int , str ]:
93+ return self ._table_list
94+
8595 @property
8696 def virtual_methods (self ) -> Mapping [int , str ]:
8797 return self ._virtual_methods
@@ -107,23 +117,23 @@ def br_offset(self) -> int:
107117 ## Public API
108118
109119 def seek_to_code (self , address : int ) -> bool :
110- if not self ._isValidCodeAdr (address ):
120+ if not self ._is_valid_code_addr (address ):
111121 return False
112122
113123 self ._br .seek (address )
114124 return True
115125
116126
117127 def seek_to_code_offset (self , offset : int ) -> bool :
118- if not self ._isValidCodeAdr (self ._code_section .start + offset ):
128+ if not self ._is_valid_code_addr (self ._code_section .start + offset ):
119129 return False
120130
121131 self ._br .seek (self ._code_section .start + offset )
122132 return True
123133
124134
125135 def seek_to_vmt_offset (self , offset : int ) -> bool :
126- if not self ._isValidCodeAdr (self ._vmt_address + offset ):
136+ if not self ._is_valid_code_addr (self ._vmt_address + offset ):
127137 return False
128138
129139 self ._br .seek (self ._vmt_address + offset )
@@ -148,7 +158,7 @@ def _check_self_ptr(self) -> bool:
148158 return self_ptr == self ._vmt_address
149159
150160
151- def _parse_name (self ) -> bool :
161+ def _resolve_name (self ) -> bool :
152162 class_name_addr = self ._get_class_name_addr ()
153163
154164 if class_name_addr is None :
@@ -172,23 +182,23 @@ def _parse_name(self) -> bool:
172182 return True
173183
174184
175- def _parse_instance_size (self ) -> bool :
185+ def _resolve_instance_size (self ) -> bool :
176186 if not self .seek_to_vmt_offset (self ._vmt_offsets .cVmtInstanceSize ):
177187 return False
178188
179189 self ._instance_size = self ._br .read32 ()
180190 return True
181191
182192
183- def _parse_parent_vmt (self ) -> bool :
193+ def _resolve_parent_vmt (self ) -> bool :
184194 if not self .seek_to_vmt_offset (self ._vmt_offsets .cVmtParent ):
185195 return False
186196
187197 self ._parent_vmt = self ._br .read32 ()
188198 return True
189199
190200
191- def _parse_virtual_methods (self ) -> bool :
201+ def _resolve_virtual_methods (self ) -> bool :
192202 class_name_addr = self ._get_class_name_addr ()
193203
194204 if class_name_addr is None :
@@ -197,7 +207,7 @@ def _parse_virtual_methods(self) -> bool:
197207 address_size = self ._bv .address_size
198208 offsets = self .vmt_offsets .__dict__ .items ()
199209 offset_map = {y :x for x , y in offsets }
200- tables_addr = self ._get_vmt_tables_addr ()
210+ tables_addr = self ._table_list . keys ()
201211
202212 if not self .seek_to_vmt_offset (self ._vmt_offsets .cVmtParent + address_size ):
203213 return False
@@ -208,7 +218,7 @@ def _parse_virtual_methods(self) -> bool:
208218 if field_value == 0 :
209219 continue
210220
211- if not self ._isValidCodeAdr (field_value ):
221+ if not self ._is_valid_code_addr (field_value ):
212222 prev_offset = self ._br .offset - address_size
213223 raise RuntimeError (f'Invalid code address deteted at 0x{ prev_offset :08X} '
214224 '({self.class_name})\n If you think it\' s a bug, please open an issue on '
@@ -227,7 +237,31 @@ def _parse_virtual_methods(self) -> bool:
227237 return True
228238
229239
230- def _isValidCodeAdr (self , addy : int , allow_null = False ) -> bool :
240+ def _resolve_table_list (self ) -> bool :
241+ if not self .seek_to_vmt_offset (self .vmt_offsets .cVmtIntfTable ):
242+ return False
243+
244+ offsets = self ._vmt_offsets .__dict__ .items ()
245+ offset_map = {y :x [4 :] for x , y in offsets }
246+
247+ stop_at = self ._vmt_address + self ._vmt_offsets .cVmtClassName
248+
249+ while self ._br .offset != stop_at :
250+ prev_br_offset = self ._br .offset
251+ address = self ._br .read32 ()
252+
253+ if address < 1 :
254+ continue
255+
256+ if not self ._is_valid_code_addr (address ):
257+ raise RuntimeError ('Invalid table address detected' )
258+
259+ self ._table_list [address ] = offset_map [prev_br_offset - self ._vmt_address ]
260+
261+ return True
262+
263+
264+ def _is_valid_code_addr (self , addy : int , allow_null = False ) -> bool :
231265 if addy == 0 :
232266 return allow_null
233267 return addy >= self ._code_section .start and addy < self ._code_section .end
@@ -239,34 +273,13 @@ def _get_class_name_addr(self) -> Union[None, int]:
239273
240274 class_name_addr = self ._br .read32 ()
241275
242- if not self ._isValidCodeAdr (class_name_addr ):
276+ if not self ._is_valid_code_addr (class_name_addr ):
243277 return None
244278
245279 return class_name_addr
246280
247281
248- def _get_vmt_tables_addr (self ) -> Union [None , List [int ]]:
249- if not self .seek_to_vmt_offset (self .vmt_offsets .cVmtIntfTable ):
250- return
251-
252- result = []
253- stop_at = self ._vmt_address + self .vmt_offsets .cVmtClassName
254-
255- while self ._br .offset != stop_at :
256- address = self ._br .read32 ()
257-
258- if address < 1 :
259- continue
260-
261- if not self ._isValidCodeAdr (address ):
262- raise RuntimeError ('Invalid table address detected' )
263-
264- result .append (address )
265-
266- return result
267-
268-
269- class ClassFinder (object ):
282+ class DelphiAnalyzer (object ):
270283 '''
271284 TODO: Doc
272285 '''
@@ -286,7 +299,6 @@ def __init__(self, bv: BinaryView, delphi_version: int):
286299 def delphi_version (self ) -> int :
287300 return self ._delphi_version
288301
289-
290302 @property
291303 def vmt_list (self ) -> List [DelphiVMT ]:
292304 return self ._vmt_list
0 commit comments