[scripts] Add debugging help for linked lists and GOT
Adding in scripts that i wrote to examine GOT/PLT/DYNAMIC in shared libs, as well as a GDB pretty-printer for util::linked_list.
This commit is contained in:
@@ -474,11 +474,39 @@ class HandleSetPrinter:
|
|||||||
return self._iterator(self.node_map['m_nodes'], self.capacity)
|
return self._iterator(self.node_map['m_nodes'], self.capacity)
|
||||||
|
|
||||||
|
|
||||||
|
class LinkedListPrinter:
|
||||||
|
def __init__(self, llist):
|
||||||
|
self.name = llist.type.tag
|
||||||
|
self.head = llist['m_head']
|
||||||
|
self.tail = llist['m_tail']
|
||||||
|
|
||||||
|
self.items = []
|
||||||
|
current = self.head
|
||||||
|
while current:
|
||||||
|
item = current.dereference()
|
||||||
|
self.items.append((str(len(self.items)), item))
|
||||||
|
current = item['m_next']
|
||||||
|
|
||||||
|
class _iterator:
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return f"{self.name}[{len(self.items)}]"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return self.items
|
||||||
|
|
||||||
|
|
||||||
def build_pretty_printers():
|
def build_pretty_printers():
|
||||||
pp = gdb.printing.RegexpCollectionPrettyPrinter("jsix")
|
pp = gdb.printing.RegexpCollectionPrettyPrinter("jsix")
|
||||||
pp.add_printer("cap table", '^cap_table$', CapTablePrinter)
|
pp.add_printer("cap table", '^cap_table$', CapTablePrinter)
|
||||||
pp.add_printer("handle set", '^util::node_set<unsigned long, 0, heap_allocated>$', HandleSetPrinter)
|
pp.add_printer("handle set", '^util::node_set<unsigned long, 0, heap_allocated>$', HandleSetPrinter)
|
||||||
pp.add_printer("vector", '^util::vector<.*>$', VectorPrinter)
|
pp.add_printer("vector", '^util::vector<.*>$', VectorPrinter)
|
||||||
|
pp.add_printer("linked list", '^util::linked_list<.*>$', LinkedListPrinter)
|
||||||
return pp
|
return pp
|
||||||
|
|
||||||
gdb.printing.register_pretty_printer(
|
gdb.printing.register_pretty_printer(
|
||||||
|
|||||||
@@ -5,3 +5,4 @@ pyyaml >= 5.4
|
|||||||
lark == 0.12.0
|
lark == 0.12.0
|
||||||
pure-cdb == 4
|
pure-cdb == 4
|
||||||
pyzstd == 0.15
|
pyzstd == 0.15
|
||||||
|
pyelftools
|
||||||
|
|||||||
124
scripts/print_got.py
Executable file
124
scripts/print_got.py
Executable file
@@ -0,0 +1,124 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
|
||||||
|
def section_header(name):
|
||||||
|
print()
|
||||||
|
print(name)
|
||||||
|
print("-" * 40)
|
||||||
|
|
||||||
|
|
||||||
|
def print_dyn(elf):
|
||||||
|
section = elf.get_section_by_name(".dynamic")
|
||||||
|
if section is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
section_header(".dynamic")
|
||||||
|
for tag in section.iter_tags():
|
||||||
|
print(tag)
|
||||||
|
|
||||||
|
|
||||||
|
def print_got(elf, name):
|
||||||
|
import struct
|
||||||
|
|
||||||
|
section = elf.get_section_by_name(name)
|
||||||
|
if section is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
section_header(name)
|
||||||
|
base_ip = section['sh_addr']
|
||||||
|
|
||||||
|
data = section.data()
|
||||||
|
n = section.data_size // 8
|
||||||
|
for i in range(n):
|
||||||
|
addr = struct.unpack_from("Q", data, i*8)[0]
|
||||||
|
print(f"[{i:2x}]: {base_ip+i*8:6x} {addr:16x}")
|
||||||
|
|
||||||
|
|
||||||
|
def print_plt(elf):
|
||||||
|
from iced_x86 import Decoder, Formatter, FormatterSyntax
|
||||||
|
|
||||||
|
section_header(".plt")
|
||||||
|
|
||||||
|
section = elf.get_section_by_name(".plt")
|
||||||
|
n = section.data_size // 16
|
||||||
|
data = section.data()
|
||||||
|
|
||||||
|
frm = Formatter(FormatterSyntax.NASM)
|
||||||
|
frm.digit_separator = "'"
|
||||||
|
frm.first_operand_char_index = 8
|
||||||
|
frm.hex_prefix = "0x"
|
||||||
|
frm.hex_suffix = ""
|
||||||
|
frm.leading_zeros = False
|
||||||
|
frm.rip_relative_addresses = False
|
||||||
|
frm.small_hex_numbers_in_decimal = False
|
||||||
|
frm.uppercase_hex = False
|
||||||
|
|
||||||
|
base_ip = section['sh_addr']
|
||||||
|
|
||||||
|
for i in range(n):
|
||||||
|
entry = data[ i*16 : (i+1)*16 ]
|
||||||
|
d = Decoder(64, entry, ip=base_ip + i*16)
|
||||||
|
|
||||||
|
indent = f"[{i:2x}]:"
|
||||||
|
for instr in d:
|
||||||
|
disasm = frm.format(instr)
|
||||||
|
print(f"{indent:6} {instr.ip:6x} {disasm}")
|
||||||
|
indent = ""
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
def print_gnu_hash(elf):
|
||||||
|
hash_section = elf.get_section_by_name(".gnu.hash")
|
||||||
|
data = hash_section.data()
|
||||||
|
|
||||||
|
import struct
|
||||||
|
(nbuckets, symoff, bloom_sz, bloom_sh) = struct.unpack_from("IIII", data, 0)
|
||||||
|
blooms = struct.unpack_from(f"{bloom_sz}Q", data, 16)
|
||||||
|
buckets = struct.unpack_from(f"{nbuckets}I", data, 16+(bloom_sz*8))
|
||||||
|
|
||||||
|
p = 16 + (bloom_sz*8) + (nbuckets*4)
|
||||||
|
n = (len(data) - p) // 4
|
||||||
|
chains = struct.unpack_from(f"{n}I", data, p)
|
||||||
|
|
||||||
|
section_header(".gnu.hash")
|
||||||
|
print(f" Bucket Count: {nbuckets}")
|
||||||
|
print(f"Symbol Offset: {symoff}")
|
||||||
|
print(f" Buckets: {buckets}")
|
||||||
|
|
||||||
|
print("\n Bloom words:")
|
||||||
|
for i in range(len(blooms)):
|
||||||
|
print(f" [{i:2}]: {blooms[i]:016x}")
|
||||||
|
|
||||||
|
print("\n Hashes:")
|
||||||
|
for i in range(len(chains)):
|
||||||
|
h = chains[i]
|
||||||
|
end = ""
|
||||||
|
if (h & 1) == 1:
|
||||||
|
end = "END"
|
||||||
|
bloom_idx = (h>>6) % bloom_sz
|
||||||
|
bloom_msk = ((1<<(h%64)) | (1<<((h>>bloom_sh)%64)))
|
||||||
|
print(f" [{i+symoff:2}]: {h:08x} {end:5} {bloom_idx:2}/{bloom_msk:016x}")
|
||||||
|
|
||||||
|
|
||||||
|
def print_tables(filename):
|
||||||
|
from elftools.elf.elffile import ELFFile
|
||||||
|
|
||||||
|
print(filename)
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
with open(filename, 'rb') as f:
|
||||||
|
elf = ELFFile(f)
|
||||||
|
print_got(elf, ".got")
|
||||||
|
print_got(elf, ".got.plt")
|
||||||
|
print_plt(elf)
|
||||||
|
print_dyn(elf)
|
||||||
|
print_gnu_hash(elf)
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
for filename in sys.argv[1:]:
|
||||||
|
print_tables(filename)
|
||||||
Reference in New Issue
Block a user