Skip to content

Instantly share code, notes, and snippets.

@integeruser
Last active April 23, 2024 09:36
Show Gist options
  • Save integeruser/b0d3ea6c4e8387d036acf6c77c0ec406 to your computer and use it in GitHub Desktop.
Save integeruser/b0d3ea6c4e8387d036acf6c77c0ec406 to your computer and use it in GitHub Desktop.
Extract symbols information (e.g. addresses) from Mach-O files
#!/usr/bin/env python3
import ctypes
LC_SYMTAB = 0x2
class mach_header_64(ctypes.Structure):
_fields_ = (
("magic", ctypes.c_uint32),
("cputype", ctypes.c_uint32),
("cpusubtype", ctypes.c_uint32),
("filetype", ctypes.c_uint32),
("ncmds", ctypes.c_uint32),
("sizeofcmds", ctypes.c_uint32),
("flags", ctypes.c_uint32),
("reserved", ctypes.c_uint32),
)
class load_command(ctypes.Structure):
_fields_ = (("cmd", ctypes.c_uint32), ("cmdsize", ctypes.c_uint32))
class symtab_command(ctypes.Structure):
_fields_ = (
("symoff", ctypes.c_uint32),
("nsyms", ctypes.c_uint32),
("stroff", ctypes.c_uint32),
("strsize", ctypes.c_uint32),
)
class nlist_64(ctypes.Structure):
_fields_ = [
("n_strx", ctypes.c_uint32),
("n_type", ctypes.c_uint8),
("n_sect", ctypes.c_uint8),
("n_desc", ctypes.c_uint16),
("n_value", ctypes.c_uint64),
]
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("macho", type=argparse.FileType())
parser.add_argument("symbol")
args = parser.parse_args()
symbol = args.symbol.encode("ascii")
with open(args.macho.name, "rb") as m:
data = bytearray(m.read())
off = 0
header = mach_header_64.from_buffer(data[off:])
off += ctypes.sizeof(mach_header_64)
for _ in range(header.ncmds):
loadcmd = load_command.from_buffer(data[off:])
if loadcmd.cmd == LC_SYMTAB:
off += ctypes.sizeof(load_command)
symtabcmd = symtab_command.from_buffer(data[off:])
strtab = data[symtabcmd.stroff : symtabcmd.stroff + symtabcmd.strsize]
nlistoff = symtabcmd.symoff
for _ in range(symtabcmd.nsyms):
nlist = nlist_64.from_buffer(data[nlistoff:])
nlistoff += ctypes.sizeof(nlist_64)
if not nlist.n_strx == 0 and strtab[nlist.n_strx :].startswith(symbol):
sym = strtab[nlist.n_strx : strtab.find(b"\x00", nlist.n_strx)]
if sym == symbol:
print("n_strx: 0x{:x}".format(nlist.n_strx))
print("n_type: 0x{:x}".format(nlist.n_type))
print("n_sect: 0x{:x}".format(nlist.n_sect))
print("n_desc: 0x{:x}".format(nlist.n_desc))
print("n_value: 0x{:016x}".format(nlist.n_value))
break
break
else:
off += loadcmd.cmdsize
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment