瀏覽代碼

Handle vtable nullptrs

nosoop 11 月之前
父節點
當前提交
581f2cde3e
共有 2 個文件被更改,包括 23 次插入4 次删除
  1. 14 3
      src/smgdc/angr/vtable_disamb.py
  2. 9 1
      src/smgdc/vtable.py

+ 14 - 3
src/smgdc/angr/vtable_disamb.py

@@ -190,11 +190,13 @@ class VtableDisambiguator(angr.Analysis):
 
         table_index = 0
         function_list: list[VTableFunction] = []
-        vtable_range = enumerate(
-            range(vtsym.rebased_addr + 0x4 * 2, vtsym.rebased_addr + vtsym.size, 4)
-        )
+
+        # we include the initial upcast offset and class typeinfo here
+        vtable_range = enumerate(range(vtsym.rebased_addr, vtsym.rebased_addr + vtsym.size, 4))
+
         for n, addr in vtable_range:
             # get symbols that map to that address
+            # NOTE: classes that don't implement virtual destructors have nullptrs
             deref = self.loader.fast_memory_load_pointer(addr)
             fnsyms = set(self.syms_by_addr.get(deref) or set()) if deref else set()
             if not fnsyms:
@@ -203,6 +205,15 @@ class VtableDisambiguator(angr.Analysis):
                 # functions are grouped correctly
                 table_index += 1
                 next(vtable_range)
+
+                for n1, addr1 in vtable_range:
+                    # consume any leading nullptrs (destructors that were optimized out)
+                    # this also consumes the next actual function pointer
+                    # we could probably get away with looking for it in the parent class...
+                    deref = self.loader.fast_memory_load_pointer(addr1)
+                    function_list.append(VTableFunction(table_index, deref))
+                    if deref != 0:
+                        break
                 continue
             function_list.append(VTableFunction(table_index, deref))
 

+ 9 - 1
src/smgdc/vtable.py

@@ -61,7 +61,7 @@ def get_windows_vtables_from(bin: "LinuxBinary", vt: Symbol) -> VTable:
     for vt_other in vt_others:
         for sym in vt_other:
             dmsym = demangler.parse(sym.name)
-            if dmsym.kind == "nonvirt_thunk":
+            if dmsym and dmsym.kind == "nonvirt_thunk":
                 thunk_fns.add(dh.extract_method_signature(dmsym))
 
     vt_out = []
@@ -114,6 +114,14 @@ def get_vtables_from_address(bin: "LinuxBinary", vt: Symbol) -> list[VTable]:
     for table_index, vptrs in enumerate(vptr_lists):
         for n, vptr in enumerate(vptrs):
             # get symbols that map to that address
+            if vptr == 0:
+                # 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
+
             fnsyms = set(vtda.syms_by_addr.get(vptr) or set()) if vptr else set()
 
             if len(fnsyms) == 1: