Jelajahi Sumber

Prune functions not associated with a virtual class

nosoop 10 bulan lalu
induk
melakukan
baa9a1bd9f
1 mengubah file dengan 20 tambahan dan 2 penghapusan
  1. 20 2
      src/smgdc/angr/vtable_disamb.py

+ 20 - 2
src/smgdc/angr/vtable_disamb.py

@@ -33,6 +33,10 @@ class VtableDisambiguator(angr.Analysis):
     subclass_map: dict[Symbol, set[Symbol]]
     superclass_map: dict[Symbol, set[Symbol]]
 
+    # we use this to test if a function belongs to a class with a vtable
+    # this way we can prune static functions from the candidate pool
+    vtable_instances: set[demangler.Node]
+
     def __init__(self):
         self.loader = self.project.loader
         self.memory = self.loader.memory
@@ -41,10 +45,14 @@ class VtableDisambiguator(angr.Analysis):
     def analyze(self) -> None:
         self.syms_by_addr = collections.defaultdict(set)
         vtable_syms = set()
+        self.vtable_instances = set()
         for symbol in self.loader.symbols:
             self.syms_by_addr[symbol.rebased_addr].add(symbol)
-            if symbol.name.startswith("_ZTV"):
+            if symbol.name.startswith("_ZTV") and not symbol.name.startswith("_ZTVZ"):
                 vtable_syms.add(symbol)
+                self.vtable_instances.add(
+                    dh.extract_vtable_typename(demangler.parse(symbol.name))
+                )
 
         # we associate a type with their subclasses so we can check them to disambiguate duplicates on the base
         self.subclass_map = collections.defaultdict(set)
@@ -109,13 +117,23 @@ class VtableDisambiguator(angr.Analysis):
         for fnsym in ambig_fnsyms:
             funcsig_set.add(dh.extract_method_signature(demangler.parse(fnsym.name)))
 
+        non_class_syms = set()
+        for sym in ambig_fnsyms:
+            fnname = dh.extract_function_name(demangler.parse(sym.name))
+            if not any(vtname == fnname[: len(vtname)] for vtname in self.vtable_instances):
+                non_class_syms.add(sym)
+
+        if len(ambig_fnsyms - non_class_syms) == 1:
+            # all but one of the ambiguous symbols are not potential virtual class methods
+            return (ambig_fnsyms - non_class_syms).pop()
+
         if len(funcsig_set) == 1:
             # we only have one name-signature combination here
             return set(ambig_fnsyms).pop()
 
         rebased_fnsym_addrs = set(fnsym.rebased_addr for fnsym in ambig_fnsyms)
 
-        for fnsym in ambig_fnsyms:
+        for fnsym in ambig_fnsyms - non_class_syms:
             funcsig = dh.extract_method_signature(demangler.parse(fnsym.name))
             for svt in related_vtsyms:
                 # only check functions at the same index