gdb scripts

This commit is contained in:
IQuant 2025-11-16 19:45:01 +03:00
parent 787b8f4e1f
commit 749439a92c
3 changed files with 101 additions and 3 deletions

3
scripts/.gitignore vendored
View file

@ -1 +1,2 @@
__pycache__
__pycache__
gdb_data/

View file

@ -1,4 +1,5 @@
import gdb
import json
patches = dict()
@ -6,7 +7,7 @@ class PatchNop(gdb.Command):
def __init__ (self):
super().__init__ ("patch-nop", gdb.COMMAND_USER)
def invoke (self, arg, from_tty):
def invoke(self, arg, from_tty):
addr = int(arg, base=0)
if addr in patches:
print("Already patched")
@ -24,13 +25,90 @@ class PatchRevert(gdb.Command):
def __init__ (self):
super().__init__ ("patch-revert", gdb.COMMAND_USER)
def invoke (self, arg, from_tty):
def invoke(self, arg, from_tty):
inferior = gdb.selected_inferior()
for addr, mem in patches.items():
print("Restoring", hex(addr))
inferior.write_memory(addr, mem)
patches.clear()
_vtables_cache = None
def get_vtables():
global _vtables_cache
if _vtables_cache is None:
print("Loading VTables")
_vtables_cache = {}
for k, v in json.load(open("gdb_data/vtables.json")).items():
_vtables_cache[int(k)] = v
return _vtables_cache
class MemReader:
def __init__(self):
self.inferior = gdb.selected_inferior()
def read_uint(self, addr: int):
try:
return int.from_bytes(self.inferior.read_memory(addr, 4), byteorder="little", signed=False)
except gdb.MemoryError:
return None
class ValueIdentifier:
def __init__(self, addr: int):
self.addr = addr
self.mem = MemReader()
self.vtables = get_vtables()
self.type = None
self.name = None
self.identify()
def identify(self):
if self.addr == 0:
self.type = "null"
return
if self.addr in self.vtables:
self.type = "pointer to vtable"
self.name = self.vtables[self.addr]
return
val = self.mem.read_uint(self.addr)
if val is None:
self.type = "unreadable pointer"
else:
#print(f"Checking if {hex(val)} is a vtable")
if val in self.vtables:
self.type = "pointer to value of type"
self.name = self.vtables[val]
return
class Identify(gdb.Command):
def __init__ (self):
super().__init__ ("identify", gdb.COMMAND_USER)
def invoke(self, arg, from_tty):
addr = int(arg, base=0)
vi = ValueIdentifier(addr)
print(vi.type, vi.name)
class Layout(gdb.Command):
def __init__ (self):
super().__init__ ("layout", gdb.COMMAND_USER)
def invoke(self, arg, from_tty):
splt = arg.split()
addr = int(splt[0], base=0)
amount = 1024
if len(splt) > 1:
amount = int(splt[1])
mem = MemReader()
for i in range(amount):
p = mem.read_uint(addr+i*4)
if p is not None:
vi = ValueIdentifier(p)
if vi.type is not None and vi.type != "null" and vi.type != "unreadable pointer":
print(f"Field {hex(i*4)} ({hex(addr+i*4)}, {hex(p)})", vi.type, vi.name)
PatchNop()
PatchRevert()
Identify()
Layout()

View file

@ -0,0 +1,19 @@
import xml.etree.ElementTree as ET
import os
import json
base_path = "scripts/gdb_data/"
os.makedirs(base_path, exist_ok=True)
source_path = "/home/quant/noita.exe.xml"
tree = ET.parse(source_path)
root = tree.getroot()
vtables = dict()
for symbol in root.find('SYMBOL_TABLE'):
addr = int(symbol.attrib["ADDRESS"], base=16)
if symbol.attrib["NAME"] == "vftable":
vtables[addr] = symbol.attrib["NAMESPACE"]
json.dump(vtables, open(base_path+"vtables.json", "w"))