Skip to content

Instantly share code, notes, and snippets.

@mrzechonek
Created November 24, 2016 11:52
Show Gist options
  • Save mrzechonek/b843be2d1b48236e40a07193272309c0 to your computer and use it in GitHub Desktop.
Save mrzechonek/b843be2d1b48236e40a07193272309c0 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
from collections import OrderedDict
import enum
import struct
class Field:
def __init__(self, format, type=int):
self.format = format
self.type = type
class StructMeta(type):
@classmethod
def __prepare__(self, name, bases):
# preserve field order
return OrderedDict()
def __new__(mcs, name, bases, attrs, **kwargs):
cls = super().__new__(mcs, name, bases, attrs, **kwargs)
cls._fields = OrderedDict((k, v) for k, v in attrs.items() if isinstance(v, Field))
return cls
class Struct(metaclass=StructMeta):
class Endian(enum.Enum):
BIG = '>'
LITTLE = '<'
NATIVE = '='
def __init__(self, *args, **kwargs):
for name in self._fields.keys():
setattr(self, name, kwargs.get(name))
def __str__(self):
values = ('{}={}'.format(i, getattr(self, i)) for i in self._fields)
return '{}({})'.format(type(self).__name__, ', '.join(values))
@classmethod
def read(cls, fp, endian=Endian.NATIVE.value):
format = endian + ''.join(i.format for i in cls._fields.values())
data = fp.read(struct.calcsize(format))
values = struct.unpack(format, data)
kwargs = { name: field.type(value)
for (name, field), value
in zip(cls._fields.items(), values)}
return cls(**kwargs)
class RangedEnumMeta(enum.EnumMeta):
def __call__(cls, value, *args, **kwargs):
if cls._range(value):
return value
return super().__call__(value, *args, **kwargs)
class ELFIdent(Struct):
class Bits(enum.Enum):
B32 = 1
B64 = 2
class Endian(enum.Enum):
LITTLE = 1
BIG = 2
class OperatingSystem(enum.Enum):
SYSTEM_V = 0x0
HP_UX = 0x1
NETBSD = 0x2
LINUX = 0x3
SOLARIS = 0x6
AIX = 0x7
IRIX = 0x8
FREEBSD = 0x9
OPENBSD = 0xc
# there are more...
magic = Field('4s', bytes)
bits = Field('B', Bits)
endian = Field('B', Endian)
version = Field('B')
os = Field('B', OperatingSystem)
abiversion = Field('B')
pad = Field('7x', None)
class ELFHeader64(Struct):
class Type(enum.Enum):
RELOCATABLE = 1
EXECUTABLE = 2
SHARED = 3
CORE = 4
class Machine(enum.Enum):
UNSPEC = 0x00
SPARC = 0x02
X86 = 0x03
MIPS = 0x08
PPC = 0x14
ARM = 0x28
SH = 0x2A
IA64 = 0x32
X86_64 = 0x3E
AARCH64 = 0xB7
type = Field('H', Type)
machine = Field('H', Machine)
version = Field('L')
entry = Field('Q')
phoff = Field('Q')
shoff = Field('Q')
flags = Field('L')
ehsize = Field('H')
phentsize = Field('H')
phnum = Field('H')
shentsize = Field('H')
shnum = Field('H')
shstrndx = Field('H')
class ProgramHeader64(Struct):
class Type(enum.Enum, metaclass=RangedEnumMeta):
NULL = 0x00000000
LOAD = 0x00000001
DYNAMIC = 0x00000002
INTERP = 0x00000003
NOTE = 0x00000004
SHLIB = 0x00000005
PHDR = 0x00000006
@classmethod
def _range(self, value):
OS = (0x60000000, 0x6FFFFFFF)
PROC = (0x70000000, 0x7FFFFFFF)
return OS[0] <= value <= OS[1] or \
PROC[0] <= value <= PROC[1]
type = Field('L', Type)
flags = Field('L')
offset = Field('Q')
vaddr = Field('Q')
paddr = Field('Q')
filesz = Field('Q')
memsz = Field('Q')
align = Field('Q')
class SectionHeader64(Struct):
class Type(enum.Enum, metaclass=RangedEnumMeta):
NULL = 0x0
PROGBITS = 0x1
SYMTAB = 0x2
STRTAB = 0x3
RELA = 0x4
HASH = 0x5
DYNAMIC = 0x6
NOTE = 0x7
NOBITS = 0x8
REL = 0x9
SHLIB = 0xa
DYNSYM = 0xb
@classmethod
def _range(self, value):
OS = (0x60000000, 0x6FFFFFFF)
PROC = (0x70000000, 0x7FFFFFFF)
return OS[0] <= value <= OS[1] or \
PROC[0] <= value <= PROC[1]
name = Field('L')
type = Field('L', Type)
flags = Field('Q')
addr = Field('Q')
offset = Field('Q')
link = Field('L')
info = Field('L')
addralign = Field('Q')
entsize = Field('Q')
if __name__ == "__main__":
import sys
f = open(sys.argv[1], 'rb')
ident = ELFIdent.read(f)
print(ident)
assert ident.bits == ELFIdent.Bits.B64
header = ELFHeader64.read(f)
print(header)
f.seek(header.phoff)
for i in range(header.phnum):
program_header = ProgramHeader64.read(f)
print(program_header)
f.seek(header.shoff)
for i in range(header.shnum):
section_header = SectionHeader64.read(f)
print(section_header)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment