From 9d19daaea3815066ea0b4fa83bfb30c8bf5f260f Mon Sep 17 00:00:00 2001 From: Zach Riggle Date: Wed, 1 Feb 2017 23:40:55 -0500 Subject: [PATCH] Simplify ctypes and ELF logic for choosing endianness / architecture --- pwndbg/ctypes.py | 49 +++------ pwndbg/elf.py | 9 +- pwndbg/elftypes.py | 255 +++------------------------------------------ 3 files changed, 32 insertions(+), 281 deletions(-) diff --git a/pwndbg/ctypes.py b/pwndbg/ctypes.py index 5701eacbb..f0fa3530f 100644 --- a/pwndbg/ctypes.py +++ b/pwndbg/ctypes.py @@ -13,48 +13,23 @@ from __future__ import print_function from __future__ import unicode_literals import ctypes -import struct - -import six +import sys import pwndbg.arch import pwndbg.events -import pwndbg.memory - -endian = {'big': '>', 'little': '<'} - -def getattribute(self, attrname): - value = super(EndianAwareStructure, self).__getattribute__(attrname) - - if pwndbg.arch.endian == pwndbg.arch.native_endian: - return value - - if attrname == '_fields_': - return value - - for field in self._fields_: - name = field[0] - typ = field[1] - - if name != attrname: - continue - - if isinstance(typ._type_, six.string_types): - fmt_orig = typ._type_ - fmt_endian = endian[pwndbg.arch.endian] + fmt_orig - value = struct.pack(fmt_orig, value) - value = struct.unpack(fmt_endian, value)[0] - return value +module = sys.modules[__name__] +@pwndbg.events.start +@pwndbg.events.new_objfile +def update(): + global module -class EndianAwareStructure(ctypes.Structure): - def __getattribute__(self, attrname): - return getattribute(self, attrname) + if pwndbg.arch.endian == 'little': + Structure = ctypes.LittleEndianStructure + else: + Structure = ctypes.BigEndianStructure -class EndianAwareUnion(ctypes.Union): - def __getattribute__(self, attrname): - return getattribute(self, attrname) + module.__dict__.update(locals()) -Union = EndianAwareUnion -Structure = EndianAwareStructure +update() diff --git a/pwndbg/elf.py b/pwndbg/elf.py index 95a24e0be..51d019635 100644 --- a/pwndbg/elf.py +++ b/pwndbg/elf.py @@ -20,13 +20,13 @@ import tempfile import gdb import pwndbg.auxv +import pwndbg.elftypes as E import pwndbg.events import pwndbg.info import pwndbg.memoize import pwndbg.memory import pwndbg.proc import pwndbg.stack -from pwndbg.elftypes import * # ELF constants PF_X, PF_W, PF_R = 1,2,4 @@ -128,8 +128,7 @@ def get_ehdr(pointer): ei_class = pwndbg.memory.byte(base+4) # Find out where the section headers start - EhdrType = { 1: Elf32_Ehdr, 2: Elf64_Ehdr }[ei_class] - Elfhdr = read(EhdrType, base) + Elfhdr = read(E.Ehdr, base) return ei_class, Elfhdr def get_phdrs(pointer): @@ -143,13 +142,11 @@ def get_phdrs(pointer): if Elfhdr is None: return (0, 0, None) - PhdrType = { 1: Elf32_Phdr, 2: Elf64_Phdr }[ei_class] - phnum = Elfhdr.e_phnum phoff = Elfhdr.e_phoff phentsize = Elfhdr.e_phentsize - x = (phnum, phentsize, read(PhdrType, Elfhdr.address + phoff)) + x = (phnum, phentsize, read(E.Phdr, Elfhdr.address + phoff)) return x def iter_phdrs(ehdr): diff --git a/pwndbg/elftypes.py b/pwndbg/elftypes.py index a64f7d663..1512cdda8 100644 --- a/pwndbg/elftypes.py +++ b/pwndbg/elftypes.py @@ -35,6 +35,8 @@ from __future__ import print_function from __future__ import unicode_literals import ctypes +import six +import sys import pwndbg.arch import pwndbg.ctypes @@ -312,245 +314,22 @@ class Elf64_Phdr(pwndbg.ctypes.Structure): ("p_memsz", Elf64_Xword), ("p_align", Elf64_Xword),] -class Elf32_Shdr(pwndbg.ctypes.Structure): - _fields_ = [("sh_name", Elf32_Word), - ("sh_type", Elf32_Word), - ("sh_flags", Elf32_Word), - ("sh_addr", Elf32_Addr), - ("sh_offset", Elf32_Off), - ("sh_size", Elf32_Word), - ("sh_link", Elf32_Word), - ("sh_info", Elf32_Word), - ("sh_addralign", Elf32_Word), - ("sh_entsize", Elf32_Word),] +module = sys.modules[__name__] -class Elf64_Shdr(pwndbg.ctypes.Structure): - _fields_ = [("sh_name", Elf64_Word), - ("sh_type", Elf64_Word), - ("sh_flags", Elf64_Xword), - ("sh_addr", Elf64_Addr), - ("sh_offset", Elf64_Off), - ("sh_size", Elf64_Xword), - ("sh_link", Elf64_Word), - ("sh_info", Elf64_Word), - ("sh_addralign", Elf64_Xword), - ("sh_entsize", Elf64_Xword),] +@pwndbg.events.start +@pwndbg.events.new_objfile +def reload(): + six.moves.reload_module(module) + module.update() -class _U__Elf32_Dyn(pwndbg.ctypes.Union): - _fields_ = [("d_val", Elf32_Sword), - ("d_ptr", Elf32_Addr),] +def update(): + if pwndbg.arch.ptrsize == 4: + Ehdr = Elf32_Ehdr + Phdr = Elf32_Phdr + else: + Ehdr = Elf64_Ehdr + Phdr = Elf64_Phdr -class Elf32_Dyn(pwndbg.ctypes.Structure): - _anonymous_ = ("d_un",) - _fields_ = [("d_tag", Elf32_Sword), - ("d_un", _U__Elf32_Dyn),] + module.__dict__.update(locals()) -class _U__Elf64_Dyn(pwndbg.ctypes.Union): - _fields_ = [("d_val", Elf64_Xword), - ("d_ptr", Elf64_Addr),] - -class Elf64_Dyn(pwndbg.ctypes.Structure): - _anonymous_ = ("d_un",) - _fields_ = [("d_tag", Elf64_Sxword), - ("d_un", _U__Elf64_Dyn),] - -class Elf32_Sym(pwndbg.ctypes.Structure): - _fields_ = [("st_name", Elf32_Word), - ("st_value", Elf32_Addr), - ("st_size", Elf32_Word), - ("st_info", ctypes.c_ubyte), - ("st_other", ctypes.c_ubyte), - ("st_shndx", Elf32_Half),] - -class Elf64_Sym(pwndbg.ctypes.Structure): - _fields_ = [("st_name", Elf64_Word), - ("st_info", ctypes.c_ubyte), - ("st_other", ctypes.c_ubyte), - ("st_shndx", Elf64_Half), - ("st_value", Elf64_Addr), - ("st_size", Elf64_Xword),] - -class Elf32_Link_Map(pwndbg.ctypes.Structure): - _fields_ = [("l_addr", Elf32_Addr), - ("l_name", Elf32_Addr), - ("l_ld", Elf32_Addr), - ("l_next", Elf32_Addr), - ("l_prev", Elf32_Addr),] - -class Elf64_Link_Map(pwndbg.ctypes.Structure): - _fields_ = [("l_addr", Elf64_Addr), - ("l_name", Elf64_Addr), - ("l_ld", Elf64_Addr), - ("l_next", Elf64_Addr), - ("l_prev", Elf64_Addr),] - - -# -# Additions below here by Zach Riggle for pwntool -# -# See the routine elf_machine_runtime_setup for the relevant architecture -# for the layout of the GOT. -# -# https://chromium.googlesource.com/chromiumos/third_party/glibc/+/master/sysdeps/x86/dl-machine.h -# https://chromium.googlesource.com/chromiumos/third_party/glibc/+/master/sysdeps/x86_64/dl-machine.h -# https://fossies.org/dox/glibc-2.20/aarch64_2dl-machine_8h_source.html#l00074 -# https://fossies.org/dox/glibc-2.20/powerpc32_2dl-machine_8c_source.html#l00203 -# -# For now, these are defined for x86 and x64 -# -char = ctypes.c_char -byte = ctypes.c_byte - -class Elf_eident(pwndbg.ctypes.Structure): - _fields_ = [('EI_MAG',char*4), - ('EI_CLASS',byte), - ('EI_DATA',byte), - ('EI_VERSION',byte), - ('EI_OSABI',byte), - ('EI_ABIVERSION',byte), - ('EI_PAD', byte*(16-9))] - -class Elf_i386_GOT(pwndbg.ctypes.Structure): - _fields_ = [("jmp", Elf32_Addr), - ("linkmap", Elf32_Addr), - ("dl_runtime_resolve", Elf32_Addr)] - -class Elf_x86_64_GOT(pwndbg.ctypes.Structure): - _fields_ = [("jmp", Elf64_Addr), - ("linkmap", Elf64_Addr), - ("dl_runtime_resolve", Elf64_Addr)] - -class Elf_HashTable(pwndbg.ctypes.Structure): - _fields_ = [('nbucket', Elf32_Word), - ('nchain', Elf32_Word),] - # ('bucket', nbucket * Elf32_Word), - # ('chain', nchain * Elf32_Word)] - -# Docs: http://dyncall.org/svn/dyncall/tags/r0.4/dyncall/dynload/dynload_syms_elf.c -class GNU_HASH(pwndbg.ctypes.Structure): - _fields_ = [('nbuckets', Elf32_Word), - ('symndx', Elf32_Word), - ('maskwords', Elf32_Word), - ('shift2', Elf32_Word)] - -class Elf32_r_debug(pwndbg.ctypes.Structure): - _fields_ = [('r_version', Elf32_Word), - ('r_map', Elf32_Addr)] - -class Elf64_r_debug(pwndbg.ctypes.Structure): - _fields_ = [('r_version', Elf32_Word), - ('r_map', Elf64_Addr)] - -constants.DT_GNU_HASH = 0x6ffffef5 -constants.STN_UNDEF = 0 - -pid_t = ctypes.c_uint32 - -class elf_siginfo(pwndbg.ctypes.Structure): - _fields_ = [('si_signo', ctypes.c_int32), - ('si_code', ctypes.c_int32), - ('si_errno', ctypes.c_int32)] - -class timeval32(pwndbg.ctypes.Structure): - _fields_ = [('tv_sec', ctypes.c_int32), - ('tv_usec', ctypes.c_int32),] - -class timeval64(pwndbg.ctypes.Structure): - _fields_ = [('tv_sec', ctypes.c_int64), - ('tv_usec', ctypes.c_int64),] - -# See linux/elfcore.h -def generate_prstatus_common(size, regtype): - c_long = ctypes.c_uint32 if size==32 else ctypes.c_uint64 - timeval = timeval32 if size==32 else timeval64 - - return [('pr_info', elf_siginfo), - ('pr_cursig', ctypes.c_int16), - ('pr_sigpend', c_long), - ('pr_sighold', c_long), - ('pr_pid', pid_t), - ('pr_ppid', pid_t), - ('pr_pgrp', pid_t), - ('pr_sid', pid_t), - ('pr_utime', timeval), - ('pr_stime', timeval), - ('pr_cutime', timeval), - ('pr_cstime', timeval), - ('pr_reg', regtype), - ('pr_fpvalid', ctypes.c_uint32) - ] - -# See i386-linux-gnu/sys/user.h -class user_regs_struct_i386(pwndbg.ctypes.Structure): - _fields_ = [(name, ctypes.c_uint32) for name in [ - 'ebx', - 'ecx', - 'edx', - 'esi', - 'edi', - 'ebp', - 'eax', - 'xds', - 'xes', - 'xfs', - 'xgs', - 'orig_eax', - 'eip', - 'xcs', - 'eflags', - 'esp', - 'xss', - ]] - -assert ctypes.sizeof(user_regs_struct_i386) == 0x44, ctypes.sizeof(user_regs_struct_i386) - -# See i386-linux-gnu/sys/user.h -class user_regs_struct_amd64(pwndbg.ctypes.Structure): - _fields_ = [(name, ctypes.c_uint64) for name in [ - 'r15', - 'r14', - 'r13', - 'r12', - 'rbp', - 'rbx', - 'r11', - 'r10', - 'r9', - 'r8', - 'rax', - 'rcx', - 'rdx', - 'rsi', - 'rdi', - 'orig_rax', - 'rip', - 'cs', - 'eflags', - 'rsp', - 'ss', - 'fs_base', - 'gs_base', - 'ds', - 'es', - 'fs', - 'gs', - ]] - -assert ctypes.sizeof(user_regs_struct_amd64) == 0xd8 - -class elf_prstatus_i386(pwndbg.ctypes.Structure): - _fields_ = generate_prstatus_common(32, user_regs_struct_i386) - -assert ctypes.sizeof(elf_prstatus_i386) == 0x90 - -class elf_prstatus_amd64(pwndbg.ctypes.Structure): - _fields_ = generate_prstatus_common(64, user_regs_struct_amd64) - -assert ctypes.sizeof(elf_prstatus_amd64) == 0x150 - -class Elf32_auxv_t(pwndbg.ctypes.Structure): - _fields_ = [('a_type', ctypes.c_uint32), - ('a_val', ctypes.c_uint32),] -class Elf64_auxv_t(pwndbg.ctypes.Structure): - _fields_ = [('a_type', ctypes.c_uint64), - ('a_val', ctypes.c_uint64),] +update()