diff --git a/assets/debugging/jsix.elf-gdb.py b/assets/debugging/jsix.elf-gdb.py index 32bd019..bf4052c 100644 --- a/assets/debugging/jsix.elf-gdb.py +++ b/assets/debugging/jsix.elf-gdb.py @@ -474,11 +474,39 @@ class HandleSetPrinter: 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(): pp = gdb.printing.RegexpCollectionPrettyPrinter("jsix") pp.add_printer("cap table", '^cap_table$', CapTablePrinter) pp.add_printer("handle set", '^util::node_set$', HandleSetPrinter) pp.add_printer("vector", '^util::vector<.*>$', VectorPrinter) + pp.add_printer("linked list", '^util::linked_list<.*>$', LinkedListPrinter) return pp gdb.printing.register_pretty_printer( diff --git a/requirements.txt b/requirements.txt index 12f1ac2..05968c7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,4 @@ pyyaml >= 5.4 lark == 0.12.0 pure-cdb == 4 pyzstd == 0.15 +pyelftools diff --git a/scripts/print_got.py b/scripts/print_got.py new file mode 100755 index 0000000..c05f61b --- /dev/null +++ b/scripts/print_got.py @@ -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)