|  | @@ -49,7 +49,7 @@ def get_windows_vtables_from(bin: "LinuxBinary", vt: Symbol) -> VTable:
 | 
											
												
													
														|  |      vtda = bin.vtable_disambiguator
 |  |      vtda = bin.vtable_disambiguator
 | 
											
												
													
														|  |      vt_typeinfo = bin.angr.loader.memory.unpack_word(vt.rebased_addr + 0x4)
 |  |      vt_typeinfo = bin.angr.loader.memory.unpack_word(vt.rebased_addr + 0x4)
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -    vt_parent_spans = [1]
 |  | 
 | 
											
												
													
														|  | 
 |  | +    vt_parent_spans = [0]
 | 
											
												
													
														|  |      for typeinfo_ptr, name in reversed(list(vtda.dump_class_parents(vt_typeinfo))):
 |  |      for typeinfo_ptr, name in reversed(list(vtda.dump_class_parents(vt_typeinfo))):
 | 
											
												
													
														|  |          vt_parent = bin.angr.loader.find_symbol(f"_ZTV{name}")
 |  |          vt_parent = bin.angr.loader.find_symbol(f"_ZTV{name}")
 | 
											
												
													
														|  |          if not vt_parent:
 |  |          if not vt_parent:
 | 
											
										
											
												
													
														|  | @@ -80,7 +80,10 @@ def get_windows_vtables_from(bin: "LinuxBinary", vt: Symbol) -> VTable:
 | 
											
												
													
														|  |              # filter MI thunks
 |  |              # filter MI thunks
 | 
											
												
													
														|  |              dmsym = demangler.parse(sym.name)
 |  |              dmsym = demangler.parse(sym.name)
 | 
											
												
													
														|  |              if dmsym:
 |  |              if dmsym:
 | 
											
												
													
														|  | -                if (
 |  | 
 | 
											
												
													
														|  | 
 |  | +                # MSVC only provides one dtor, so here we'll use the deleting one (D0)
 | 
											
												
													
														|  | 
 |  | +                if dh.is_dtor(dmsym) and dh.get_dtor_type(dmsym) != "deleting":
 | 
											
												
													
														|  | 
 |  | +                    continue
 | 
											
												
													
														|  | 
 |  | +                elif (
 | 
											
												
													
														|  |                      not demangler.is_ctor_or_dtor(dmsym)
 |  |                      not demangler.is_ctor_or_dtor(dmsym)
 | 
											
												
													
														|  |                      and dh.extract_method_signature(dmsym) in thunk_fns
 |  |                      and dh.extract_method_signature(dmsym) in thunk_fns
 | 
											
												
													
														|  |                  ):
 |  |                  ):
 | 
											
										
											
												
													
														|  | @@ -124,11 +127,22 @@ def get_vtables_from_address(bin: "LinuxBinary", vt: Symbol) -> list[VTable]:
 | 
											
												
													
														|  |              # get symbols that map to that address
 |  |              # get symbols that map to that address
 | 
											
												
													
														|  |              if vptr == 0:
 |  |              if vptr == 0:
 | 
											
												
													
														|  |                  # HACK: some virtual destructors got optimized out and are represented by nullptrs
 |  |                  # HACK: some virtual destructors got optimized out and are represented by nullptrs
 | 
											
												
													
														|  | -                # TODO: it might be better to pull destructors from the parent
 |  | 
 | 
											
												
													
														|  | -                call_unexpected = bin.angr.loader.find_symbol("__cxa_call_unexpected")
 |  | 
 | 
											
												
													
														|  | -                assert call_unexpected
 |  | 
 | 
											
												
													
														|  | -                function_list.append(VTableFunction(table_index, {call_unexpected}))
 |  | 
 | 
											
												
													
														|  | -                continue
 |  | 
 | 
											
												
													
														|  | 
 |  | +                for parent_vt in bin.vtable_disambiguator.superclass_map[vt]:
 | 
											
												
													
														|  | 
 |  | +                    # HACK: in that case we try to match functions from the parent
 | 
											
												
													
														|  | 
 |  | +                    vptr = (
 | 
											
												
													
														|  | 
 |  | +                        bin.angr.loader.fast_memory_load_pointer(
 | 
											
												
													
														|  | 
 |  | +                            parent_vt.rebased_addr + (0x4 * n) + 0x8
 | 
											
												
													
														|  | 
 |  | +                        )
 | 
											
												
													
														|  | 
 |  | +                        or 0
 | 
											
												
													
														|  | 
 |  | +                    )
 | 
											
												
													
														|  | 
 |  | +                    if vptr:
 | 
											
												
													
														|  | 
 |  | +                        break
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +                if vptr == 0:
 | 
											
												
													
														|  | 
 |  | +                    call_unexpected = bin.angr.loader.find_symbol("__cxa_call_unexpected")
 | 
											
												
													
														|  | 
 |  | +                    assert call_unexpected
 | 
											
												
													
														|  | 
 |  | +                    function_list.append(VTableFunction(table_index, {call_unexpected}))
 | 
											
												
													
														|  | 
 |  | +                    continue
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |              fnsyms = set(vtda.syms_by_addr.get(vptr) or set()) if vptr else set()
 |  |              fnsyms = set(vtda.syms_by_addr.get(vptr) or set()) if vptr else set()
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -160,11 +174,7 @@ def get_vtables_from_address(bin: "LinuxBinary", vt: Symbol) -> list[VTable]:
 | 
											
												
													
														|  |              function_list.append(VTableFunction(table_index, fnsyms))
 |  |              function_list.append(VTableFunction(table_index, fnsyms))
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      for n, vfn in enumerate(function_list):
 |  |      for n, vfn in enumerate(function_list):
 | 
											
												
													
														|  | -        if n == 0:
 |  | 
 | 
											
												
													
														|  | -            # HACK: skip duplicated references to destructor
 |  | 
 | 
											
												
													
														|  | -            # we should be doing this at the disambiguation stage
 |  | 
 | 
											
												
													
														|  | -            continue
 |  | 
 | 
											
												
													
														|  | -        elif len(vfn.possible_syms) == 1:
 |  | 
 | 
											
												
													
														|  | 
 |  | +        if len(vfn.possible_syms) == 1:
 | 
											
												
													
														|  |              continue
 |  |              continue
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |          remaining_syms = vfn.possible_syms - disambiguated_functions
 |  |          remaining_syms = vfn.possible_syms - disambiguated_functions
 |