Queue: skip the compiler's at-exit destructor thunks (mov ecx, global; jmp dtor)

This commit is contained in:
KeelrLeek committed 2026-10-05 14:46:31 -05:00
1 parent 3f32d0eb3e
commit d2c365d531
1 file changed
+13
+13
View File
@@ -32,6 +32,9 @@ class FunctionQueue:
self.r = Reverse(self.config) self.r = Reverse(self.config)
self.cap = int(self.config.get("attempt_cap", 2)) self.cap = int(self.config.get("attempt_cap", 2))
self.min_size = int(self.config.get("queue_min_size", 8)) self.min_size = int(self.config.get("queue_min_size", 8))
# [[lo, hi, "label"], ...] ranked low, e.g. the compiler-generated static initializers at the end of .text
self.low_priority = [(int(str(lo), 0), int(str(hi), 0), label)
for lo, hi, label in self.config.get("low_priority_ranges", [])]
# ------------------------------------------------------------------ records # ------------------------------------------------------------------ records
def statuses(self): def statuses(self):
@@ -139,6 +142,12 @@ class FunctionQueue:
if self._category(addr) not in ("game", "unsorted"): if self._category(addr) not in ("game", "unsorted"):
score *= 0.6 score *= 0.6
score *= 0.5 ** rejected.get(addr, 0) score *= 0.5 ** rejected.get(addr, 0)
low = next((label for lo, hi, label in self.low_priority if lo <= addr < hi), None)
if low:
score *= 0.2 # e.g. the compiler's static initializers
reasons_low = [low]
else:
reasons_low = []
if addr in similar_readable: if addr in similar_readable:
score *= 1.5 # a readable near-duplicate to start from score *= 1.5 # a readable near-duplicate to start from
reasons = [f"{size} bytes", f"{round(named_share * 100)}% of {len(calls)} callees named"] reasons = [f"{size} bytes", f"{round(named_share * 100)}% of {len(calls)} callees named"]
@@ -148,6 +157,7 @@ class FunctionQueue:
reasons.append(f"rejected {rejected[addr]}x") reasons.append(f"rejected {rejected[addr]}x")
if addr in similar_readable: if addr in similar_readable:
reasons.append("has a readable near-duplicate") reasons.append("has a readable near-duplicate")
reasons += reasons_low
return score, reasons return score, reasons
def next_functions(self, agent, n=10, similar_readable=frozenset()): def next_functions(self, agent, n=10, similar_readable=frozenset()):
@@ -173,6 +183,9 @@ class FunctionQueue:
re.match(r"(nullsub|thunk)_", self.r.name_of(addr) or "") or \ re.match(r"(nullsub|thunk)_", self.r.name_of(addr) or "") or \
re.match(r"thunk_", (statuses.get(addr) or (None, ""))[1].split("_", 1)[-1]): re.match(r"thunk_", (statuses.get(addr) or (None, ""))[1].split("_", 1)[-1]):
continue # stubs and thunks are named in bulk, not decompiled continue # stubs and thunks are named in bulk, not decompiled
head = self.r.read(addr, 10) if int(facts[addr].get("size") or 0) == 10 else b""
if head[:1] and 0xB8 <= head[0] <= 0xBF and head[5:6] == b"\xe9":
continue # mov reg, imm32; jmp: an at-exit destructor thunk or an SEH handler stub (compiler's)
score, reasons = self.score(addr, facts, named, rejected, similar_readable) score, reasons = self.score(addr, facts, named, rejected, similar_readable)
ranked.append((score, addr, reasons)) ranked.append((score, addr, reasons))
ranked.sort(reverse=True) ranked.sort(reverse=True)