From d3a42fa5dcdb0c467586eb6b92271fa4dbeb648b Mon Sep 17 00:00:00 2001 From: Pierre LALET Date: Wed, 27 Feb 2019 20:29:44 +0100 Subject: [PATCH] Include elfesteem fork in miasm --- .codespell_ignore | 1 + README.md | 13 +- example/asm/shellcode.py | 4 +- example/elfesteem/minidump_to_pe.py | 48 + example/elfesteem/test_pe.py | 31 + example/jitter/arm_sc.py | 2 +- example/jitter/run_with_linuxenv.py | 2 +- example/jitter/unpack_upx.py | 2 +- miasm/analysis/binary.py | 4 +- miasm/elfesteem/__init__.py | 3 + miasm/elfesteem/cstruct.py | 154 +++ miasm/elfesteem/elf.py | 1538 ++++++++++++++++++++++++ miasm/elfesteem/elf_init.py | 878 ++++++++++++++ miasm/elfesteem/minidump.py | 545 +++++++++ miasm/elfesteem/minidump_init.py | 194 ++++ miasm/elfesteem/new_cstruct.py | 265 +++++ miasm/elfesteem/pe.py | 1668 +++++++++++++++++++++++++++ miasm/elfesteem/pe_init.py | 603 ++++++++++ miasm/elfesteem/strpatchwork.py | 106 ++ miasm/jitter/loader/elf.py | 12 +- miasm/jitter/loader/pe.py | 6 +- miasm/os_dep/win_api_x86_32_seh.py | 2 +- requirements.txt | 1 - setup.py | 1 + test/analysis/dse.py | 2 +- test/arch/aarch64/unit/asm_test.py | 2 +- test/arch/mips32/unit/asm_test.py | 2 +- test/arch/x86/unit/asm_test.py | 2 +- 28 files changed, 6058 insertions(+), 33 deletions(-) create mode 100644 example/elfesteem/minidump_to_pe.py create mode 100644 example/elfesteem/test_pe.py create mode 100644 miasm/elfesteem/__init__.py create mode 100644 miasm/elfesteem/cstruct.py create mode 100644 miasm/elfesteem/elf.py create mode 100644 miasm/elfesteem/elf_init.py create mode 100644 miasm/elfesteem/minidump.py create mode 100644 miasm/elfesteem/minidump_init.py create mode 100644 miasm/elfesteem/new_cstruct.py create mode 100644 miasm/elfesteem/pe.py create mode 100644 miasm/elfesteem/pe_init.py create mode 100644 miasm/elfesteem/strpatchwork.py diff --git a/.codespell_ignore b/.codespell_ignore index 3724a1f46..8eab9f6f3 100644 --- a/.codespell_ignore +++ b/.codespell_ignore @@ -4,3 +4,4 @@ uint mye iff nto +rela diff --git a/README.md b/README.md index 010f75d65..0d1fdf8a9 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Miasm is a free and open source (GPLv2) reverse engineering framework. Miasm aims to analyze / modify / generate binary programs. Here is a non exhaustive list of features: -* Opening / modifying / generating PE / ELF 32 / 64 LE / BE using Elfesteem +* Opening / modifying / generating PE / ELF 32 / 64 LE / BE * Assembling / Disassembling X86 / ARM / MIPS / SH4 / MSP430 * Representing assembly semantic using intermediate language * Emulating using JIT (dynamic code analysis, unpacking, ...) @@ -525,7 +525,6 @@ Miasm uses: * python-pyparsing * python-dev -* elfesteem from [Elfesteem](https://github.com/serpilliere/elfesteem.git) * optionally python-pycparser (version >= 2.17) To enable code JIT, one of the following module is mandatory: @@ -539,14 +538,6 @@ To enable code JIT, one of the following module is mandatory: Configuration ------------- -* Install elfesteem -```pycon -git clone https://github.com/serpilliere/elfesteem.git elfesteem -cd elfesteem -python setup.py build -sudo python setup.py install -``` - To use the jitter, GCC or LLVM is recommended * GCC (any version) * Clang (any version) @@ -570,7 +561,7 @@ Windows & IDA Most of Miasm's IDA plugins use a subset of Miasm functionality. A quick way to have them working is to add: -* `elfesteem` directory and `pyparsing.py` to `C:\...\IDA\python\` or `pip install pyparsing elfesteem` +* `pyparsing.py` to `C:\...\IDA\python\` or `pip install pyparsing` * `miasm/miasm` directory to `C:\...\IDA\python\` All features excepting JITter related ones will be available. For a more complete installation, please refer to above paragraphs. diff --git a/example/asm/shellcode.py b/example/asm/shellcode.py index ed489bbde..59ea3a943 100755 --- a/example/asm/shellcode.py +++ b/example/asm/shellcode.py @@ -4,8 +4,8 @@ from pdb import pm from future.utils import viewitems -from elfesteem import pe_init -from elfesteem.strpatchwork import StrPatchwork +from miasm.elfesteem import pe_init +from miasm.elfesteem.strpatchwork import StrPatchwork from miasm.core import parse_asm, asmblock from miasm.analysis.machine import Machine diff --git a/example/elfesteem/minidump_to_pe.py b/example/elfesteem/minidump_to_pe.py new file mode 100644 index 000000000..8aff3e624 --- /dev/null +++ b/example/elfesteem/minidump_to_pe.py @@ -0,0 +1,48 @@ +#! /usr/bin/env python +"""Minidump to PE example""" + +import sys + +from future.utils import viewvalues + +from miasm.elfesteem.minidump_init import Minidump +from miasm.elfesteem.pe_init import PE + +minidump = Minidump(open(sys.argv[1], 'rb').read()) + +pe = PE() +for i, memory in enumerate(sorted(viewvalues(minidump.memory), + key=lambda x:x.address)): + # Get section name + name = str(memory.name) + if not name: + name = "s_%02d" % i + else: + name = name.split('\\')[-1] + + # Get section protection + protect = memory.pretty_protect + protect_mask = 0x20 + if protect == "UNKNOWN": + protect_mask |= 0xe0000000 + else: + if "EXECUTE" in protect: + protect_mask |= 1 << 29 + if "READ" in protect: + protect_mask |= 1 << 30 + if "WRITE" in protect: + protect_mask |= 1 << 31 + + # Add the section + pe.SHList.add_section(name=name, addr=memory.address, rawsize=memory.size, + data=memory.content, flags=protect_mask) + +# Find entry point +try: + entry_point = minidump.threads.Threads[0].ThreadContext.Eip[0] +except AttributeError: + entry_point = minidump.threads.Threads[0].ThreadContext.Rip[0] + +pe.Opthdr.AddressOfEntryPoint = entry_point + +open("out_pe.bin", "wb").write(bytes(pe)) diff --git a/example/elfesteem/test_pe.py b/example/elfesteem/test_pe.py new file mode 100644 index 000000000..e9cff0b42 --- /dev/null +++ b/example/elfesteem/test_pe.py @@ -0,0 +1,31 @@ +#! /usr/bin/env python + +import miasm.elfesteem.pe as pe +from miasm.elfesteem.pe_init import PE +import rlcompleter +import readline +import pdb +import sys +from pprint import pprint as pp +readline.parse_and_bind("tab: complete") + + +e_ = PE() +mysh = b"\xc3" +s_text = e_.SHList.add_section( + name="text", addr=0x1000, rawsize=0x1000, data=mysh) +e_.Opthdr.AddressOfEntryPoint = s_text.addr +new_dll = [({"name": "kernel32.dll", + "firstthunk": s_text.addr + 0x100}, + ["CreateFileA", "SetFilePointer", "WriteFile", "CloseHandle"] + ), + ({"name": "USER32.dll", + "firstthunk": None}, + ["SetDlgItemInt", "GetMenu", "HideCaret"] + ) + ] +e_.DirImport.add_dlldesc(new_dll) + +s_myimp = e_.SHList.add_section(name="myimp", rawsize=0x1000) +e_.DirImport.set_rva(s_myimp.addr) +open('uu.bin', 'wb').write(bytes(e_)) diff --git a/example/jitter/arm_sc.py b/example/jitter/arm_sc.py index 8d5b56775..ddadbf29e 100755 --- a/example/jitter/arm_sc.py +++ b/example/jitter/arm_sc.py @@ -3,7 +3,7 @@ from miasm.core.utils import int_to_byte from miasm.analysis.sandbox import Sandbox_Linux_armb_str from miasm.analysis.sandbox import Sandbox_Linux_arml_str -from elfesteem.strpatchwork import StrPatchwork +from miasm.elfesteem.strpatchwork import StrPatchwork from pdb import pm diff --git a/example/jitter/run_with_linuxenv.py b/example/jitter/run_with_linuxenv.py index e2869699e..0237cc942 100644 --- a/example/jitter/run_with_linuxenv.py +++ b/example/jitter/run_with_linuxenv.py @@ -2,7 +2,7 @@ import logging import re -from elfesteem import elf as elf_csts +from miasm.elfesteem import elf as elf_csts from miasm.os_dep.linux import environment, syscall from miasm.analysis.machine import Machine diff --git a/example/jitter/unpack_upx.py b/example/jitter/unpack_upx.py index 0a41d0382..05d28b16a 100644 --- a/example/jitter/unpack_upx.py +++ b/example/jitter/unpack_upx.py @@ -2,7 +2,7 @@ import os import logging from pdb import pm -from elfesteem import pe +from miasm.elfesteem import pe from miasm.analysis.sandbox import Sandbox_Win_x86_32 # User defined methods diff --git a/miasm/analysis/binary.py b/miasm/analysis/binary.py index 82f831121..6dc095cf0 100644 --- a/miasm/analysis/binary.py +++ b/miasm/analysis/binary.py @@ -131,7 +131,7 @@ class ContainerPE(Container): def parse(self, data, vm=None, **kwargs): from miasm.jitter.loader.pe import vm_load_pe, guess_arch - from elfesteem import pe_init + from miasm.elfesteem import pe_init # Parse signature if not data.startswith(b'MZ'): @@ -178,7 +178,7 @@ def parse(self, data, vm=None, addr=0, apply_reloc=False, **kwargs): """ from miasm.jitter.loader.elf import vm_load_elf, guess_arch, \ fill_loc_db_with_symbols - from elfesteem import elf_init + from miasm.elfesteem import elf_init # Parse signature if not data.startswith(b'\x7fELF'): diff --git a/miasm/elfesteem/__init__.py b/miasm/elfesteem/__init__.py new file mode 100644 index 000000000..1a602f38e --- /dev/null +++ b/miasm/elfesteem/__init__.py @@ -0,0 +1,3 @@ +#!/usr/bin/env python + +__all__ = ['pe_init', 'elf_init', 'strpatchwork'] diff --git a/miasm/elfesteem/cstruct.py b/miasm/elfesteem/cstruct.py new file mode 100644 index 000000000..06d2e0027 --- /dev/null +++ b/miasm/elfesteem/cstruct.py @@ -0,0 +1,154 @@ +#! /usr/bin/env python + +from __future__ import print_function +from builtins import zip +from functools import reduce +import struct + +from future.utils import PY3 + +type_size = {} +size2type = {} +for t in 'B', 'H', 'I', 'Q': + s = struct.calcsize(t) + type_size[t] = s * 8 + size2type[s * 8] = t + +type_size['u08'] = size2type[8] +type_size['u16'] = size2type[16] +type_size['u32'] = size2type[32] +type_size['u64'] = size2type[64] + + +def fix_size(fields, wsize): + out = [] + for name, v in fields: + if v.endswith("s"): + pass + elif v == "ptr": + v = size2type[wsize] + elif not v in type_size: + raise ValueError("unknown Cstruct type", v) + else: + v = type_size[v] + out.append((name, v)) + fields = out + return fields + + +class Cstruct_Metaclass(type): + + def __new__(cls, name, bases, dct): + o = super(Cstruct_Metaclass, cls).__new__(cls, name, bases, dct) + o._packstring = o._packformat + \ + "".join(x[1] for x in o._fields) + o._size = struct.calcsize(o._packstring) + return o + + +class CStruct(object): + #__metaclass__ = Cstruct_Metaclass + _packformat = "" + _fields = [] + + @classmethod + def _from_file(cls, f): + return cls(f.read(cls._size)) + + def __init__(self, sex, wsize, *args, **kargs): + if sex == 1: + sex = '<' + else: + sex = '>' + # packformat enforce sex + if self._packformat: + sex = "" + pstr = fix_size(self._fields, wsize) + self._packstring = sex + self._packformat + \ + "".join(x[1] for x in pstr) + self._size = struct.calcsize(self._packstring) + + self._names = [x[0] for x in self._fields] + if kargs: + self.__dict__.update(kargs) + else: + if args: + s = args[0] + else: + s = b"" + s += b"\x00" * self._size + s = s[:self._size] + self._unpack(s) + + def _unpack(self, s): + disas = struct.unpack(self._packstring, s) + for n, v in zip(self._names, disas): + setattr(self, n, v) + + def _pack(self): + return struct.pack(self._packstring, + *(getattr(self, x) for x in self._names)) + + def _spack(self, superstruct, shift=0): + attr = [] + for name in self._names: + s = getattr(self, name) + if isinstance(s, CStruct): + if s in superstruct: + s = reduce(lambda x, y: x + len(y), + superstruct[:superstruct.index(s)], + 0) + s += shift + else: + raise Exception("%r is not a superstructure" % s) + attr.append(s) + return struct.pack(self._packstring, *attr) + + def _copy(self): + return self.__class__(**self.__dict__) + + def __len__(self): + return self._size + + def __str__(self): + if PY3: + return repr(self) + return self.__bytes__() + + def __bytes__(self): + return self._pack() + + def __repr__(self): + return "<%s=%s>" % (self.__class__.__name__, "/".join(repr( + getattr(self, x[0])) for x in self._fields + )) + + def __getitem__(self, item): # to work with format strings + return getattr(self, item) + + def _show(self): + print("##%s:" % self.__class__.__name__) + fmt = "%%-%is = %%r" % max(len(x[0]) for x in self._fields) + for fn, ft in self._fields: + print(fmt % (fn, getattr(self, fn))) + + +class CStructStruct(object): + + def __init__(self, lst, shift=0): + self._lst = lst + self._shift = shift + + def __getattr__(self, attr): + return getattr(self._lst, attr) + + def __str__(self): + if PY3: + return repr(self) + return self.__bytes__() + + def __bytes__(self): + return b"".join( + a if isinstance(a, bytes) else a._spack(self._lst, self._shift) + for a in self._lst + ) diff --git a/miasm/elfesteem/elf.py b/miasm/elfesteem/elf.py new file mode 100644 index 000000000..bdd088b8c --- /dev/null +++ b/miasm/elfesteem/elf.py @@ -0,0 +1,1538 @@ +#! /usr/bin/env python + +from miasm.elfesteem.cstruct import CStruct + +class Ehdr(CStruct): + _fields = [ ("ident","16s"), + ("type","u16"), + ("machine","u16"), + ("version","u32"), + ("entry","ptr"), + ("phoff","ptr"), + ("shoff","ptr"), + ("flags","u32"), + ("ehsize","u16"), + ("phentsize","u16"), + ("phnum","u16"), + ("shentsize","u16"), + ("shnum","u16"), + ("shstrndx","u16") ] + + +class Shdr(CStruct): + _fields = [ ("name","u32"), + ("type","u32"), + ("flags","ptr"), + ("addr","ptr"), + ("offset","ptr"), + ("size","ptr"), + ("link","u32"), + ("info","u32"), + ("addralign","ptr"), + ("entsize","ptr") ] + +class Phdr(CStruct): + _fields = [ ("type","u32"), + ("offset","u32"), + ("vaddr","u32"), + ("paddr","u32"), + ("filesz","u32"), + ("memsz","u32"), + ("flags","u32"), + ("align","u32") ] + +class Phdr64(CStruct): + _fields = [ ("type","u32"), + ("flags","u32"), + ("offset","ptr"), + ("vaddr","ptr"), + ("paddr","ptr"), + ("filesz","ptr"), + ("memsz","ptr"), + ("align","ptr") ] + +class Nhdr(CStruct): + _fields = [ ("namesz","u32"), + ("descsz","u32"), + ("type", "u32") ] + + +class Sym32(CStruct): + _fields = [ ("name","u32"), + ("value","u32"), + ("size","u32"), + ("info","u08"), + ("other","u08"), + ("shndx","u16") ] + +class Sym64(CStruct): + _fields = [ ("name","u32"), + ("info","u08"), + ("other","u08"), + ("shndx","u16"), + ("value","u64"), + ("size","u64") ] + +class Dym(CStruct): + _fields = [ ("tag","u32"), + ("val","u32") ] + +class Rel32(CStruct): + _fields = [ ("offset","ptr"), + ("info","u32") ] + +class Rel64(CStruct): + _fields = [ ("offset","ptr"), + ("info","u64") ] + +class Rela32(CStruct): + _fields = [ ("offset","ptr"), + ("info","u32"), + ("addend","ptr") ] + +class Rela64(CStruct): + _fields = [ ("offset","ptr"), + ("info","u64"), + ("addend","ptr") ] + +class Dynamic(CStruct): + _fields = [ ("type","ptr"), + ("name","ptr") ] + + +# Legal values for e_ident (identification indexes) + +EI_MAG0 = 0 # File identification +EI_MAG1 = 1 # File identification +EI_MAG2 = 2 # File identification +EI_MAG3 = 3 # File identification +EI_CLASS = 4 # File class +EI_DATA = 5 # Data encoding +EI_VERSION = 6 # File version +EI_OSABI = 7 # Operating system/ABI identification +EI_ABIVERSION = 8 # ABI version +EI_PAD = 9 # Start of padding bytes +EI_NIDENT = 16 # Size of e_ident[] + +# Legal values for e_ident[EI_CLASS] + +ELFCLASSNONE = 0 # Invalid class +ELFCLASS32 = 1 # 32-bit objects +ELFCLASS64 = 2 # 64-bit objects + +# Legal values for e_ident[EI_DATA] + +ELFDATANONE = 0 # Invalid data encoding +ELFDATA2LSB = 1 # Least significant byte at lowest address +ELFDATA2MSB = 2 # Most significant byte at lowest address + +# Legal values for e_type (object file type). + +ET_NONE = 0 # No file type +ET_REL = 1 # Relocatable file +ET_EXEC = 2 # Executable file +ET_DYN = 3 # Shared object file +ET_CORE = 4 # Core file +ET_NUM = 5 # Number of defined types +ET_LOOS = 0xfe00 # OS-specific range start +ET_HIOS = 0xfeff # OS-specific range end +ET_LOPROC = 0xff00 # Processor-specific range start +ET_HIPROC = 0xffff # Processor-specific range end + +# Legal values for e_machine (architecture). + +EM_NONE = 0 # No machine +EM_M32 = 1 # AT&T WE 32100 +EM_SPARC = 2 # SUN SPARC +EM_386 = 3 # Intel 80386 +EM_68K = 4 # Motorola m68k family +EM_88K = 5 # Motorola m88k family +EM_486 = 6 # Intel 80486 +EM_860 = 7 # Intel 80860 +EM_MIPS = 8 # MIPS R3000 big-endian +EM_S370 = 9 # IBM System/370 +EM_MIPS_RS3_LE = 10 # MIPS R3000 little-endian + +EM_PARISC = 15 # HPPA +EM_VPP500 = 17 # Fujitsu VPP500 +EM_SPARC32PLUS = 18 # Sun's "v8plus" +EM_960 = 19 # Intel 80960 +EM_PPC = 20 # PowerPC +EM_PPC64 = 21 # PowerPC 64-bit +EM_S390 = 22 # IBM S390 + +EM_V800 = 36 # NEC V800 series +EM_FR20 = 37 # Fujitsu FR20 +EM_RH32 = 38 # TRW RH-32 +EM_RCE = 39 # Motorola RCE +EM_ARM = 40 # ARM +EM_FAKE_ALPHA = 41 # Digital Alpha +EM_SH = 42 # Hitachi SH +EM_SPARCV9 = 43 # SPARC v9 64-bit +EM_TRICORE = 44 # Siemens Tricore +EM_ARC = 45 # Argonaut RISC Core +EM_H8_300 = 46 # Hitachi H8/300 +EM_H8_300H = 47 # Hitachi H8/300H +EM_H8S = 48 # Hitachi H8S +EM_H8_500 = 49 # Hitachi H8/500 +EM_IA_64 = 50 # Intel Merced +EM_MIPS_X = 51 # Stanford MIPS-X +EM_COLDFIRE = 52 # Motorola Coldfire +EM_68HC12 = 53 # Motorola M68HC12 +EM_MMA = 54 # Fujitsu MMA Multimedia Accelerator*/ +EM_PCP = 55 # Siemens PCP +EM_NCPU = 56 # Sony nCPU embeeded RISC +EM_NDR1 = 57 # Denso NDR1 microprocessor +EM_STARCORE = 58 # Motorola Start*Core processor +EM_ME16 = 59 # Toyota ME16 processor +EM_ST100 = 60 # STMicroelectronic ST100 processor +EM_TINYJ = 61 # Advanced Logic Corp. Tinyj emb.fam*/ +EM_X86_64 = 62 # AMD x86-64 architecture +EM_AARCH64 = 183 # Aarch64 architecture +EM_PDSP = 63 # Sony DSP Processor + +EM_FX66 = 66 # Siemens FX66 microcontroller +EM_ST9PLUS = 67 # STMicroelectronics ST9+ 8/16 mc +EM_ST7 = 68 # STmicroelectronics ST7 8 bit mc +EM_68HC16 = 69 # Motorola MC68HC16 microcontroller +EM_68HC11 = 70 # Motorola MC68HC11 microcontroller +EM_68HC08 = 71 # Motorola MC68HC08 microcontroller +EM_68HC05 = 72 # Motorola MC68HC05 microcontroller +EM_SVX = 73 # Silicon Graphics SVx +EM_ST19 = 74 # STMicroelectronics ST19 8 bit mc +EM_VAX = 75 # Digital VAX +EM_CRIS = 76 # Axis Communications 32-bit embedded processor +EM_JAVELIN = 77 # Infineon Technologies 32-bit embedded processor +EM_FIREPATH = 78 # Element 14 64-bit DSP Processor +EM_ZSP = 79 # LSI Logic 16-bit DSP Processor +EM_MMIX = 80 # Donald Knuth's educational 64-bit processor +EM_HUANY = 81 # Harvard University machine-independent object files +EM_PRISM = 82 # SiTera Prism +EM_AVR = 83 # Atmel AVR 8-bit microcontroller +EM_FR30 = 84 # Fujitsu FR30 +EM_D10V = 85 # Mitsubishi D10V +EM_D30V = 86 # Mitsubishi D30V +EM_V850 = 87 # NEC v850 +EM_M32R = 88 # Mitsubishi M32R +EM_MN10300 = 89 # Matsushita MN10300 +EM_MN10200 = 90 # Matsushita MN10200 +EM_PJ = 91 # picoJava +EM_OPENRISC = 92 # OpenRISC 32-bit embedded processor +EM_ARC_A5 = 93 # ARC Cores Tangent-A5 +EM_XTENSA = 94 # Tensilica Xtensa Architecture + +EM_ALPHA = 0x9026 + +# Legal values for sh_type (section type). + +SHT_NULL = 0 # Section header table entry unused +SHT_PROGBITS = 1 # Program data +SHT_SYMTAB = 2 # Symbol table +SHT_STRTAB = 3 # String table +SHT_RELA = 4 # Relocation entries with addends +SHT_HASH = 5 # Symbol hash table +SHT_DYNAMIC = 6 # Dynamic linking information +SHT_NOTE = 7 # Notes +SHT_NOBITS = 8 # Program space with no data (bss) +SHT_REL = 9 # Relocation entries, no addends +SHT_SHLIB = 10 # Reserved +SHT_DYNSYM = 11 # Dynamic linker symbol table +SHT_INIT_ARRAY = 14 # Array of constructors +SHT_FINI_ARRAY = 15 # Array of destructors +SHT_PREINIT_ARRAY = 16 # Array of pre-constructors +SHT_GROUP = 17 # Section group +SHT_SYMTAB_SHNDX = 18 # Extended section indices +SHT_NUM = 19 # Number of defined types. +SHT_LOOS = 0x60000000 # Start OS-specific +SHT_GNU_LIBLIST = 0x6ffffff7 # Prelink library list +SHT_CHECKSUM = 0x6ffffff8 # Checksum for DSO content. +SHT_LOSUNW = 0x6ffffffa # Sun-specific low bound. +SHT_SUNW_move = 0x6ffffffa +SHT_SUNW_COMDAT = 0x6ffffffb +SHT_SUNW_syminfo = 0x6ffffffc +SHT_GNU_verdef = 0x6ffffffd # Version definition section. +SHT_GNU_verneed = 0x6ffffffe # Version needs section. +SHT_GNU_versym = 0x6fffffff # Version symbol table. +SHT_HISUNW = 0x6fffffff # Sun-specific high bound. +SHT_HIOS = 0x6fffffff # End OS-specific type +SHT_LOPROC = 0x70000000 # Start of processor-specific +SHT_HIPROC = 0x7fffffff # End of processor-specific +SHT_LOUSER = 0x80000000 # Start of application-specific +SHT_HIUSER = 0x8fffffff # End of application-specific + +# Legal values for sh_flags (section flags). + +SHF_WRITE = (1 << 0) # Writable +SHF_ALLOC = (1 << 1) # Occupies memory during execution +SHF_EXECINSTR = (1 << 2) # Executable +SHF_MERGE = (1 << 4) # Might be merged +SHF_STRINGS = (1 << 5) # Contains nul-terminated strings +SHF_INFO_LINK = (1 << 6) # `sh_info' contains SHT index +SHF_LINK_ORDER = (1 << 7) # Preserve order after combining +SHF_OS_NONCONFORMING = (1 << 8) # Non-standard OS specific handling required +SHF_GROUP = (1 << 9) # Section is member of a group. +SHF_TLS = (1 << 10) # Section hold thread-local data. +SHF_MASKOS = 0x0ff00000 # OS-specific. +SHF_MASKPROC = 0xf0000000 # Processor-specific + +# Section group handling. + +GRP_COMDAT = 0x1 # Mark group as COMDAT. + +# Legal values for p_type (segment type). + +PT_NULL = 0 # Program header table entry unused +PT_LOAD = 1 # Loadable program segment +PT_DYNAMIC = 2 # Dynamic linking information +PT_INTERP = 3 # Program interpreter +PT_NOTE = 4 # Auxiliary information +PT_SHLIB = 5 # Reserved +PT_PHDR = 6 # Entry for header table itself +PT_TLS = 7 # Thread-local storage segment +PT_NUM = 8 # Number of defined types +PT_LOOS = 0x60000000 # Start of OS-specific +PT_GNU_EH_FRAME = 0x6474e550 # GCC .eh_frame_hdr segment +PT_GNU_STACK = 0x6474e551 # Indicates stack executability +PT_LOSUNW = 0x6ffffffa +PT_SUNWBSS = 0x6ffffffa # Sun Specific segment +PT_SUNWSTACK = 0x6ffffffb # Stack segment +PT_HISUNW = 0x6fffffff +PT_HIOS = 0x6fffffff # End of OS-specific +PT_LOPROC = 0x70000000 # Start of processor-specific +PT_HIPROC = 0x7fffffff # End of processor-specific + +# Legal values for p_flags (segment flags). + +PF_X = (1 << 0) # Segment is executable +PF_W = (1 << 1) # Segment is writable +PF_R = (1 << 2) # Segment is readable +PF_MASKOS = 0x0ff00000 # OS-specific +PF_MASKPROC = 0xf0000000 # Processor-specific + +# Legal values for note segment descriptor types for core files. + +NT_PRSTATUS = 1 # Contains copy of prstatus struct +NT_FPREGSET = 2 # Contains copy of fpregset struct +NT_PRPSINFO = 3 # Contains copy of prpsinfo struct +NT_PRXREG = 4 # Contains copy of prxregset struct +NT_TASKSTRUCT = 4 # Contains copy of task structure +NT_PLATFORM = 5 # String from sysinfo(SI_PLATFORM) +NT_AUXV = 6 # Contains copy of auxv array +NT_GWINDOWS = 7 # Contains copy of gwindows struct +NT_ASRS = 8 # Contains copy of asrset struct +NT_PSTATUS = 10 # Contains copy of pstatus struct +NT_PSINFO = 13 # Contains copy of psinfo struct +NT_PRCRED = 14 # Contains copy of prcred struct +NT_UTSNAME = 15 # Contains copy of utsname struct +NT_LWPSTATUS = 16 # Contains copy of lwpstatus struct +NT_LWPSINFO = 17 # Contains copy of lwpinfo struct +NT_PRFPXREG = 20 # Contains copy of fprxregset struct + +# Legal values for the note segment descriptor types for object files. + +NT_VERSION = 1 # Contains a version string. + +# Legal values for ST_BIND subfield of st_info (symbol binding). +# bind = Sym.info >> 4 +# val = Sym.info 0xf + +STB_LOCAL = 0 # Local symbol +STB_GLOBAL = 1 # Global symbol +STB_WEAK = 2 # Weak symbol +STB_NUM = 3 # Number of defined types. +STB_LOOS = 10 # Start of OS-specific +STB_HIOS = 12 # End of OS-specific +STB_LOPROC = 13 # Start of processor-specific +STB_HIPROC = 15 # End of processor-specific + +#Legal values for ST_TYPE subfield of st_info (symbol type). + +STT_NOTYPE = 0 # Symbol type is unspecified +STT_OBJECT = 1 # Symbol is a data object +STT_FUNC = 2 # Symbol is a code object +STT_SECTION = 3 # Symbol associated with a section +STT_FILE = 4 # Symbol's name is file name +STT_COMMON = 5 # Symbol is a common data object +STT_TLS = 6 # Symbol is thread-local data object*/ +STT_NUM = 7 # Number of defined types. +STT_LOOS = 10 # Start of OS-specific +STT_GNU_IFUNC = 10 # Symbol is indirect code object +STT_HIOS = 12 # End of OS-specific +STT_LOPROC = 13 # Start of processor-specific +STT_HIPROC = 15 # End of processor-specific + +# Legal values for d_tag (dynamic entry type). + +DT_NULL = 0 # Marks end of dynamic section +DT_NEEDED = 1 # Name of needed library +DT_PLTRELSZ = 2 # Size in bytes of PLT relocs +DT_PLTGOT = 3 # Processor defined value +DT_HASH = 4 # Address of symbol hash table +DT_STRTAB = 5 # Address of string table +DT_SYMTAB = 6 # Address of symbol table +DT_RELA = 7 # Address of Rela relocs +DT_RELASZ = 8 # Total size of Rela relocs +DT_RELAENT = 9 # Size of one Rela reloc +DT_STRSZ = 10 # Size of string table +DT_SYMENT = 11 # Size of one symbol table entry +DT_INIT = 12 # Address of init function +DT_FINI = 13 # Address of termination function +DT_SONAME = 14 # Name of shared object +DT_RPATH = 15 # Library search path (deprecated) +DT_SYMBOLIC = 16 # Start symbol search here +DT_REL = 17 # Address of Rel relocs +DT_RELSZ = 18 # Total size of Rel relocs +DT_RELENT = 19 # Size of one Rel reloc +DT_PLTREL = 20 # Type of reloc in PLT +DT_DEBUG = 21 # For debugging; unspecified +DT_TEXTREL = 22 # Reloc might modify .text +DT_JMPREL = 23 # Address of PLT relocs +DT_BIND_NOW = 24 # Process relocations of object +DT_INIT_ARRAY = 25 # Array with addresses of init fct +DT_FINI_ARRAY = 26 # Array with addresses of fini fct +DT_INIT_ARRAYSZ = 27 # Size in bytes of DT_INIT_ARRAY +DT_FINI_ARRAYSZ = 28 # Size in bytes of DT_FINI_ARRAY +DT_RUNPATH = 29 # Library search path +DT_FLAGS = 30 # Flags for the object being loaded +DT_ENCODING = 32 # Start of encoded range +DT_PREINIT_ARRAY = 32 # Array with addresses of preinit fct +DT_PREINIT_ARRAYSZ = 33 # size in bytes of DT_PREINIT_ARRAY +DT_NUM = 34 # Number used +DT_LOOS = 0x6000000d # Start of OS-specific +DT_HIOS = 0x6ffff000 # End of OS-specific +DT_LOPROC = 0x70000000 # Start of processor-specific +DT_HIPROC = 0x7fffffff # End of processor-specific +#DT_PROCNUM = DT_MIPS_NUM # Most used by any processor + +# DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the +# Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's +# approach. +DT_VALRNGLO = 0x6ffffd00 +DT_GNU_PRELINKED = 0x6ffffdf5 # Prelinking timestamp +DT_GNU_CONFLICTSZ = 0x6ffffdf6 # Size of conflict section +DT_GNU_LIBLISTSZ = 0x6ffffdf7 # Size of library list +DT_CHECKSUM = 0x6ffffdf8 +DT_PLTPADSZ = 0x6ffffdf9 +DT_MOVEENT = 0x6ffffdfa +DT_MOVESZ = 0x6ffffdfb +DT_FEATURE_1 = 0x6ffffdfc # Feature selection (DTF_*). +DT_POSFLAG_1 = 0x6ffffdfd # Flags for DT_* entries, effecting the following DT_* entry. +DT_SYMINSZ = 0x6ffffdfe # Size of syminfo table (in bytes) +DT_SYMINENT = 0x6ffffdff # Entry size of syminfo +DT_VALRNGHI = 0x6ffffdff +DT_VALNUM = 12 + +# DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the +# Dyn.d_un.d_ptr field of the Elf*_Dyn structure. +# +# If any adjustment is made to the ELF object after it has been +# built these entries will need to be adjusted. +DT_ADDRRNGLO = 0x6ffffe00 +DT_GNU_CONFLICT = 0x6ffffef8 # Start of conflict section +DT_GNU_LIBLIST = 0x6ffffef9 # Library list +DT_CONFIG = 0x6ffffefa # Configuration information. +DT_DEPAUDIT = 0x6ffffefb # Dependency auditing. +DT_AUDIT = 0x6ffffefc # Object auditing. +DT_PLTPAD = 0x6ffffefd # PLT padding. +DT_MOVETAB = 0x6ffffefe # Move table. +DT_SYMINFO = 0x6ffffeff # Syminfo table. +DT_ADDRRNGHI = 0x6ffffeff +DT_ADDRNUM = 10 + +# The versioning entry types. The next are defined as part of the +# GNU extension. +DT_VERSYM = 0x6ffffff0 + +DT_RELACOUNT = 0x6ffffff9 +DT_RELCOUNT = 0x6ffffffa + +# These were chosen by Sun. +DT_FLAGS_1 = 0x6ffffffb # State flags, see DF_1_* below. +DT_VERDEF = 0x6ffffffc # Address of version definition table +DT_VERDEFNUM = 0x6ffffffd # Number of version definitions +DT_VERNEED = 0x6ffffffe # Address of table with needed versions +DT_VERNEEDNUM = 0x6fffffff # Number of needed versions +DT_VERSIONTAGNUM = 16 + +# Sun added these machine-independent extensions in the "processor-specific" +# range. Be compatible. +DT_AUXILIARY = 0x7ffffffd # Shared object to load before self +DT_FILTER = 0x7fffffff # Shared object to get values from +DT_EXTRANUM = 3 + +# Values of `d_un.d_val' in the DT_FLAGS entry. +DF_ORIGIN = 0x00000001 # Object may use DF_ORIGIN +DF_SYMBOLIC = 0x00000002 # Symbol resolutions starts here +DF_TEXTREL = 0x00000004 # Object contains text relocations +DF_BIND_NOW = 0x00000008 # No lazy binding for this object +DF_STATIC_TLS = 0x00000010 # Module uses the static TLS model + +# State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 +# entry in the dynamic section. +DF_1_NOW = 0x00000001 # Set RTLD_NOW for this object. +DF_1_GLOBAL = 0x00000002 # Set RTLD_GLOBAL for this object. +DF_1_GROUP = 0x00000004 # Set RTLD_GROUP for this object. +DF_1_NODELETE = 0x00000008 # Set RTLD_NODELETE for this object. +DF_1_LOADFLTR = 0x00000010 # Trigger filtee loading at runtime. +DF_1_INITFIRST = 0x00000020 # Set RTLD_INITFIRST for this object +DF_1_NOOPEN = 0x00000040 # Set RTLD_NOOPEN for this object. +DF_1_ORIGIN = 0x00000080 # $ORIGIN must be handled. +DF_1_DIRECT = 0x00000100 # Direct binding enabled. +DF_1_TRANS = 0x00000200 +DF_1_INTERPOSE = 0x00000400 # Object is used to interpose. +DF_1_NODEFLIB = 0x00000800 # Ignore default lib search path. +DF_1_NODUMP = 0x00001000 # Object can't be dldump'ed. +DF_1_CONFALT = 0x00002000 # Configuration alternative created. +DF_1_ENDFILTEE = 0x00004000 # Filtee terminates filters search. +DF_1_DISPRELDNE = 0x00008000 # Disp reloc applied at build time. +DF_1_DISPRELPND = 0x00010000 # Disp reloc applied at run-time. + +# Flags for the feature selection in DT_FEATURE_1. +DTF_1_PARINIT = 0x00000001 +DTF_1_CONFEXP = 0x00000002 + +# Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. +DF_P1_LAZYLOAD = 0x00000001 # Lazyload following object. +DF_P1_GROUPPERM = 0x00000002 # Symbols from next object are not generally available. + +# GNU Versioning +VER_FLG_BASE = 1 # Version of the file itself, must not be used to match symbols +VER_FLG_WEAK = 2 # Reference to this version is weak +VER_NEED_CURRENT = 1 # Versioning implementation number + +# Relocs + +# Motorola 68k relocations + +R_68K_NONE = 0 # No reloc +R_68K_32 = 1 # Direct 32 bit +R_68K_16 = 2 # Direct 16 bit +R_68K_8 = 3 # Direct 8 bit +R_68K_PC32 = 4 # PC relative 32 bit +R_68K_PC16 = 5 # PC relative 16 bit +R_68K_PC8 = 6 # PC relative 8 bit +R_68K_GOT32 = 7 # 32 bit PC relative GOT entry +R_68K_GOT16 = 8 # 16 bit PC relative GOT entry +R_68K_GOT8 = 9 # 8 bit PC relative GOT entry +R_68K_GOT32O = 10 # 32 bit GOT offset +R_68K_GOT16O = 11 # 16 bit GOT offset +R_68K_GOT8O = 12 # 8 bit GOT offset +R_68K_PLT32 = 13 # 32 bit PC relative PLT address +R_68K_PLT16 = 14 # 16 bit PC relative PLT address +R_68K_PLT8 = 15 # 8 bit PC relative PLT address +R_68K_PLT32O = 16 # 32 bit PLT offset +R_68K_PLT16O = 17 # 16 bit PLT offset +R_68K_PLT8O = 18 # 8 bit PLT offset +R_68K_COPY = 19 # Copy symbol at runtime +R_68K_GLOB_DAT = 20 # Create GOT entry +R_68K_JMP_SLOT = 21 # Create PLT entry +R_68K_RELATIVE = 22 # Adjust by program base +R_68K_TLS_GD32 = 25 # 32 bit GOT offset for GD +R_68K_TLS_GD16 = 26 # 16 bit GOT offset for GD +R_68K_TLS_GD8 = 27 # 8 bit GOT offset for GD +R_68K_TLS_LDM32 = 28 # 32 bit GOT offset for LDM +R_68K_TLS_LDM16 = 29 # 16 bit GOT offset for LDM +R_68K_TLS_LDM8 = 30 # 8 bit GOT offset for LDM +R_68K_TLS_LDO32 = 31 # 32 bit module-relative offset +R_68K_TLS_LDO16 = 32 # 16 bit module-relative offset +R_68K_TLS_LDO8 = 33 # 8 bit module-relative offset +R_68K_TLS_IE32 = 34 # 32 bit GOT offset for IE +R_68K_TLS_IE16 = 35 # 16 bit GOT offset for IE +R_68K_TLS_IE8 = 36 # 8 bit GOT offset for IE +R_68K_TLS_LE32 = 37 # 32 bit offset relative to static TLS block +R_68K_TLS_LE16 = 38 # 16 bit offset relative to static TLS block +R_68K_TLS_LE8 = 39 # 8 bit offset relative to static TLS block +R_68K_TLS_DTPMOD32 = 40 # 32 bit module number +R_68K_TLS_DTPREL32 = 41 # 32 bit module-relative offset +R_68K_TLS_TPREL32 = 42 # 32 bit TP-relative offset +# Keep this the last entry. +R_68K_NUM = 43 + +# Intel 80386 relocations + +R_386_NONE = 0 # No reloc +R_386_32 = 1 # Direct 32 bit +R_386_PC32 = 2 # PC relative 32 bit +R_386_GOT32 = 3 # 32 bit GOT entry +R_386_PLT32 = 4 # 32 bit PLT address +R_386_COPY = 5 # Copy symbol at runtime +R_386_GLOB_DAT = 6 # Create GOT entry +R_386_JMP_SLOT = 7 # Create PLT entry +R_386_RELATIVE = 8 # Adjust by program base +R_386_GOTOFF = 9 # 32 bit offset to GOT +R_386_GOTPC = 10 # 32 bit PC relative offset to GOT +R_386_32PLT = 11 +R_386_TLS_TPOFF = 14 # Offset in static TLS block +R_386_TLS_IE = 15 # Address of GOT entry for static TLS block offset +R_386_TLS_GOTIE = 16 # GOT entry for static TLS block offset +R_386_TLS_LE = 17 # Offset relative to static TLS block +R_386_TLS_GD = 18 # Direct 32 bit for GNU version of general dynamic thread local data +R_386_TLS_LDM = 19 # Direct 32 bit for GNU version of local dynamic thread local data in LE code +R_386_16 = 20 +R_386_PC16 = 21 +R_386_8 = 22 +R_386_PC8 = 23 +R_386_TLS_GD_32 = 24 # Direct 32 bit for general dynamic thread local data +R_386_TLS_GD_PUSH = 25 # Tag for pushl in GD TLS code +R_386_TLS_GD_CALL = 26 # Relocation for call to __tls_get_addr() +R_386_TLS_GD_POP = 27 # Tag for popl in GD TLS code +R_386_TLS_LDM_32 = 28 # Direct 32 bit for local dynamic thread local data in LE code +R_386_TLS_LDM_PUSH = 29 # Tag for pushl in LDM TLS code +R_386_TLS_LDM_CALL = 30 # Relocation for call to __tls_get_addr() in LDM code +R_386_TLS_LDM_POP = 31 # Tag for popl in LDM TLS code +R_386_TLS_LDO_32 = 32 # Offset relative to TLS block +R_386_TLS_IE_32 = 33 # GOT entry for negated static TLS block offset +R_386_TLS_LE_32 = 34 # Negated offset relative to static TLS block +R_386_TLS_DTPMOD32 = 35 # ID of module containing symbol +R_386_TLS_DTPOFF32 = 36 # Offset in TLS block +R_386_TLS_TPOFF32 = 37 # Negated offset in static TLS block +# 38? +R_386_TLS_GOTDESC = 39 # GOT offset for TLS descriptor. +R_386_TLS_DESC_CALL = 40 # Marker of call through TLS descriptor for relaxation. +R_386_TLS_DESC = 41 # TLS descriptor containing pointer to code and to argument, returning the TLS offset for the symbol. +R_386_IRELATIVE = 42 # Adjust indirectly by program base +# Keep this the last entry. +R_386_NUM = 43 + +# SUN SPARC relocations + +R_SPARC_NONE = 0 # No reloc +R_SPARC_8 = 1 # Direct 8 bit +R_SPARC_16 = 2 # Direct 16 bit +R_SPARC_32 = 3 # Direct 32 bit +R_SPARC_DISP8 = 4 # PC relative 8 bit +R_SPARC_DISP16 = 5 # PC relative 16 bit +R_SPARC_DISP32 = 6 # PC relative 32 bit +R_SPARC_WDISP30 = 7 # PC relative 30 bit shifted +R_SPARC_WDISP22 = 8 # PC relative 22 bit shifted +R_SPARC_HI22 = 9 # High 22 bit +R_SPARC_22 = 10 # Direct 22 bit +R_SPARC_13 = 11 # Direct 13 bit +R_SPARC_LO10 = 12 # Truncated 10 bit +R_SPARC_GOT10 = 13 # Truncated 10 bit GOT entry +R_SPARC_GOT13 = 14 # 13 bit GOT entry +R_SPARC_GOT22 = 15 # 22 bit GOT entry shifted +R_SPARC_PC10 = 16 # PC relative 10 bit truncated +R_SPARC_PC22 = 17 # PC relative 22 bit shifted +R_SPARC_WPLT30 = 18 # 30 bit PC relative PLT address +R_SPARC_COPY = 19 # Copy symbol at runtime +R_SPARC_GLOB_DAT = 20 # Create GOT entry +R_SPARC_JMP_SLOT = 21 # Create PLT entry +R_SPARC_RELATIVE = 22 # Adjust by program base +R_SPARC_UA32 = 23 # Direct 32 bit unaligned + +# Additional Sparc64 relocs. + +R_SPARC_PLT32 = 24 # Direct 32 bit ref to PLT entry +R_SPARC_HIPLT22 = 25 # High 22 bit PLT entry +R_SPARC_LOPLT10 = 26 # Truncated 10 bit PLT entry +R_SPARC_PCPLT32 = 27 # PC rel 32 bit ref to PLT entry +R_SPARC_PCPLT22 = 28 # PC rel high 22 bit PLT entry +R_SPARC_PCPLT10 = 29 # PC rel trunc 10 bit PLT entry +R_SPARC_10 = 30 # Direct 10 bit +R_SPARC_11 = 31 # Direct 11 bit +R_SPARC_64 = 32 # Direct 64 bit +R_SPARC_OLO10 = 33 # 10bit with secondary 13bit addend +R_SPARC_HH22 = 34 # Top 22 bits of direct 64 bit +R_SPARC_HM10 = 35 # High middle 10 bits of ... +R_SPARC_LM22 = 36 # Low middle 22 bits of ... +R_SPARC_PC_HH22 = 37 # Top 22 bits of pc rel 64 bit +R_SPARC_PC_HM10 = 38 # High middle 10 bit of ... +R_SPARC_PC_LM22 = 39 # Low miggle 22 bits of ... +R_SPARC_WDISP16 = 40 # PC relative 16 bit shifted +R_SPARC_WDISP19 = 41 # PC relative 19 bit shifted +R_SPARC_GLOB_JMP = 42 # was part of v9 ABI but was removed +R_SPARC_7 = 43 # Direct 7 bit +R_SPARC_5 = 44 # Direct 5 bit +R_SPARC_6 = 45 # Direct 6 bit +R_SPARC_DISP64 = 46 # PC relative 64 bit +R_SPARC_PLT64 = 47 # Direct 64 bit ref to PLT entry +R_SPARC_HIX22 = 48 # High 22 bit complemented +R_SPARC_LOX10 = 49 # Truncated 11 bit complemented +R_SPARC_H44 = 50 # Direct high 12 of 44 bit +R_SPARC_M44 = 51 # Direct mid 22 of 44 bit +R_SPARC_L44 = 52 # Direct low 10 of 44 bit +R_SPARC_REGISTER = 53 # Global register usage +R_SPARC_UA64 = 54 # Direct 64 bit unaligned +R_SPARC_UA16 = 55 # Direct 16 bit unaligned +R_SPARC_TLS_GD_HI22 = 56 +R_SPARC_TLS_GD_LO10 = 57 +R_SPARC_TLS_GD_ADD = 58 +R_SPARC_TLS_GD_CALL = 59 +R_SPARC_TLS_LDM_HI22 = 60 +R_SPARC_TLS_LDM_LO10 = 61 +R_SPARC_TLS_LDM_ADD = 62 +R_SPARC_TLS_LDM_CALL = 63 +R_SPARC_TLS_LDO_HIX22 = 64 +R_SPARC_TLS_LDO_LOX10 = 65 +R_SPARC_TLS_LDO_ADD = 66 +R_SPARC_TLS_IE_HI22 = 67 +R_SPARC_TLS_IE_LO10 = 68 +R_SPARC_TLS_IE_LD = 69 +R_SPARC_TLS_IE_LDX = 70 +R_SPARC_TLS_IE_ADD = 71 +R_SPARC_TLS_LE_HIX22 = 72 +R_SPARC_TLS_LE_LOX10 = 73 +R_SPARC_TLS_DTPMOD32 = 74 +R_SPARC_TLS_DTPMOD64 = 75 +R_SPARC_TLS_DTPOFF32 = 76 +R_SPARC_TLS_DTPOFF64 = 77 +R_SPARC_TLS_TPOFF32 = 78 +R_SPARC_TLS_TPOFF64 = 79 +R_SPARC_GOTDATA_HIX22 = 80 +R_SPARC_GOTDATA_LOX10 = 81 +R_SPARC_GOTDATA_OP_HIX22 = 82 +R_SPARC_GOTDATA_OP_LOX10 = 83 +R_SPARC_GOTDATA_OP = 84 +R_SPARC_H34 = 85 +R_SPARC_SIZE32 = 86 +R_SPARC_SIZE64 = 87 +R_SPARC_JMP_IREL = 248 +R_SPARC_IRELATIVE = 249 +R_SPARC_GNU_VTINHERIT = 250 +R_SPARC_GNU_VTENTRY = 251 +R_SPARC_REV32 = 252 +# Keep this the last entry. +R_SPARC_NUM = 253 + +# MIPS R3000 relocations + +R_MIPS_NONE = 0 # No reloc +R_MIPS_16 = 1 # Direct 16 bit +R_MIPS_32 = 2 # Direct 32 bit +R_MIPS_REL32 = 3 # PC relative 32 bit +R_MIPS_26 = 4 # Direct 26 bit shifted +R_MIPS_HI16 = 5 # High 16 bit +R_MIPS_LO16 = 6 # Low 16 bit +R_MIPS_GPREL16 = 7 # GP relative 16 bit +R_MIPS_LITERAL = 8 # 16 bit literal entry +R_MIPS_GOT16 = 9 # 16 bit GOT entry +R_MIPS_PC16 = 10 # PC relative 16 bit +R_MIPS_CALL16 = 11 # 16 bit GOT entry for function +R_MIPS_GPREL32 = 12 # GP relative 32 bit + +R_MIPS_SHIFT5 = 16 +R_MIPS_SHIFT6 = 17 +R_MIPS_64 = 18 +R_MIPS_GOT_DISP = 19 +R_MIPS_GOT_PAGE = 20 +R_MIPS_GOT_OFST = 21 +R_MIPS_GOT_HI16 = 22 +R_MIPS_GOT_LO16 = 23 +R_MIPS_SUB = 24 +R_MIPS_INSERT_A = 25 +R_MIPS_INSERT_B = 26 +R_MIPS_DELETE = 27 +R_MIPS_HIGHER = 28 +R_MIPS_HIGHEST = 29 +R_MIPS_CALL_HI16 = 30 +R_MIPS_CALL_LO16 = 31 +R_MIPS_SCN_DISP = 32 +R_MIPS_REL16 = 33 +R_MIPS_ADD_IMMEDIATE = 34 +R_MIPS_PJUMP = 35 +R_MIPS_RELGOT = 36 +R_MIPS_JALR = 37 +R_MIPS_TLS_DTPMOD32 = 38 # Module number 32 bit +R_MIPS_TLS_DTPREL32 = 39 # Module-relative offset 32 bit +R_MIPS_TLS_DTPMOD64 = 40 # Module number 64 bit +R_MIPS_TLS_DTPREL64 = 41 # Module-relative offset 64 bit +R_MIPS_TLS_GD = 42 # 16 bit GOT offset for GD +R_MIPS_TLS_LDM = 43 # 16 bit GOT offset for LDM +R_MIPS_TLS_DTPREL_HI16 = 44 # Module-relative offset, high 16 bits +R_MIPS_TLS_DTPREL_LO16 = 45 # Module-relative offset, low 16 bits +R_MIPS_TLS_GOTTPREL = 46 # 16 bit GOT offset for IE +R_MIPS_TLS_TPREL32 = 47 # TP-relative offset, 32 bit +R_MIPS_TLS_TPREL64 = 48 # TP-relative offset, 64 bit +R_MIPS_TLS_TPREL_HI16 = 49 # TP-relative offset, high 16 bits +R_MIPS_TLS_TPREL_LO16 = 50 # TP-relative offset, low 16 bits +R_MIPS_GLOB_DAT = 51 +R_MIPS_COPY = 126 +R_MIPS_JUMP_SLOT = 127 +# Keep this the last entry. +R_MIPS_NUM = 128 + +# HPPA relocations + +R_PARISC_NONE = 0 # No reloc. +R_PARISC_DIR32 = 1 # Direct 32-bit reference. +R_PARISC_DIR21L = 2 # Left 21 bits of eff. address. +R_PARISC_DIR17R = 3 # Right 17 bits of eff. address. +R_PARISC_DIR17F = 4 # 17 bits of eff. address. +R_PARISC_DIR14R = 6 # Right 14 bits of eff. address. +R_PARISC_PCREL32 = 9 # 32-bit rel. address. +R_PARISC_PCREL21L = 10 # Left 21 bits of rel. address. +R_PARISC_PCREL17R = 11 # Right 17 bits of rel. address. +R_PARISC_PCREL17F = 12 # 17 bits of rel. address. +R_PARISC_PCREL14R = 14 # Right 14 bits of rel. address. +R_PARISC_DPREL21L = 18 # Left 21 bits of rel. address. +R_PARISC_DPREL14R = 22 # Right 14 bits of rel. address. +R_PARISC_GPREL21L = 26 # GP-relative, left 21 bits. +R_PARISC_GPREL14R = 30 # GP-relative, right 14 bits. +R_PARISC_LTOFF21L = 34 # LT-relative, left 21 bits. +R_PARISC_LTOFF14R = 38 # LT-relative, right 14 bits. +R_PARISC_SECREL32 = 41 # 32 bits section rel. address. +R_PARISC_SEGBASE = 48 # No relocation, set segment base. +R_PARISC_SEGREL32 = 49 # 32 bits segment rel. address. +R_PARISC_PLTOFF21L = 50 # PLT rel. address, left 21 bits. +R_PARISC_PLTOFF14R = 54 # PLT rel. address, right 14 bits. +R_PARISC_LTOFF_FPTR32 = 57 # 32 bits LT-rel. function pointer. +R_PARISC_LTOFF_FPTR21L = 58 # LT-rel. fct ptr, left 21 bits. +R_PARISC_LTOFF_FPTR14R = 62 # LT-rel. fct ptr, right 14 bits. +R_PARISC_FPTR64 = 64 # 64 bits function address. +R_PARISC_PLABEL32 = 65 # 32 bits function address. +R_PARISC_PLABEL21L = 66 # Left 21 bits of fdesc address. +R_PARISC_PLABEL14R = 70 # Right 14 bits of fdesc address. +R_PARISC_PCREL64 = 72 # 64 bits PC-rel. address. +R_PARISC_PCREL22F = 74 # 22 bits PC-rel. address. +R_PARISC_PCREL14WR = 75 # PC-rel. address, right 14 bits. +R_PARISC_PCREL14DR = 76 # PC rel. address, right 14 bits. +R_PARISC_PCREL16F = 77 # 16 bits PC-rel. address. +R_PARISC_PCREL16WF = 78 # 16 bits PC-rel. address. +R_PARISC_PCREL16DF = 79 # 16 bits PC-rel. address. +R_PARISC_DIR64 = 80 # 64 bits of eff. address. +R_PARISC_DIR14WR = 83 # 14 bits of eff. address. +R_PARISC_DIR14DR = 84 # 14 bits of eff. address. +R_PARISC_DIR16F = 85 # 16 bits of eff. address. +R_PARISC_DIR16WF = 86 # 16 bits of eff. address. +R_PARISC_DIR16DF = 87 # 16 bits of eff. address. +R_PARISC_GPREL64 = 88 # 64 bits of GP-rel. address. +R_PARISC_GPREL14WR = 91 # GP-rel. address, right 14 bits. +R_PARISC_GPREL14DR = 92 # GP-rel. address, right 14 bits. +R_PARISC_GPREL16F = 93 # 16 bits GP-rel. address. +R_PARISC_GPREL16WF = 94 # 16 bits GP-rel. address. +R_PARISC_GPREL16DF = 95 # 16 bits GP-rel. address. +R_PARISC_LTOFF64 = 96 # 64 bits LT-rel. address. +R_PARISC_LTOFF14WR = 99 # LT-rel. address, right 14 bits. +R_PARISC_LTOFF14DR = 100 # LT-rel. address, right 14 bits. +R_PARISC_LTOFF16F = 101 # 16 bits LT-rel. address. +R_PARISC_LTOFF16WF = 102 # 16 bits LT-rel. address. +R_PARISC_LTOFF16DF = 103 # 16 bits LT-rel. address. +R_PARISC_SECREL64 = 104 # 64 bits section rel. address. +R_PARISC_SEGREL64 = 112 # 64 bits segment rel. address. +R_PARISC_PLTOFF14WR = 115 # PLT-rel. address, right 14 bits. +R_PARISC_PLTOFF14DR = 116 # PLT-rel. address, right 14 bits. +R_PARISC_PLTOFF16F = 117 # 16 bits LT-rel. address. +R_PARISC_PLTOFF16WF = 118 # 16 bits PLT-rel. address. +R_PARISC_PLTOFF16DF = 119 # 16 bits PLT-rel. address. +R_PARISC_LTOFF_FPTR64 = 120 # 64 bits LT-rel. function ptr. +R_PARISC_LTOFF_FPTR14WR = 123 # LT-rel. fct. ptr., right 14 bits. +R_PARISC_LTOFF_FPTR14DR = 124 # LT-rel. fct. ptr., right 14 bits. +R_PARISC_LTOFF_FPTR16F = 125 # 16 bits LT-rel. function ptr. +R_PARISC_LTOFF_FPTR16WF = 126 # 16 bits LT-rel. function ptr. +R_PARISC_LTOFF_FPTR16DF = 127 # 16 bits LT-rel. function ptr. +R_PARISC_LORESERVE = 128 +R_PARISC_COPY = 128 # Copy relocation. +R_PARISC_IPLT = 129 # Dynamic reloc, imported PLT +R_PARISC_EPLT = 130 # Dynamic reloc, exported PLT +R_PARISC_TPREL32 = 153 # 32 bits TP-rel. address. +R_PARISC_TPREL21L = 154 # TP-rel. address, left 21 bits. +R_PARISC_TPREL14R = 158 # TP-rel. address, right 14 bits. +R_PARISC_LTOFF_TP21L = 162 # LT-TP-rel. address, left 21 bits. +R_PARISC_LTOFF_TP14R = 166 # LT-TP-rel. address, right 14 bits.*/ +R_PARISC_LTOFF_TP14F = 167 # 14 bits LT-TP-rel. address. +R_PARISC_TPREL64 = 216 # 64 bits TP-rel. address. +R_PARISC_TPREL14WR = 219 # TP-rel. address, right 14 bits. +R_PARISC_TPREL14DR = 220 # TP-rel. address, right 14 bits. +R_PARISC_TPREL16F = 221 # 16 bits TP-rel. address. +R_PARISC_TPREL16WF = 222 # 16 bits TP-rel. address. +R_PARISC_TPREL16DF = 223 # 16 bits TP-rel. address. +R_PARISC_LTOFF_TP64 = 224 # 64 bits LT-TP-rel. address. +R_PARISC_LTOFF_TP14WR = 227 # LT-TP-rel. address, right 14 bits.*/ +R_PARISC_LTOFF_TP14DR = 228 # LT-TP-rel. address, right 14 bits.*/ +R_PARISC_LTOFF_TP16F = 229 # 16 bits LT-TP-rel. address. +R_PARISC_LTOFF_TP16WF = 230 # 16 bits LT-TP-rel. address. +R_PARISC_LTOFF_TP16DF = 231 # 16 bits LT-TP-rel. address. +R_PARISC_GNU_VTENTRY = 232 +R_PARISC_GNU_VTINHERIT = 233 +R_PARISC_TLS_GD21L = 234 # GD 21-bit left. +R_PARISC_TLS_GD14R = 235 # GD 14-bit right. +R_PARISC_TLS_GDCALL = 236 # GD call to __t_g_a. +R_PARISC_TLS_LDM21L = 237 # LD module 21-bit left. +R_PARISC_TLS_LDM14R = 238 # LD module 14-bit right. +R_PARISC_TLS_LDMCALL = 239 # LD module call to __t_g_a. +R_PARISC_TLS_LDO21L = 240 # LD offset 21-bit left. +R_PARISC_TLS_LDO14R = 241 # LD offset 14-bit right. +R_PARISC_TLS_DTPMOD32 = 242 # DTP module 32-bit. +R_PARISC_TLS_DTPMOD64 = 243 # DTP module 64-bit. +R_PARISC_TLS_DTPOFF32 = 244 # DTP offset 32-bit. +R_PARISC_TLS_DTPOFF64 = 245 # DTP offset 32-bit. +R_PARISC_TLS_LE21L = R_PARISC_TPREL21L +R_PARISC_TLS_LE14R = R_PARISC_TPREL14R +R_PARISC_TLS_IE21L = R_PARISC_LTOFF_TP21L +R_PARISC_TLS_IE14R = R_PARISC_LTOFF_TP14R +R_PARISC_TLS_TPREL32 = R_PARISC_TPREL32 +R_PARISC_TLS_TPREL64 = R_PARISC_TPREL64 +R_PARISC_HIRESERVE = 255 + +# Alpha relocations + +R_ALPHA_NONE = 0 # No reloc +R_ALPHA_REFLONG = 1 # Direct 32 bit +R_ALPHA_REFQUAD = 2 # Direct 64 bit +R_ALPHA_GPREL32 = 3 # GP relative 32 bit +R_ALPHA_LITERAL = 4 # GP relative 16 bit w/optimization +R_ALPHA_LITUSE = 5 # Optimization hint for LITERAL +R_ALPHA_GPDISP = 6 # Add displacement to GP +R_ALPHA_BRADDR = 7 # PC+4 relative 23 bit shifted +R_ALPHA_HINT = 8 # PC+4 relative 16 bit shifted +R_ALPHA_SREL16 = 9 # PC relative 16 bit +R_ALPHA_SREL32 = 10 # PC relative 32 bit +R_ALPHA_SREL64 = 11 # PC relative 64 bit +R_ALPHA_GPRELHIGH = 17 # GP relative 32 bit, high 16 bits +R_ALPHA_GPRELLOW = 18 # GP relative 32 bit, low 16 bits +R_ALPHA_GPREL16 = 19 # GP relative 16 bit +R_ALPHA_COPY = 24 # Copy symbol at runtime +R_ALPHA_GLOB_DAT = 25 # Create GOT entry +R_ALPHA_JMP_SLOT = 26 # Create PLT entry +R_ALPHA_RELATIVE = 27 # Adjust by program base +R_ALPHA_TLS_GD_HI = 28 +R_ALPHA_TLSGD = 29 +R_ALPHA_TLS_LDM = 30 +R_ALPHA_DTPMOD64 = 31 +R_ALPHA_GOTDTPREL = 32 +R_ALPHA_DTPREL64 = 33 +R_ALPHA_DTPRELHI = 34 +R_ALPHA_DTPRELLO = 35 +R_ALPHA_DTPREL16 = 36 +R_ALPHA_GOTTPREL = 37 +R_ALPHA_TPREL64 = 38 +R_ALPHA_TPRELHI = 39 +R_ALPHA_TPRELLO = 40 +R_ALPHA_TPREL16 = 41 +# Keep this the last entry. +R_ALPHA_NUM = 46 + +# PowerPC relocations + +R_PPC_NONE = 0 +R_PPC_ADDR32 = 1 # 32bit absolute address +R_PPC_ADDR24 = 2 # 26bit address, 2 bits ignored. +R_PPC_ADDR16 = 3 # 16bit absolute address +R_PPC_ADDR16_LO = 4 # lower 16bit of absolute address +R_PPC_ADDR16_HI = 5 # high 16bit of absolute address +R_PPC_ADDR16_HA = 6 # adjusted high 16bit +R_PPC_ADDR14 = 7 # 16bit address, 2 bits ignored +R_PPC_ADDR14_BRTAKEN = 8 +R_PPC_ADDR14_BRNTAKEN = 9 +R_PPC_REL24 = 10 # PC relative 26 bit +R_PPC_REL14 = 11 # PC relative 16 bit +R_PPC_REL14_BRTAKEN = 12 +R_PPC_REL14_BRNTAKEN = 13 +R_PPC_GOT16 = 14 +R_PPC_GOT16_LO = 15 +R_PPC_GOT16_HI = 16 +R_PPC_GOT16_HA = 17 +R_PPC_PLTREL24 = 18 +R_PPC_COPY = 19 +R_PPC_GLOB_DAT = 20 +R_PPC_JMP_SLOT = 21 +R_PPC_RELATIVE = 22 +R_PPC_LOCAL24PC = 23 +R_PPC_UADDR32 = 24 +R_PPC_UADDR16 = 25 +R_PPC_REL32 = 26 +R_PPC_PLT32 = 27 +R_PPC_PLTREL32 = 28 +R_PPC_PLT16_LO = 29 +R_PPC_PLT16_HI = 30 +R_PPC_PLT16_HA = 31 +R_PPC_SDAREL16 = 32 +R_PPC_SECTOFF = 33 +R_PPC_SECTOFF_LO = 34 +R_PPC_SECTOFF_HI = 35 +R_PPC_SECTOFF_HA = 36 + +# PowerPC relocations defined for the TLS access ABI. +R_PPC_TLS = 67 # none (sym+add)@tls +R_PPC_DTPMOD32 = 68 # word32 (sym+add)@dtpmod +R_PPC_TPREL16 = 69 # half16* (sym+add)@tprel +R_PPC_TPREL16_LO = 70 # half16 (sym+add)@tprel@l +R_PPC_TPREL16_HI = 71 # half16 (sym+add)@tprel@h +R_PPC_TPREL16_HA = 72 # half16 (sym+add)@tprel@ha +R_PPC_TPREL32 = 73 # word32 (sym+add)@tprel +R_PPC_DTPREL16 = 74 # half16* (sym+add)@dtprel +R_PPC_DTPREL16_LO = 75 # half16 (sym+add)@dtprel@l +R_PPC_DTPREL16_HI = 76 # half16 (sym+add)@dtprel@h +R_PPC_DTPREL16_HA = 77 # half16 (sym+add)@dtprel@ha +R_PPC_DTPREL32 = 78 # word32 (sym+add)@dtprel +R_PPC_GOT_TLSGD16 = 79 # half16* (sym+add)@got@tlsgd +R_PPC_GOT_TLSGD16_LO = 80 # half16 (sym+add)@got@tlsgd@l +R_PPC_GOT_TLSGD16_HI = 81 # half16 (sym+add)@got@tlsgd@h +R_PPC_GOT_TLSGD16_HA = 82 # half16 (sym+add)@got@tlsgd@ha +R_PPC_GOT_TLSLD16 = 83 # half16* (sym+add)@got@tlsld +R_PPC_GOT_TLSLD16_LO = 84 # half16 (sym+add)@got@tlsld@l +R_PPC_GOT_TLSLD16_HI = 85 # half16 (sym+add)@got@tlsld@h +R_PPC_GOT_TLSLD16_HA = 86 # half16 (sym+add)@got@tlsld@ha +R_PPC_GOT_TPREL16 = 87 # half16* (sym+add)@got@tprel +R_PPC_GOT_TPREL16_LO = 88 # half16 (sym+add)@got@tprel@l +R_PPC_GOT_TPREL16_HI = 89 # half16 (sym+add)@got@tprel@h +R_PPC_GOT_TPREL16_HA = 90 # half16 (sym+add)@got@tprel@ha +R_PPC_GOT_DTPREL16 = 91 # half16* (sym+add)@got@dtprel +R_PPC_GOT_DTPREL16_LO = 92 # half16* (sym+add)@got@dtprel@l +R_PPC_GOT_DTPREL16_HI = 93 # half16* (sym+add)@got@dtprel@h +R_PPC_GOT_DTPREL16_HA = 94 # half16* (sym+add)@got@dtprel@ha + +# The remaining relocs are from the Embedded ELF ABI, and are not in the SVR4 ELF ABI. +R_PPC_EMB_NADDR32 = 101 +R_PPC_EMB_NADDR16 = 102 +R_PPC_EMB_NADDR16_LO = 103 +R_PPC_EMB_NADDR16_HI = 104 +R_PPC_EMB_NADDR16_HA = 105 +R_PPC_EMB_SDAI16 = 106 +R_PPC_EMB_SDA2I16 = 107 +R_PPC_EMB_SDA2REL = 108 +R_PPC_EMB_SDA21 = 109 # 16 bit offset in SDA +R_PPC_EMB_MRKREF = 110 +R_PPC_EMB_RELSEC16 = 111 +R_PPC_EMB_RELST_LO = 112 +R_PPC_EMB_RELST_HI = 113 +R_PPC_EMB_RELST_HA = 114 +R_PPC_EMB_BIT_FLD = 115 +R_PPC_EMB_RELSDA = 116 # 16 bit relative offset in SDA + +# Diab tool relocations. +R_PPC_DIAB_SDA21_LO = 180 # like EMB_SDA21, but lower 16 bit +R_PPC_DIAB_SDA21_HI = 181 # like EMB_SDA21, but high 16 bit +R_PPC_DIAB_SDA21_HA = 182 # like EMB_SDA21, adjusted high 16 +R_PPC_DIAB_RELSDA_LO = 183 # like EMB_RELSDA, but lower 16 bit +R_PPC_DIAB_RELSDA_HI = 184 # like EMB_RELSDA, but high 16 bit +R_PPC_DIAB_RELSDA_HA = 185 # like EMB_RELSDA, adjusted high 16 + +# GNU extension to support local ifunc. +R_PPC_IRELATIVE = 248 + +# GNU relocs used in PIC code sequences. +R_PPC_REL16 = 249 # half16 (sym+add-.) +R_PPC_REL16_LO = 250 # half16 (sym+add-.)@l +R_PPC_REL16_HI = 251 # half16 (sym+add-.)@h +R_PPC_REL16_HA = 252 # half16 (sym+add-.)@ha + +# This is a phony reloc to handle any old fashioned TOC16 references that may still be in object files. +R_PPC_TOC16 = 255 + +# PowerPC64 relocations defined by the ABIs +R_PPC64_NONE = R_PPC_NONE +R_PPC64_ADDR32 = R_PPC_ADDR32 # 32bit absolute address +R_PPC64_ADDR24 = R_PPC_ADDR24 # 26bit address, word aligned +R_PPC64_ADDR16 = R_PPC_ADDR16 # 16bit absolute address +R_PPC64_ADDR16_LO = R_PPC_ADDR16_LO # lower 16bits of address +R_PPC64_ADDR16_HI = R_PPC_ADDR16_HI # high 16bits of address. +R_PPC64_ADDR16_HA = R_PPC_ADDR16_HA # adjusted high 16bits. +R_PPC64_ADDR14 = R_PPC_ADDR14 # 16bit address, word aligned +R_PPC64_ADDR14_BRTAKEN = R_PPC_ADDR14_BRTAKEN +R_PPC64_ADDR14_BRNTAKEN = R_PPC_ADDR14_BRNTAKEN +R_PPC64_REL24 = R_PPC_REL24 # PC-rel. 26 bit, word aligned +R_PPC64_REL14 = R_PPC_REL14 # PC relative 16 bit +R_PPC64_REL14_BRTAKEN = R_PPC_REL14_BRTAKEN +R_PPC64_REL14_BRNTAKEN = R_PPC_REL14_BRNTAKEN +R_PPC64_GOT16 = R_PPC_GOT16 +R_PPC64_GOT16_LO = R_PPC_GOT16_LO +R_PPC64_GOT16_HI = R_PPC_GOT16_HI +R_PPC64_GOT16_HA = R_PPC_GOT16_HA + +R_PPC64_COPY = R_PPC_COPY +R_PPC64_GLOB_DAT = R_PPC_GLOB_DAT +R_PPC64_JMP_SLOT = R_PPC_JMP_SLOT +R_PPC64_RELATIVE = R_PPC_RELATIVE + +R_PPC64_UADDR32 = R_PPC_UADDR32 +R_PPC64_UADDR16 = R_PPC_UADDR16 +R_PPC64_REL32 = R_PPC_REL32 +R_PPC64_PLT32 = R_PPC_PLT32 +R_PPC64_PLTREL32 = R_PPC_PLTREL32 +R_PPC64_PLT16_LO = R_PPC_PLT16_LO +R_PPC64_PLT16_HI = R_PPC_PLT16_HI +R_PPC64_PLT16_HA = R_PPC_PLT16_HA + +R_PPC64_SECTOFF = R_PPC_SECTOFF +R_PPC64_SECTOFF_LO = R_PPC_SECTOFF_LO +R_PPC64_SECTOFF_HI = R_PPC_SECTOFF_HI +R_PPC64_SECTOFF_HA = R_PPC_SECTOFF_HA +R_PPC64_ADDR30 = 37 # word30 (S + A - P) >> 2 +R_PPC64_ADDR64 = 38 # doubleword64 S + A +R_PPC64_ADDR16_HIGHER = 39 # half16 #higher(S + A) +R_PPC64_ADDR16_HIGHERA = 40 # half16 #highera(S + A) +R_PPC64_ADDR16_HIGHEST = 41 # half16 #highest(S + A) +R_PPC64_ADDR16_HIGHESTA = 42 # half16 #highesta(S + A) +R_PPC64_UADDR64 = 43 # doubleword64 S + A +R_PPC64_REL64 = 44 # doubleword64 S + A - P +R_PPC64_PLT64 = 45 # doubleword64 L + A +R_PPC64_PLTREL64 = 46 # doubleword64 L + A - P +R_PPC64_TOC16 = 47 # half16* S + A - .TOC +R_PPC64_TOC16_LO = 48 # half16 #lo(S + A - .TOC.) +R_PPC64_TOC16_HI = 49 # half16 #hi(S + A - .TOC.) +R_PPC64_TOC16_HA = 50 # half16 #ha(S + A - .TOC.) +R_PPC64_TOC = 51 # doubleword64 .TOC +R_PPC64_PLTGOT16 = 52 # half16* M + A +R_PPC64_PLTGOT16_LO = 53 # half16 #lo(M + A) +R_PPC64_PLTGOT16_HI = 54 # half16 #hi(M + A) +R_PPC64_PLTGOT16_HA = 55 # half16 #ha(M + A) + +R_PPC64_ADDR16_DS = 56 # half16ds* (S + A) >> 2 +R_PPC64_ADDR16_LO_DS = 57 # half16ds #lo(S + A) >> 2 +R_PPC64_GOT16_DS = 58 # half16ds* (G + A) >> 2 +R_PPC64_GOT16_LO_DS = 59 # half16ds #lo(G + A) >> 2 +R_PPC64_PLT16_LO_DS = 60 # half16ds #lo(L + A) >> 2 +R_PPC64_SECTOFF_DS = 61 # half16ds* (R + A) >> 2 +R_PPC64_SECTOFF_LO_DS = 62 # half16ds #lo(R + A) >> 2 +R_PPC64_TOC16_DS = 63 # half16ds* (S + A - .TOC.) >> 2 +R_PPC64_TOC16_LO_DS = 64 # half16ds #lo(S + A - .TOC.) >> 2 +R_PPC64_PLTGOT16_DS = 65 # half16ds* (M + A) >> 2 +R_PPC64_PLTGOT16_LO_DS = 66 # half16ds #lo(M + A) >> 2 + +# PowerPC64 relocations defined for the TLS access ABI. +R_PPC64_TLS = 67 # none (sym+add)@tls +R_PPC64_DTPMOD64 = 68 # doubleword64 (sym+add)@dtpmod +R_PPC64_TPREL16 = 69 # half16* (sym+add)@tprel +R_PPC64_TPREL16_LO = 70 # half16 (sym+add)@tprel@l +R_PPC64_TPREL16_HI = 71 # half16 (sym+add)@tprel@h +R_PPC64_TPREL16_HA = 72 # half16 (sym+add)@tprel@ha +R_PPC64_TPREL64 = 73 # doubleword64 (sym+add)@tprel +R_PPC64_DTPREL16 = 74 # half16* (sym+add)@dtprel +R_PPC64_DTPREL16_LO = 75 # half16 (sym+add)@dtprel@l +R_PPC64_DTPREL16_HI = 76 # half16 (sym+add)@dtprel@h +R_PPC64_DTPREL16_HA = 77 # half16 (sym+add)@dtprel@ha +R_PPC64_DTPREL64 = 78 # doubleword64 (sym+add)@dtprel +R_PPC64_GOT_TLSGD16 = 79 # half16* (sym+add)@got@tlsgd +R_PPC64_GOT_TLSGD16_LO = 80 # half16 (sym+add)@got@tlsgd@l +R_PPC64_GOT_TLSGD16_HI = 81 # half16 (sym+add)@got@tlsgd@h +R_PPC64_GOT_TLSGD16_HA = 82 # half16 (sym+add)@got@tlsgd@ha +R_PPC64_GOT_TLSLD16 = 83 # half16* (sym+add)@got@tlsld +R_PPC64_GOT_TLSLD16_LO = 84 # half16 (sym+add)@got@tlsld@l +R_PPC64_GOT_TLSLD16_HI = 85 # half16 (sym+add)@got@tlsld@h +R_PPC64_GOT_TLSLD16_HA = 86 # half16 (sym+add)@got@tlsld@ha +R_PPC64_GOT_TPREL16_DS = 87 # half16ds* (sym+add)@got@tprel +R_PPC64_GOT_TPREL16_LO_DS = 88 # half16ds (sym+add)@got@tprel@l +R_PPC64_GOT_TPREL16_HI = 89 # half16 (sym+add)@got@tprel@h +R_PPC64_GOT_TPREL16_HA = 90 # half16 (sym+add)@got@tprel@ha +R_PPC64_GOT_DTPREL16_DS = 91 # half16ds* (sym+add)@got@dtprel +R_PPC64_GOT_DTPREL16_LO_DS = 92 # half16ds (sym+add)@got@dtprel@l +R_PPC64_GOT_DTPREL16_HI = 93 # half16 (sym+add)@got@dtprel@h +R_PPC64_GOT_DTPREL16_HA = 94 # half16 (sym+add)@got@dtprel@ha +R_PPC64_TPREL16_DS = 95 # half16ds* (sym+add)@tprel +R_PPC64_TPREL16_LO_DS = 96 # half16ds (sym+add)@tprel@l +R_PPC64_TPREL16_HIGHER = 97 # half16 (sym+add)@tprel@higher +R_PPC64_TPREL16_HIGHERA = 98 # half16 (sym+add)@tprel@highera +R_PPC64_TPREL16_HIGHEST = 99 # half16 (sym+add)@tprel@highest +R_PPC64_TPREL16_HIGHESTA = 100 # half16 (sym+add)@tprel@highesta +R_PPC64_DTPREL16_DS = 101 # half16ds* (sym+add)@dtprel +R_PPC64_DTPREL16_LO_DS = 102 # half16ds (sym+add)@dtprel@l +R_PPC64_DTPREL16_HIGHER = 103 # half16 (sym+add)@dtprel@higher +R_PPC64_DTPREL16_HIGHERA = 104 # half16 (sym+add)@dtprel@highera +R_PPC64_DTPREL16_HIGHEST = 105 # half16 (sym+add)@dtprel@highest +R_PPC64_DTPREL16_HIGHESTA = 106 # half16 (sym+add)@dtprel@highesta + +# GNU extension to support local ifunc. +R_PPC64_JMP_IREL = 247 +R_PPC64_IRELATIVE = 248 +R_PPC64_REL16 = 249 # half16 (sym+add-.) +R_PPC64_REL16_LO = 250 # half16 (sym+add-.)@l +R_PPC64_REL16_HI = 251 # half16 (sym+add-.)@h +R_PPC64_REL16_HA = 252 # half16 (sym+add-.)@ha + +# PowerPC64 specific values for the Dyn d_tag field. +DT_PPC64_GLINK = (DT_LOPROC + 0) +DT_PPC64_OPD = (DT_LOPROC + 1) +DT_PPC64_OPDSZ = (DT_LOPROC + 2) +DT_PPC64_NUM = 3 + +# ARM relocations + +R_ARM_NONE = 0 # No reloc +R_ARM_PC24 = 1 # PC relative 26 bit branch +R_ARM_ABS32 = 2 # Direct 32 bit +R_ARM_REL32 = 3 # PC relative 32 bit +R_ARM_PC13 = 4 +R_ARM_ABS16 = 5 # Direct 16 bit +R_ARM_ABS12 = 6 # Direct 12 bit +R_ARM_THM_ABS5 = 7 +R_ARM_ABS8 = 8 # Direct 8 bit +R_ARM_SBREL32 = 9 +R_ARM_THM_PC22 = 10 +R_ARM_THM_PC8 = 11 +R_ARM_AMP_VCALL9 = 12 +R_ARM_SWI24 = 13 # Obsolete static relocation. +R_ARM_TLS_DESC = 13 # Dynamic relocation. +R_ARM_THM_SWI8 = 14 +R_ARM_XPC25 = 15 +R_ARM_THM_XPC22 = 16 +R_ARM_TLS_DTPMOD32 = 17 # ID of module containing symbol +R_ARM_TLS_DTPOFF32 = 18 # Offset in TLS block +R_ARM_TLS_TPOFF32 = 19 # Offset in static TLS block +R_ARM_COPY = 20 # Copy symbol at runtime +R_ARM_GLOB_DAT = 21 # Create GOT entry +R_ARM_JUMP_SLOT = 22 # Create PLT entry +R_ARM_RELATIVE = 23 # Adjust by program base +R_ARM_GOTOFF = 24 # 32 bit offset to GOT +R_ARM_GOTPC = 25 # 32 bit PC relative offset to GOT +R_ARM_GOT32 = 26 # 32 bit GOT entry +R_ARM_PLT32 = 27 # 32 bit PLT address +R_ARM_ALU_PCREL_7_0 = 32 +R_ARM_ALU_PCREL_15_8 = 33 +R_ARM_ALU_PCREL_23_15 = 34 +R_ARM_LDR_SBREL_11_0 = 35 +R_ARM_ALU_SBREL_19_12 = 36 +R_ARM_ALU_SBREL_27_20 = 37 +R_ARM_TLS_GOTDESC = 90 +R_ARM_TLS_CALL = 91 +R_ARM_TLS_DESCSEQ = 92 +R_ARM_THM_TLS_CALL = 93 +R_ARM_GNU_VTENTRY = 100 +R_ARM_GNU_VTINHERIT = 101 +R_ARM_THM_PC11 = 102 # thumb unconditional branch +R_ARM_THM_PC9 = 103 # thumb conditional branch +R_ARM_TLS_GD32 = 104 # PC-rel 32 bit for global dynamic thread local data +R_ARM_TLS_LDM32 = 105 # PC-rel 32 bit for local dynamic thread local data +R_ARM_TLS_LDO32 = 106 # 32 bit offset relative to TLS block +R_ARM_TLS_IE32 = 107 # PC-rel 32 bit for GOT entry of static TLS block offset +R_ARM_TLS_LE32 = 108 # 32 bit offset relative to static TLS block +R_ARM_THM_TLS_DESCSEQ = 129 +R_ARM_IRELATIVE = 160 +R_ARM_RXPC25 = 249 +R_ARM_RSBREL32 = 250 +R_ARM_THM_RPC22 = 251 +R_ARM_RREL32 = 252 +R_ARM_RABS22 = 253 +R_ARM_RPC24 = 254 +R_ARM_RBASE = 255 +# Keep this the last entry. +R_ARM_NUM = 256 + +# IA-64 relocations + +R_IA64_NONE = 0x00 # none +R_IA64_IMM14 = 0x21 # symbol + addend, add imm14 +R_IA64_IMM22 = 0x22 # symbol + addend, add imm22 +R_IA64_IMM64 = 0x23 # symbol + addend, mov imm64 +R_IA64_DIR32MSB = 0x24 # symbol + addend, data4 MSB +R_IA64_DIR32LSB = 0x25 # symbol + addend, data4 LSB +R_IA64_DIR64MSB = 0x26 # symbol + addend, data8 MSB +R_IA64_DIR64LSB = 0x27 # symbol + addend, data8 LSB +R_IA64_GPREL22 = 0x2a # @gprel(sym + add), add imm22 +R_IA64_GPREL64I = 0x2b # @gprel(sym + add), mov imm64 +R_IA64_GPREL32MSB = 0x2c # @gprel(sym + add), data4 MSB +R_IA64_GPREL32LSB = 0x2d # @gprel(sym + add), data4 LSB +R_IA64_GPREL64MSB = 0x2e # @gprel(sym + add), data8 MSB +R_IA64_GPREL64LSB = 0x2f # @gprel(sym + add), data8 LSB +R_IA64_LTOFF22 = 0x32 # @ltoff(sym + add), add imm22 +R_IA64_LTOFF64I = 0x33 # @ltoff(sym + add), mov imm64 +R_IA64_PLTOFF22 = 0x3a # @pltoff(sym + add), add imm22 +R_IA64_PLTOFF64I = 0x3b # @pltoff(sym + add), mov imm64 +R_IA64_PLTOFF64MSB = 0x3e # @pltoff(sym + add), data8 MSB +R_IA64_PLTOFF64LSB = 0x3f # @pltoff(sym + add), data8 LSB +R_IA64_FPTR64I = 0x43 # @fptr(sym + add), mov imm64 +R_IA64_FPTR32MSB = 0x44 # @fptr(sym + add), data4 MSB +R_IA64_FPTR32LSB = 0x45 # @fptr(sym + add), data4 LSB +R_IA64_FPTR64MSB = 0x46 # @fptr(sym + add), data8 MSB +R_IA64_FPTR64LSB = 0x47 # @fptr(sym + add), data8 LSB +R_IA64_PCREL60B = 0x48 # @pcrel(sym + add), brl +R_IA64_PCREL21B = 0x49 # @pcrel(sym + add), ptb, call +R_IA64_PCREL21M = 0x4a # @pcrel(sym + add), chk.s +R_IA64_PCREL21F = 0x4b # @pcrel(sym + add), fchkf +R_IA64_PCREL32MSB = 0x4c # @pcrel(sym + add), data4 MSB +R_IA64_PCREL32LSB = 0x4d # @pcrel(sym + add), data4 LSB +R_IA64_PCREL64MSB = 0x4e # @pcrel(sym + add), data8 MSB +R_IA64_PCREL64LSB = 0x4f # @pcrel(sym + add), data8 LSB +R_IA64_LTOFF_FPTR22 = 0x52 # @ltoff(@fptr(s+a)), imm22 +R_IA64_LTOFF_FPTR64I = 0x53 # @ltoff(@fptr(s+a)), imm64 +R_IA64_LTOFF_FPTR32MSB = 0x54 # @ltoff(@fptr(s+a)), data4 MSB +R_IA64_LTOFF_FPTR32LSB = 0x55 # @ltoff(@fptr(s+a)), data4 LSB +R_IA64_LTOFF_FPTR64MSB = 0x56 # @ltoff(@fptr(s+a)), data8 MSB +R_IA64_LTOFF_FPTR64LSB = 0x57 # @ltoff(@fptr(s+a)), data8 LSB +R_IA64_SEGREL32MSB = 0x5c # @segrel(sym + add), data4 MSB +R_IA64_SEGREL32LSB = 0x5d # @segrel(sym + add), data4 LSB +R_IA64_SEGREL64MSB = 0x5e # @segrel(sym + add), data8 MSB +R_IA64_SEGREL64LSB = 0x5f # @segrel(sym + add), data8 LSB +R_IA64_SECREL32MSB = 0x64 # @secrel(sym + add), data4 MSB +R_IA64_SECREL32LSB = 0x65 # @secrel(sym + add), data4 LSB +R_IA64_SECREL64MSB = 0x66 # @secrel(sym + add), data8 MSB +R_IA64_SECREL64LSB = 0x67 # @secrel(sym + add), data8 LSB +R_IA64_REL32MSB = 0x6c # data 4 + REL +R_IA64_REL32LSB = 0x6d # data 4 + REL +R_IA64_REL64MSB = 0x6e # data 8 + REL +R_IA64_REL64LSB = 0x6f # data 8 + REL +R_IA64_LTV32MSB = 0x74 # symbol + addend, data4 MSB +R_IA64_LTV32LSB = 0x75 # symbol + addend, data4 LSB +R_IA64_LTV64MSB = 0x76 # symbol + addend, data8 MSB +R_IA64_LTV64LSB = 0x77 # symbol + addend, data8 LSB +R_IA64_PCREL21BI = 0x79 # @pcrel(sym + add), 21bit inst +R_IA64_PCREL22 = 0x7a # @pcrel(sym + add), 22bit inst +R_IA64_PCREL64I = 0x7b # @pcrel(sym + add), 64bit inst +R_IA64_IPLTMSB = 0x80 # dynamic reloc, imported PLT, MSB +R_IA64_IPLTLSB = 0x81 # dynamic reloc, imported PLT, LSB +R_IA64_COPY = 0x84 # copy relocation +R_IA64_SUB = 0x85 # Addend and symbol difference +R_IA64_LTOFF22X = 0x86 # LTOFF22, relaxable. +R_IA64_LDXMOV = 0x87 # Use of LTOFF22X. +R_IA64_TPREL14 = 0x91 # @tprel(sym + add), imm14 +R_IA64_TPREL22 = 0x92 # @tprel(sym + add), imm22 +R_IA64_TPREL64I = 0x93 # @tprel(sym + add), imm64 +R_IA64_TPREL64MSB = 0x96 # @tprel(sym + add), data8 MSB +R_IA64_TPREL64LSB = 0x97 # @tprel(sym + add), data8 LSB +R_IA64_LTOFF_TPREL22 = 0x9a # @ltoff(@tprel(s+a)), imm2 +R_IA64_DTPMOD64MSB = 0xa6 # @dtpmod(sym + add), data8 MSB +R_IA64_DTPMOD64LSB = 0xa7 # @dtpmod(sym + add), data8 LSB +R_IA64_LTOFF_DTPMOD22 = 0xaa # @ltoff(@dtpmod(sym + add)), imm22 +R_IA64_DTPREL14 = 0xb1 # @dtprel(sym + add), imm14 +R_IA64_DTPREL22 = 0xb2 # @dtprel(sym + add), imm22 +R_IA64_DTPREL64I = 0xb3 # @dtprel(sym + add), imm64 +R_IA64_DTPREL32MSB = 0xb4 # @dtprel(sym + add), data4 MSB +R_IA64_DTPREL32LSB = 0xb5 # @dtprel(sym + add), data4 LSB +R_IA64_DTPREL64MSB = 0xb6 # @dtprel(sym + add), data8 MSB +R_IA64_DTPREL64LSB = 0xb7 # @dtprel(sym + add), data8 LSB +R_IA64_LTOFF_DTPREL22 = 0xba # @ltoff(@dtprel(s+a)), imm22 + +# SH relocations + +R_SH_NONE = 0 +R_SH_DIR32 = 1 +R_SH_REL32 = 2 +R_SH_DIR8WPN = 3 +R_SH_IND12W = 4 +R_SH_DIR8WPL = 5 +R_SH_DIR8WPZ = 6 +R_SH_DIR8BP = 7 +R_SH_DIR8W = 8 +R_SH_DIR8L = 9 +R_SH_SWITCH16 = 25 +R_SH_SWITCH32 = 26 +R_SH_USES = 27 +R_SH_COUNT = 28 +R_SH_ALIGN = 29 +R_SH_CODE = 30 +R_SH_DATA = 31 +R_SH_LABEL = 32 +R_SH_SWITCH8 = 33 +R_SH_GNU_VTINHERIT = 34 +R_SH_GNU_VTENTRY = 35 +R_SH_TLS_GD_32 = 144 +R_SH_TLS_LD_32 = 145 +R_SH_TLS_LDO_32 = 146 +R_SH_TLS_IE_32 = 147 +R_SH_TLS_LE_32 = 148 +R_SH_TLS_DTPMOD32 = 149 +R_SH_TLS_DTPOFF32 = 150 +R_SH_TLS_TPOFF32 = 151 +R_SH_GOT32 = 160 +R_SH_PLT32 = 161 +R_SH_COPY = 162 +R_SH_GLOB_DAT = 163 +R_SH_JMP_SLOT = 164 +R_SH_RELATIVE = 165 +R_SH_GOTOFF = 166 +R_SH_GOTPC = 167 +# Keep this the last entry. +R_SH_NUM = 256 + +# S/390 relocations + +R_390_NONE = 0 # No reloc. +R_390_8 = 1 # Direct 8 bit. +R_390_12 = 2 # Direct 12 bit. +R_390_16 = 3 # Direct 16 bit. +R_390_32 = 4 # Direct 32 bit. +R_390_PC32 = 5 # PC relative 32 bit. +R_390_GOT12 = 6 # 12 bit GOT offset. +R_390_GOT32 = 7 # 32 bit GOT offset. +R_390_PLT32 = 8 # 32 bit PC relative PLT address. +R_390_COPY = 9 # Copy symbol at runtime. +R_390_GLOB_DAT = 10 # Create GOT entry. +R_390_JMP_SLOT = 11 # Create PLT entry. +R_390_RELATIVE = 12 # Adjust by program base. +R_390_GOTOFF32 = 13 # 32 bit offset to GOT. +R_390_GOTPC = 14 # 32 bit PC relative offset to GOT. +R_390_GOT16 = 15 # 16 bit GOT offset. +R_390_PC16 = 16 # PC relative 16 bit. +R_390_PC16DBL = 17 # PC relative 16 bit shifted by 1. +R_390_PLT16DBL = 18 # 16 bit PC rel. PLT shifted by 1. +R_390_PC32DBL = 19 # PC relative 32 bit shifted by 1. +R_390_PLT32DBL = 20 # 32 bit PC rel. PLT shifted by 1. +R_390_GOTPCDBL = 21 # 32 bit PC rel. GOT shifted by 1. +R_390_64 = 22 # Direct 64 bit. +R_390_PC64 = 23 # PC relative 64 bit. +R_390_GOT64 = 24 # 64 bit GOT offset. +R_390_PLT64 = 25 # 64 bit PC relative PLT address. +R_390_GOTENT = 26 # 32 bit PC rel. to GOT entry >> 1. +R_390_GOTOFF16 = 27 # 16 bit offset to GOT. +R_390_GOTOFF64 = 28 # 64 bit offset to GOT. +R_390_GOTPLT12 = 29 # 12 bit offset to jump slot. +R_390_GOTPLT16 = 30 # 16 bit offset to jump slot. +R_390_GOTPLT32 = 31 # 32 bit offset to jump slot. +R_390_GOTPLT64 = 32 # 64 bit offset to jump slot. +R_390_GOTPLTENT = 33 # 32 bit rel. offset to jump slot. +R_390_PLTOFF16 = 34 # 16 bit offset from GOT to PLT. +R_390_PLTOFF32 = 35 # 32 bit offset from GOT to PLT. +R_390_PLTOFF64 = 36 # 16 bit offset from GOT to PLT. +R_390_TLS_LOAD = 37 # Tag for load insn in TLS code. +R_390_TLS_GDCALL = 38 # Tag for function call in general dynamic TLS code. +R_390_TLS_LDCALL = 39 # Tag for function call in local dynamic TLS code. +R_390_TLS_GD32 = 40 # Direct 32 bit for general dynamic thread local data. +R_390_TLS_GD64 = 41 # Direct 64 bit for general dynamic thread local data. +R_390_TLS_GOTIE12 = 42 # 12 bit GOT offset for static TLS block offset. +R_390_TLS_GOTIE32 = 43 # 32 bit GOT offset for static TLS block offset. +R_390_TLS_GOTIE64 = 44 # 64 bit GOT offset for static TLS block offset. +R_390_TLS_LDM32 = 45 # Direct 32 bit for local dynamic thread local data in LE code. +R_390_TLS_LDM64 = 46 # Direct 64 bit for local dynamic thread local data in LE code. +R_390_TLS_IE32 = 47 # 32 bit address of GOT entry for negated static TLS block offset. +R_390_TLS_IE64 = 48 # 64 bit address of GOT entry for negated static TLS block offset. +R_390_TLS_IEENT = 49 # 32 bit rel. offset to GOT entry for negated static TLS block offset. +R_390_TLS_LE32 = 50 # 32 bit negated offset relative to static TLS block. +R_390_TLS_LE64 = 51 # 64 bit negated offset relative to static TLS block. +R_390_TLS_LDO32 = 52 # 32 bit offset relative to TLS block. +R_390_TLS_LDO64 = 53 # 64 bit offset relative to TLS block. +R_390_TLS_DTPMOD = 54 # ID of module containing symbol. +R_390_TLS_DTPOFF = 55 # Offset in TLS block. +R_390_TLS_TPOFF = 56 # Negated offset in static TLS block. +R_390_20 = 57 # Direct 20 bit. +R_390_GOT20 = 58 # 20 bit GOT offset. +R_390_GOTPLT20 = 59 # 20 bit offset to jump slot. +R_390_TLS_GOTIE20 = 60 # 20 bit GOT offset for static TLS block offset. +# Keep this the last entry. +R_390_NUM = 61 + + +# CRIS relocations. +R_CRIS_NONE = 0 +R_CRIS_8 = 1 +R_CRIS_16 = 2 +R_CRIS_32 = 3 +R_CRIS_8_PCREL = 4 +R_CRIS_16_PCREL = 5 +R_CRIS_32_PCREL = 6 +R_CRIS_GNU_VTINHERIT = 7 +R_CRIS_GNU_VTENTRY = 8 +R_CRIS_COPY = 9 +R_CRIS_GLOB_DAT = 10 +R_CRIS_JUMP_SLOT = 11 +R_CRIS_RELATIVE = 12 +R_CRIS_16_GOT = 13 +R_CRIS_32_GOT = 14 +R_CRIS_16_GOTPLT = 15 +R_CRIS_32_GOTPLT = 16 +R_CRIS_32_GOTREL = 17 +R_CRIS_32_PLT_GOTREL = 18 +R_CRIS_32_PLT_PCREL = 19 + +R_CRIS_NUM = 20 + + +# AMD x86-64 relocations. +R_X86_64_NONE = 0 # No reloc +R_X86_64_64 = 1 # Direct 64 bit +R_X86_64_PC32 = 2 # PC relative 32 bit signed +R_X86_64_GOT32 = 3 # 32 bit GOT entry +R_X86_64_PLT32 = 4 # 32 bit PLT address +R_X86_64_COPY = 5 # Copy symbol at runtime +R_X86_64_GLOB_DAT = 6 # Create GOT entry +R_X86_64_JUMP_SLOT = 7 # Create PLT entry +R_X86_64_RELATIVE = 8 # Adjust by program base +R_X86_64_GOTPCREL = 9 # 32 bit signed PC relative offset to GOT +R_X86_64_32 = 10 # Direct 32 bit zero extended +R_X86_64_32S = 11 # Direct 32 bit sign extended +R_X86_64_16 = 12 # Direct 16 bit zero extended +R_X86_64_PC16 = 13 # 16 bit sign extended pc relative +R_X86_64_8 = 14 # Direct 8 bit sign extended +R_X86_64_PC8 = 15 # 8 bit sign extended pc relative +R_X86_64_DTPMOD64 = 16 # ID of module containing symbol +R_X86_64_DTPOFF64 = 17 # Offset in module's TLS block +R_X86_64_TPOFF64 = 18 # Offset in initial TLS block +R_X86_64_TLSGD = 19 # 32 bit signed PC relative offset to two GOT entries for GD symbol +R_X86_64_TLSLD = 20 # 32 bit signed PC relative offset to two GOT entries for LD symbol +R_X86_64_DTPOFF32 = 21 # Offset in TLS block +R_X86_64_GOTTPOFF = 22 # 32 bit signed PC relative offset to GOT entry for IE symbol +R_X86_64_TPOFF32 = 23 # Offset in initial TLS block +R_X86_64_PC64 = 24 # PC relative 64 bit +R_X86_64_GOTOFF64 = 25 # 64 bit offset to GOT +R_X86_64_GOTPC32 = 26 # 32 bit signed pc relative offset to GOT +R_X86_64_GOT64 = 27 # 64-bit GOT entry offset +R_X86_64_GOTPCREL64 = 28 # 64-bit PC relative offset to GOT entry +R_X86_64_GOTPC64 = 29 # 64-bit PC relative offset to GOT +R_X86_64_GOTPLT64 = 30 # like GOT64, says PLT entry needed +R_X86_64_PLTOFF64 = 31 # 64-bit GOT relative offset to PLT entry +R_X86_64_SIZE32 = 32 # Size of symbol plus 32-bit addend +R_X86_64_SIZE64 = 33 # Size of symbol plus 64-bit addend +R_X86_64_GOTPC32_TLSDESC = 34 # GOT offset for TLS descriptor. +R_X86_64_TLSDESC_CALL = 35 # Marker for call through TLS descriptor. +R_X86_64_TLSDESC = 36 # TLS descriptor. +R_X86_64_IRELATIVE = 37 # Adjust indirectly by program base + +R_X86_64_NUM = 38 + + +# AM33 relocations. +R_MN10300_NONE = 0 # No reloc. +R_MN10300_32 = 1 # Direct 32 bit. +R_MN10300_16 = 2 # Direct 16 bit. +R_MN10300_8 = 3 # Direct 8 bit. +R_MN10300_PCREL32 = 4 # PC-relative 32-bit. +R_MN10300_PCREL16 = 5 # PC-relative 16-bit signed. +R_MN10300_PCREL8 = 6 # PC-relative 8-bit signed. +R_MN10300_GNU_VTINHERIT = 7 # Ancient C++ vtable garbage... +R_MN10300_GNU_VTENTRY = 8 # ... collection annotation. +R_MN10300_24 = 9 # Direct 24 bit. +R_MN10300_GOTPC32 = 10 # 32-bit PCrel offset to GOT. +R_MN10300_GOTPC16 = 11 # 16-bit PCrel offset to GOT. +R_MN10300_GOTOFF32 = 12 # 32-bit offset from GOT. +R_MN10300_GOTOFF24 = 13 # 24-bit offset from GOT. +R_MN10300_GOTOFF16 = 14 # 16-bit offset from GOT. +R_MN10300_PLT32 = 15 # 32-bit PCrel to PLT entry. +R_MN10300_PLT16 = 16 # 16-bit PCrel to PLT entry. +R_MN10300_GOT32 = 17 # 32-bit offset to GOT entry. +R_MN10300_GOT24 = 18 # 24-bit offset to GOT entry. +R_MN10300_GOT16 = 19 # 16-bit offset to GOT entry. +R_MN10300_COPY = 20 # Copy symbol at runtime. +R_MN10300_GLOB_DAT = 21 # Create GOT entry. +R_MN10300_JMP_SLOT = 22 # Create PLT entry. +R_MN10300_RELATIVE = 23 # Adjust by program base. + +R_MN10300_NUM = 24 + + +# M32R relocs. +R_M32R_NONE = 0 # No reloc. +R_M32R_16 = 1 # Direct 16 bit. +R_M32R_32 = 2 # Direct 32 bit. +R_M32R_24 = 3 # Direct 24 bit. +R_M32R_10_PCREL = 4 # PC relative 10 bit shifted. +R_M32R_18_PCREL = 5 # PC relative 18 bit shifted. +R_M32R_26_PCREL = 6 # PC relative 26 bit shifted. +R_M32R_HI16_ULO = 7 # High 16 bit with unsigned low. +R_M32R_HI16_SLO = 8 # High 16 bit with signed low. +R_M32R_LO16 = 9 # Low 16 bit. +R_M32R_SDA16 = 10 # 16 bit offset in SDA. +R_M32R_GNU_VTINHERIT = 11 +R_M32R_GNU_VTENTRY = 12 +# M32R relocs use SHT_RELA. +R_M32R_16_RELA = 33 # Direct 16 bit. +R_M32R_32_RELA = 34 # Direct 32 bit. +R_M32R_24_RELA = 35 # Direct 24 bit. +R_M32R_10_PCREL_RELA = 36 # PC relative 10 bit shifted. +R_M32R_18_PCREL_RELA = 37 # PC relative 18 bit shifted. +R_M32R_26_PCREL_RELA = 38 # PC relative 26 bit shifted. +R_M32R_HI16_ULO_RELA = 39 # High 16 bit with unsigned low +R_M32R_HI16_SLO_RELA = 40 # High 16 bit with signed low +R_M32R_LO16_RELA = 41 # Low 16 bit +R_M32R_SDA16_RELA = 42 # 16 bit offset in SDA +R_M32R_RELA_GNU_VTINHERIT = 43 +R_M32R_RELA_GNU_VTENTRY = 44 +R_M32R_REL32 = 45 # PC relative 32 bit. + +R_M32R_GOT24 = 48 # 24 bit GOT entry +R_M32R_26_PLTREL = 49 # 26 bit PC relative to PLT shifted +R_M32R_COPY = 50 # Copy symbol at runtime +R_M32R_GLOB_DAT = 51 # Create GOT entry +R_M32R_JMP_SLOT = 52 # Create PLT entry +R_M32R_RELATIVE = 53 # Adjust by program base +R_M32R_GOTOFF = 54 # 24 bit offset to GOT +R_M32R_GOTPC24 = 55 # 24 bit PC relative offset to GOT +R_M32R_GOT16_HI_ULO = 56 # High 16 bit GOT entry with unsigned low +R_M32R_GOT16_HI_SLO = 57 # High 16 bit GOT entry with signed low +R_M32R_GOT16_LO = 58 # Low 16 bit GOT entry +R_M32R_GOTPC_HI_ULO = 59 # High 16 bit PC relative offset to GOT with unsigned low +R_M32R_GOTPC_HI_SLO = 60 # High 16 bit PC relative offset to GOT with signed low +R_M32R_GOTPC_LO = 61 # Low 16 bit PC relative offset to GOT +R_M32R_GOTOFF_HI_ULO = 62 # High 16 bit offset to GOT with unsigned low +R_M32R_GOTOFF_HI_SLO = 63 # High 16 bit offset to GOT with signed low +R_M32R_GOTOFF_LO = 64 # Low 16 bit offset to GOT +R_M32R_NUM = 256 # Keep this the last entry. diff --git a/miasm/elfesteem/elf_init.py b/miasm/elfesteem/elf_init.py new file mode 100644 index 000000000..14a37eb5a --- /dev/null +++ b/miasm/elfesteem/elf_init.py @@ -0,0 +1,878 @@ +#! /usr/bin/env python + +from __future__ import print_function +from builtins import range +import logging +import struct + +from future.utils import PY3, with_metaclass + +from miasm.core.utils import force_bytes +from miasm.elfesteem import cstruct +from miasm.elfesteem import elf +from miasm.elfesteem.strpatchwork import StrPatchwork + +log = logging.getLogger("elfparse") +console_handler = logging.StreamHandler() +console_handler.setFormatter(logging.Formatter("%(levelname)-5s: %(message)s")) +log.addHandler(console_handler) +log.setLevel(logging.WARN) + + +def printable(string): + if isinstance(string, bytes): + return "".join( + c.decode() if b" " <= c < b"~" else "." + for c in (string[i:i+1] for i in range(len(string))) + ) + return string + + +class StructWrapper_metaclass(type): + + def __new__(cls, name, bases, dct): + wrapped = dct["wrapped"] + if wrapped is not None: # XXX: make dct lookup look into base classes + for fname, v in wrapped._fields: + dct[fname] = property(dct.pop("get_" + fname, + lambda self, fname=fname: getattr( + self.cstr, fname)), + dct.pop("set_" + fname, + lambda self, v, fname=fname: setattr( + self.cstr, fname, v)), + dct.pop("del_" + fname, None)) + return type.__new__(cls, name, bases, dct) + + +class StructWrapper(with_metaclass(StructWrapper_metaclass, object)): + + wrapped = None + + def __init__(self, parent, sex, size, *args, **kargs): + self.cstr = self.wrapped(sex, size, *args, **kargs) + self.parent = parent + + def __getitem__(self, item): + return getattr(self, item) + + def __repr__(self): + return "> 8].name + + def get_type(self): + return self.cstr.info & 0xff + + +class WRel64(StructWrapper): + wrapped = elf.Rel64 + wrapped._fields.append(("sym", "u32")) + wrapped._fields.append(("type", "u32")) + + def get_sym(self): + return self.parent.linksection.symtab[self.cstr.info >> 32].name + + def get_type(self): + return self.cstr.info & 0xffffffff + + +class WRela32(WRel32): + wrapped = elf.Rela32 + wrapped._fields.append(("sym", "u32")) + wrapped._fields.append(("type", "u08")) + + def get_sym(self): + return self.parent.linksection.symtab[self.cstr.info >> 8].name + + def get_type(self): + return self.cstr.info & 0xff + + +class WRela64(WRel64): + wrapped = elf.Rela64 + wrapped._fields.append(("sym", "u32")) + wrapped._fields.append(("type", "u32")) + + def get_sym(self): + return self.parent.linksection.symtab[self.cstr.info >> 32].name + + def get_type(self): + return self.cstr.info & 0xffffffff + + +class WShdr(StructWrapper): + wrapped = elf.Shdr + + def get_name(self): + return self.parent.parent._shstr.get_name(self.cstr.name) + + +class WDynamic(StructWrapper): + wrapped = elf.Dynamic + + def get_name(self): + if self.type == elf.DT_NEEDED: + return self.parent.linksection.get_name(self.cstr.name) + return self.cstr.name + + +class WPhdr(StructWrapper): + wrapped = elf.Phdr + + +class WPhdr64(StructWrapper): + wrapped = elf.Phdr64 + + +class WNhdr(StructWrapper): + wrapped = elf.Nhdr + + +class ContentManager(object): + + def __get__(self, owner, x): + if hasattr(owner, '_content'): + return owner._content + + def __set__(self, owner, new_content): + owner.resize(len(owner._content), len(new_content)) + owner._content = StrPatchwork(new_content) + owner.parse_content(owner.sex, owner.size) + + def __delete__(self, owner): + self.__set__(owner, None) + + +# Sections + +class Section_metaclass(type): + + def __new__(cls, name, bases, dct): + o = type.__new__(cls, name, bases, dct) + if name != "Section": + Section.register(o) + return o + + def register(cls, o): + if o.sht is not None: + cls.sectypes[o.sht] = o + + def __call__(cls, parent, sex, size, shstr=None): + sh = None + if shstr is not None: + sh = WShdr(None, sex, size, shstr) + if sh.type in Section.sectypes: + cls = Section.sectypes[sh.type] + i = cls.__new__(cls, cls.__name__, cls.__bases__, cls.__dict__) + if sh is not None: + sh.parent = i + i.__init__(parent, sh) + return i + + +class Section(with_metaclass(Section_metaclass, object)): + + sectypes = {} + content = ContentManager() + + def resize(self, old, new): + self.sh.size += new - old + self.parent.resize(self, new - old) + if self.phparent: + self.phparent.resize(self, new - old) + + def parse_content(self, sex, size): + self.sex, self.size = sex, size + pass + + def get_linksection(self): + return self.parent[self.sh.link] + + def set_linksection(self, val): + if isinstance(val, Section): + val = self.parent.shlist.find(val) + if type(val) is int: + self.sh.link = val + linksection = property(get_linksection, set_linksection) + + def get_infosection(self): + # XXX info may not be in sh list ?!? + if not self.sh.info in self.parent: + return None + return self.parent[self.sh.info] + + def set_infosection(self, val): + if isinstance(val, Section): + val = self.parent.shlist.find(val) + if type(val) is int: + self.sh.info = val + infosection = property(get_infosection, set_infosection) + + def __init__(self, parent, sh=None): + self.parent = parent + self.phparent = None + self.sh = sh + self._content = b"" + + def __repr__(self): + r = "{%(name)s ofs=%(offset)#x sz=%(size)#x addr=%(addr)#010x}" % self.sh + return r + + +class NullSection(Section): + sht = elf.SHT_NULL + + def get_name(self, ofs): + # XXX check this + return b"" + + +class ProgBits(Section): + sht = elf.SHT_PROGBITS + + +class HashSection(Section): + sht = elf.SHT_HASH + + +class NoBitsSection(Section): + sht = elf.SHT_NOBITS + + +class ShLibSection(Section): + sht = elf.SHT_SHLIB + + +class InitArray(Section): + sht = elf.SHT_INIT_ARRAY + + +class FiniArray(Section): + sht = elf.SHT_FINI_ARRAY + + +class GroupSection(Section): + sht = elf.SHT_GROUP + + +class SymTabSHIndeces(Section): + sht = elf.SHT_SYMTAB_SHNDX + + +class GNUVerSym(Section): + sht = elf.SHT_GNU_versym + + +class GNUVerNeed(Section): + sht = elf.SHT_GNU_verneed + + +class GNUVerDef(Section): + sht = elf.SHT_GNU_verdef + + +class GNULibLIst(Section): + sht = elf.SHT_GNU_LIBLIST + + +class CheckSumSection(Section): + sht = elf.SHT_CHECKSUM + + +class NoteSection(Section): + sht = elf.SHT_NOTE + + def parse_content(self, sex, size): + self.sex, self.size = sex, size + c = self.content + hsz = 12 + self.notes = [] + # XXX: c may not be aligned? + while len(c) > hsz: + note = WNhdr(self, sex, size, c) + namesz, descsz = note.namesz, note.descsz + name = c[hsz:hsz + namesz] + desc = c[hsz + namesz:hsz + namesz + descsz] + c = c[hsz + namesz + descsz:] + self.notes.append((note.type, name, desc)) + + +class Dynamic(Section): + sht = elf.SHT_DYNAMIC + + def parse_content(self, sex, size): + self.sex, self.size = sex, size + c = self.content + self.dyntab = [] + self.dynamic = {} + sz = self.sh.entsize + idx = 0 + while len(c) > sz*idx: + s = c[sz*idx:sz*(idx+1)] + idx += 1 + dyn = WDynamic(self, sex, size, s) + self.dyntab.append(dyn) + if isinstance(dyn.name, str): + self[dyn.name] = dyn + + def __setitem__(self, item, value): + if isinstance(item, bytes): + self.dynamic[item] = value + return + if isinstance(item, str): + self.symbols[item.encode()] = value + return + self.dyntab[item] = value + + def __getitem__(self, item): + if isinstance(item, bytes): + return self.dynamic[item] + if isinstance(item, str): + return self.dynamic[item.encode()] + return self.dyntab[item] + + +class StrTable(Section): + sht = elf.SHT_STRTAB + + def parse_content(self, sex, size): + self.sex, self.size = sex, size + self.res = {} + c = self.content + q = 0 + index = 0 + l = len(c) + while index < l: + p = c.find(b"\x00", index) + if p < 0: + log.warning("Missing trailing 0 for string [%s]" % c) # XXX + p = len(c) - index + self.res[index] = c[index:p] + # print q, c[:p] + index = p + 1 + # q += p+1 + # c = c[p+1:] + + def get_name(self, ofs): + return self.content[ofs:self.content.find(b'\x00', start=ofs)] + + def add_name(self, name): + name = force_bytes(name) + name = name + b"\x00" + if name in self.content: + return self.content.find(name) + n = len(self.content) + self.content = bytes(self.content) + name + return n + + def mod_name(self, name, new_name): + s = bytes(self.content) + name_b = b'\x00%s\x00' % name.encode() + if not name_b in s: + raise ValueError('Unknown name %r' % name) + self.content = s.replace( + name_b, + b'\x00%s\x00' % new_name.encode() + ) + return len(self.content) + + +class SymTable(Section): + sht = elf.SHT_SYMTAB + + def parse_content(self, sex, size): + self.sex, self.size = sex, size + c = self.content + self.symtab = [] + self.symbols = {} + sz = self.sh.entsize + index = 0 + l = len(c) + if size == 32: + WSym = WSym32 + elif size == 64: + WSym = WSym64 + else: + ValueError('unknown size') + while index < l: + s = c[index:index + sz] + index += sz + sym = WSym(self, sex, size, s) + self.symtab.append(sym) + self[sym.name] = sym + + def __getitem__(self, item): + if isinstance(item, bytes): + return self.symbols[item] + if isinstance(item, str): + return self.symbols[item.encode()] + return self.symtab[item] + + def __setitem__(self, item, value): + if isinstance(item, bytes): + self.symbols[item] = value + return + if isinstance(item, str): + self.symbols[item.encode()] = value + return + self.symtab[item] = value + + +class DynSymTable(SymTable): + sht = elf.SHT_DYNSYM + + +class RelTable(Section): + sht = elf.SHT_REL + + def parse_content(self, sex, size): + self.sex, self.size = sex, size + if size == 32: + WRel = WRel32 + elif size == 64: + WRel = WRel64 + else: + ValueError('unknown size') + c = self.content + self.reltab = [] + self.rel = {} + sz = self.sh.entsize + + idx = 0 + while len(c) > sz*idx: + s = c[sz*idx:sz*(idx+1)] + idx += 1 + rel = WRel(self, sex, size, s) + self.reltab.append(rel) + if rel.parent.linksection != self.parent.shlist[0]: + self.rel[rel.sym] = rel + + +class RelATable(RelTable): + sht = elf.SHT_RELA + +# Section List + + +class SHList(object): + + def __init__(self, parent, sex, size): + self.parent = parent + self.shlist = [] + ehdr = self.parent.Ehdr + of1 = ehdr.shoff + if not of1: # No SH table + return + for i in range(ehdr.shnum): + of2 = of1 + ehdr.shentsize + shstr = parent[of1:of2] + self.shlist.append(Section(self, sex, size, shstr=shstr)) + of1 = of2 + self._shstr = self.shlist[ehdr.shstrndx] + + for s in self.shlist: + if not isinstance(s, NoBitsSection): + s._content = StrPatchwork( + parent[s.sh.offset: s.sh.offset + s.sh.size] + ) + # Follow dependencies when initializing sections + zero = self.shlist[0] + todo = self.shlist[1:] + done = [] + while todo: + s = todo.pop(0) + if ((s.linksection == zero or s.linksection in done) and + (s.infosection in [zero, None] or s.infosection in done)): + done.append(s) + s.parse_content(sex, size) + else: + todo.append(s) + for s in self.shlist: + self.do_add_section(s) + + def do_add_section(self, section): + n = section.sh.name + if n.startswith(b"."): + n = n[1:] + n = printable(n).replace(".", "_").replace("-", "_") + setattr(self, n, section) # xxx + + def append(self, item): + self.do_add_section(item) + self.shlist.append(item) + + def __getitem__(self, item): + return self.shlist[item] + + def __repr__(self): + rep = ["# section offset size addr flags"] + for i, s in enumerate(self.shlist): + l = "%(name)-15s %(offset)08x %(size)06x %(addr)08x %(flags)x " % s.sh + l = ("%2i " % i) + l + s.__class__.__name__ + rep.append(l) + return "\n".join(rep) + + def __bytes__(self): + return b"".join( + bytes(s.sh) for s in self.shlist + ) + + def __str__(self): + if PY3: + return repr(self) + return bytes(self) + + def resize(self, sec, diff): + for s in self.shlist: + if s.sh.offset > sec.sh.offset: + s.sh.offset += diff + if self.parent.Ehdr.shoff > sec.sh.offset: + self.parent.Ehdr.shoff += diff + if self.parent.Ehdr.phoff > sec.sh.offset: + self.parent.Ehdr.phoff += diff + +# Program Header List + + +class ProgramHeader(object): + + def __init__(self, parent, sex, size, phstr): + self.parent = parent + self.ph = WPhdr(self, sex, size, phstr) + self.shlist = [] + for s in self.parent.parent.sh: + if isinstance(s, NullSection): + continue + if ((isinstance(s, NoBitsSection) and s.sh.offset == self.ph.offset + self.ph.filesz) + or self.ph.offset <= s.sh.offset < self.ph.offset + self.ph.filesz): + s.phparent = self + self.shlist.append(s) + + def resize(self, sec, diff): + self.ph.filesz += diff + self.ph.memsz += diff + self.parent.resize(sec, diff) + + +class ProgramHeader64(object): + + def __init__(self, parent, sex, size, phstr): + self.parent = parent + self.ph = WPhdr64(self, sex, size, phstr) + self.shlist = [] + for s in self.parent.parent.sh: + if isinstance(s, NullSection): + continue + if ((isinstance(s, NoBitsSection) and s.sh.offset == self.ph.offset + self.ph.filesz) + or self.ph.offset <= s.sh.offset < self.ph.offset + self.ph.filesz): + s.phparent = self + self.shlist.append(s) + + def resize(self, sec, diff): + self.ph.filesz += diff + self.ph.memsz += diff + self.parent.resize(sec, diff) + + +class PHList(object): + + def __init__(self, parent, sex, size): + self.parent = parent + self.phlist = [] + ehdr = self.parent.Ehdr + of1 = ehdr.phoff + for i in range(ehdr.phnum): + of2 = of1 + ehdr.phentsize + phstr = parent[of1:of2] + if size == 32: + self.phlist.append(ProgramHeader(self, sex, size, phstr)) + else: + self.phlist.append(ProgramHeader64(self, sex, size, phstr)) + of1 = of2 + + def __getitem__(self, item): + return self.phlist[item] + + def __repr__(self): + r = [" offset filesz vaddr memsz"] + for i, p in enumerate(self.phlist): + l = "%(offset)07x %(filesz)06x %(vaddr)08x %(memsz)07x %(type)02x %(flags)01x" % p.ph + l = ("%2i " % i) + l + r.append(l) + r.append(" " + " ".join(printable(s.sh.name) for s in p.shlist)) + return "\n".join(r) + + def __bytes__(self): + return b"".join( + bytes(p.ph) for p in self.phlist + ) + + def __str__(self): + if PY3: + return repr(self) + return self.__bytes__(self) + + def resize(self, sec, diff): + for p in self.phlist: + if p.ph.offset > sec.sh.offset: + p.ph.offset += diff + if p.ph.vaddr > sec.phparent.ph.vaddr + sec.sh.offset: + p.ph.vaddr += diff + if p.ph.paddr > sec.phparent.ph.paddr + sec.sh.offset: + p.ph.paddr += diff + + +class virt(object): + + def __init__(self, x): + self.parent = x + + def get_rvaitem(self, start, stop=None): + if stop == None: + s = self.parent.getsectionbyvad(start) + if s: + start = start - s.sh.addr + else: + s = self.parent.getphbyvad(start) + if s: + start = start - s.ph.vaddr + if not s: + return [(None, start)] + return [(s, start)] + total_len = stop - start + + virt_item = [] + while total_len: + s = self.parent.getsectionbyvad(start) + if not s: + s = self.parent.getphbyvad(start) + if not s: + raise ValueError('unknown rva address! %x' % start) + if isinstance(s, ProgramHeader) or isinstance(s, ProgramHeader64): + s_max = s.ph.filesz + s_start = start - s.ph.vaddr + s_stop = stop - s.ph.vaddr + else: + s_max = s.sh.size + s_start = start - s.sh.addr + s_stop = stop - s.sh.addr + if s_stop > s_max: + s_stop = s_max + + s_len = s_stop - s_start + if s_len == 0: + raise ValueError('empty section! %x' % start) + total_len -= s_len + start += s_len + n_item = slice(s_start, s_stop) + virt_item.append((s, n_item)) + return virt_item + + def item2virtitem(self, item): + if not type(item) is slice: # integer + return self.get_rvaitem(item) + start = item.start + stop = item.stop + assert(item.step is None) + return self.get_rvaitem(start, stop) + + def get(self, ad_start, ad_stop=None): + rva_items = self.get_rvaitem(ad_start, ad_stop) + data_out = b"" + for s, n_item in rva_items: + if not (isinstance(s, ProgramHeader) or isinstance(s, ProgramHeader64)): + data_out += s.content.__getitem__(n_item) + continue + if not type(n_item) is slice: + n_item = slice(n_item, n_item + 1, 1) + start = n_item.start + s.ph.offset + stop = n_item.stop + s.ph.offset + if n_item.step != None: + step = n_item.step + s.ph.offset + else: + step = None + n_item = slice(start, stop, step) + # data_out += self.parent.content.__s.content.__getitem__(n_item) + data_out += self.parent.content.__getitem__(n_item) + + return data_out + + def set(self, item, data): + if not type(item) is slice: + item = slice(item, item + len(data), None) + virt_item = self.item2virtitem(item) + if not virt_item: + return + off = 0 + for s, n_item in virt_item: + if isinstance(s, ProgBits): + i = slice(off, n_item.stop + off - n_item.start, n_item.step) + + data_slice = data.__getitem__(i) + s.content.__setitem__(n_item, data_slice) + off = i.stop + else: + raise ValueError('TODO XXX') + + return + + def __getitem__(self, item): + if isinstance(item, slice): + assert(item.step is None) + return self.get(item.start, item.stop) + else: + return self.get(item) + + def __setitem__(self, item, data): + if isinstance(item, slice): + rva = item.start + else: + rva = item + self.set(rva, data) + + def max_addr(self): + # the maximum virtual address is found by retrieving the maximum + # possible virtual address, either from the program entries, and + # section entries. if there is no such object, raise an error. + l = 0 + if self.parent.ph.phlist: + for phdr in self.parent.ph.phlist: + l = max(l, phdr.ph.vaddr + phdr.ph.memsz) + if self.parent.sh.shlist: + for shdr in self.parent.sh.shlist: + l = max(l, shdr.sh.addr + shdr.sh.size) + if not l: + raise ValueError('maximum virtual address not found !') + return l + + def is_addr_in(self, ad): + return self.parent.is_in_virt_address(ad) + + def find(self, pattern, start=0): + sections = [] + offset = start + for s in self.parent.ph: + s_max = s.ph.memsz # max(s.ph.filesz, s.ph.memsz) + if offset < s.ph.vaddr + s_max: + sections.append(s) + + if not sections: + return -1 + offset -= sections[0].ph.vaddr + if offset < 0: + offset = 0 + for s in sections: + data = self.parent.content[s.ph.offset:s.ph.offset + s.ph.filesz] + ret = data.find(pattern, offset) + if ret != -1: + return ret + s.ph.vaddr # self.parent.rva2virt(s.addr + ret) + offset = 0 + return -1 + +# ELF object + + +class ELF(object): + + def __init__(self, elfstr): + self._content = elfstr + self.parse_content() + + self._virt = virt(self) + + def get_virt(self): + return self._virt + virt = property(get_virt) + + content = ContentManager() + + def parse_content(self): + h = self.content[:8] + self.size = struct.unpack('B', h[4:5])[0] * 32 + self.sex = struct.unpack('B', h[5:6])[0] + self.Ehdr = WEhdr(self, self.sex, self.size, self.content) + self.sh = SHList(self, self.sex, self.size) + self.ph = PHList(self, self.sex, self.size) + + def resize(self, old, new): + pass + + def __getitem__(self, item): + return self.content[item] + + def build_content(self): + c = StrPatchwork() + c[0] = bytes(self.Ehdr) + c[self.Ehdr.phoff] = bytes(self.ph) + for s in self.sh: + c[s.sh.offset] = bytes(s.content) + c[self.Ehdr.shoff] = bytes(self.sh) + return bytes(c) + + def __bytes__(self): + return self.build_content() + + def __str__(self): + if PY3: + return repr(self) + return bytes(self) + + def getphbyvad(self, ad): + for s in self.ph: + if s.ph.vaddr <= ad < s.ph.vaddr + s.ph.memsz: + return s + + def getsectionbyvad(self, ad): + for s in self.sh: + if s.sh.addr <= ad < s.sh.addr + s.sh.size: + return s + + def getsectionbyname(self, name): + name = force_bytes(name) + for s in self.sh: + try: + if s.sh.name.strip(b'\x00') == name: + return s + except UnicodeDecodeError: + pass + return None + + def is_in_virt_address(self, ad): + for s in self.sh: + if s.sh.addr <= ad < s.sh.addr + s.sh.size: + return True + return False diff --git a/miasm/elfesteem/minidump.py b/miasm/elfesteem/minidump.py new file mode 100644 index 000000000..ee2be8a08 --- /dev/null +++ b/miasm/elfesteem/minidump.py @@ -0,0 +1,545 @@ +"""Constants and structures associated to Minidump format +Based on: http://amnesia.gtisc.gatech.edu/~moyix/minidump.py +""" +from future.utils import viewitems + +from future.builtins import int as int_types +from miasm.elfesteem.new_cstruct import CStruct + +class Enumeration(object): + """Stand for an enumeration type""" + + def __init__(self, enum_info): + """enum_info: {name: value}""" + self._enum_info = enum_info + self._inv_info = dict((v, k) for k, v in viewitems(enum_info)) + + def __getitem__(self, key): + """Helper: assume that string is for key, integer is for value""" + if isinstance(key, int_types): + return self._inv_info[key] + return self._enum_info[key] + + def __getattr__(self, key): + if key in self._enum_info: + return self._enum_info[key] + raise AttributeError + + def from_value(self, value): + return self._inv_info[value] + + +class Rva(CStruct): + """Relative Virtual Address + Note: RVA in Minidump means "file offset" + """ + _fields = [("rva", "u32"), + ] + + +minidumpType = Enumeration({ + # MINIDUMP_TYPE + # https://msdn.microsoft.com/en-us/library/ms680519(v=vs.85).aspx + "MiniDumpNormal" : 0x00000000, + "MiniDumpWithDataSegs" : 0x00000001, + "MiniDumpWithFullMemory" : 0x00000002, + "MiniDumpWithHandleData" : 0x00000004, + "MiniDumpFilterMemory" : 0x00000008, + "MiniDumpScanMemory" : 0x00000010, + "MiniDumpWithUnloadedModules" : 0x00000020, + "MiniDumpWithIndirectlyReferencedMemory" : 0x00000040, + "MiniDumpFilterModulePaths" : 0x00000080, + "MiniDumpWithProcessThreadData" : 0x00000100, + "MiniDumpWithPrivateReadWriteMemory" : 0x00000200, + "MiniDumpWithoutOptionalData" : 0x00000400, + "MiniDumpWithFullMemoryInfo" : 0x00000800, + "MiniDumpWithThreadInfo" : 0x00001000, + "MiniDumpWithCodeSegs" : 0x00002000, + "MiniDumpWithoutAuxiliaryState" : 0x00004000, + "MiniDumpWithFullAuxiliaryState" : 0x00008000, + "MiniDumpWithPrivateWriteCopyMemory" : 0x00010000, + "MiniDumpIgnoreInaccessibleMemory" : 0x00020000, + "MiniDumpWithTokenInformation" : 0x00040000, + "MiniDumpWithModuleHeaders" : 0x00080000, + "MiniDumpFilterTriage" : 0x00100000, + "MiniDumpValidTypeFlags" : 0x001fffff, +}) + +class MinidumpHDR(CStruct): + """MINIDUMP_HEADER + https://msdn.microsoft.com/en-us/library/ms680378(VS.85).aspx + """ + _fields = [("Magic", "u32"), # MDMP + ("Version", "u16"), + ("ImplementationVersion", "u16"), + ("NumberOfStreams", "u32"), + ("StreamDirectoryRva", "Rva"), + ("Checksum", "u32"), + ("TimeDateStamp", "u32"), + ("Flags", "u32") + ] + +class LocationDescriptor(CStruct): + """MINIDUMP_LOCATION_DESCRIPTOR + https://msdn.microsoft.com/en-us/library/ms680383(v=vs.85).aspx + """ + _fields = [("DataSize", "u32"), + ("Rva", "Rva"), + ] + + +streamType = Enumeration({ + # MINIDUMP_STREAM_TYPE + # https://msdn.microsoft.com/en-us/library/ms680394(v=vs.85).aspx + "UnusedStream" : 0, + "ReservedStream0" : 1, + "ReservedStream1" : 2, + "ThreadListStream" : 3, + "ModuleListStream" : 4, + "MemoryListStream" : 5, + "ExceptionStream" : 6, + "SystemInfoStream" : 7, + "ThreadExListStream" : 8, + "Memory64ListStream" : 9, + "CommentStreamA" : 10, + "CommentStreamW" : 11, + "HandleDataStream" : 12, + "FunctionTableStream" : 13, + "UnloadedModuleListStream" : 14, + "MiscInfoStream" : 15, + "MemoryInfoListStream" : 16, + "ThreadInfoListStream" : 17, + "HandleOperationListStream" : 18, + "LastReservedStream" : 0xffff, +}) + +class StreamDirectory(CStruct): + """MINIDUMP_DIRECTORY + https://msdn.microsoft.com/en-us/library/ms680365(VS.85).aspx + """ + _fields = [("StreamType", "u32"), + ("Location", "LocationDescriptor"), + ] + + @property + def pretty_name(self): + return streamType[self.StreamType] + + +class FixedFileInfo(CStruct): + """VS_FIXEDFILEINFO + https://msdn.microsoft.com/en-us/library/ms646997(v=vs.85).aspx + """ + _fields = [("dwSignature", "u32"), + ("dwStrucVersion", "u32"), + ("dwFileVersionMS", "u32"), + ("dwFileVersionLS", "u32"), + ("dwProductVersionMS", "u32"), + ("dwProductVersionLS", "u32"), + ("dwFileFlagsMask", "u32"), + ("dwFileFlags", "u32"), + ("dwFileOS", "u32"), + ("dwFileType", "u32"), + ("dwFileSubtype", "u32"), + ("dwFileDateMS", "u32"), + ("dwFileDateLS", "u32"), + ] + +class MinidumpString(CStruct): + """MINIDUMP_STRING + https://msdn.microsoft.com/en-us/library/ms680395(v=vs.85).aspx + """ + _fields = [("Length", "u32"), + ("Buffer", "u08", lambda string:string.Length), + ] + +class Module(CStruct): + """MINIDUMP_MODULE + https://msdn.microsoft.com/en-us/library/ms680392(v=vs.85).aspx + """ + _fields = [("BaseOfImage", "u64"), + ("SizeOfImage", "u32"), + ("CheckSum", "u32"), + ("TimeDateStamp", "u32"), + ("ModuleNameRva", "Rva"), + ("VersionInfo", "FixedFileInfo"), + ("CvRecord", "LocationDescriptor"), + ("MiscRecord", "LocationDescriptor"), + ("Reserved0", "u64"), + ("Reserved1", "u64"), + ] + + +class ModuleList(CStruct): + """MINIDUMP_MODULE_LIST + https://msdn.microsoft.com/en-us/library/ms680391(v=vs.85).aspx + """ + _fields = [("NumberOfModules", "u32"), + ("Modules", "Module", lambda mlist:mlist.NumberOfModules), + ] + + +class MemoryDescriptor64(CStruct): + """MINIDUMP_MEMORY_DESCRIPTOR64 + https://msdn.microsoft.com/en-us/library/ms680384(v=vs.85).aspx + """ + _fields = [("StartOfMemoryRange", "u64"), + ("DataSize", "u64") + ] + + +class Memory64List(CStruct): + """MINIDUMP_MEMORY64_LIST + https://msdn.microsoft.com/en-us/library/ms680387(v=vs.85).aspx + """ + _fields = [("NumberOfMemoryRanges", "u64"), + ("BaseRva", "u64"), + ("MemoryRanges", "MemoryDescriptor64", + lambda mlist:mlist.NumberOfMemoryRanges), + ] + +class MemoryDescriptor(CStruct): + """MINIDUMP_MEMORY_DESCRIPTOR + https://msdn.microsoft.com/en-us/library/ms680384(v=vs.85).aspx + """ + _fields = [("StartOfMemoryRange", "u64"), + ("Memory", "LocationDescriptor"), + ] + +class MemoryList(CStruct): + """MINIDUMP_MEMORY_LIST + https://msdn.microsoft.com/en-us/library/ms680387(v=vs.85).aspx + """ + _fields = [("NumberOfMemoryRanges", "u32"), + ("MemoryRanges", "MemoryDescriptor", + lambda mlist:mlist.NumberOfMemoryRanges), + ] + +memProtect = Enumeration({ + # MEM PROTECT + # https://msdn.microsoft.com/en-us/library/aa366786(v=vs.85).aspx + "PAGE_NOACCESS" : 0x0001, + "PAGE_READONLY" : 0x0002, + "PAGE_READWRITE" : 0x0004, + "PAGE_WRITECOPY" : 0x0008, + "PAGE_EXECUTE" : 0x0010, + "PAGE_EXECUTE_READ" : 0x0020, + "PAGE_EXECUTE_READWRITE" : 0x0040, + "PAGE_EXECUTE_WRITECOPY" : 0x0080, + "PAGE_GUARD" : 0x0100, + "PAGE_NOCACHE" : 0x0200, + "PAGE_WRITECOMBINE" : 0x0400, +}) + +class MemoryInfo(CStruct): + """MINIDUMP_MEMORY_INFO + https://msdn.microsoft.com/en-us/library/ms680386(v=vs.85).aspx + """ + _fields = [("BaseAddress", "u64"), + ("AllocationBase", "u64"), + ("AllocationProtect", "u32"), + ("__alignment1", "u32"), + ("RegionSize", "u64"), + ("State", "u32"), + ("Protect", "u32"), + ("Type", "u32"), + ("__alignment2", "u32"), + ] + +class MemoryInfoList(CStruct): + """MINIDUMP_MEMORY_INFO_LIST + https://msdn.microsoft.com/en-us/library/ms680385(v=vs.85).aspx + """ + _fields = [("SizeOfHeader", "u32"), + ("SizeOfEntry", "u32"), + ("NumberOfEntries", "u64"), + # Fake field, for easy access to MemoryInfo elements + ("MemoryInfos", "MemoryInfo", + lambda mlist: mlist.NumberOfEntries), + ] + + +contextFlags_x86 = Enumeration({ + "CONTEXT_i386" : 0x00010000, + "CONTEXT_CONTROL" : 0x00010001, + "CONTEXT_INTEGER" : 0x00010002, + "CONTEXT_SEGMENTS" : 0x00010004, + "CONTEXT_FLOATING_POINT" : 0x00010008, + "CONTEXT_DEBUG_REGISTERS" : 0x00010010, + "CONTEXT_EXTENDED_REGISTERS" : 0x00010020, +}) + +class FloatingSaveArea(CStruct): + """FLOATING_SAVE_AREA + http://terminus.rewolf.pl/terminus/structures/ntdll/_FLOATING_SAVE_AREA_x86.html + """ + _fields = [("ControlWord", "u32"), + ("StatusWord", "u32"), + ("TagWord", "u32"), + ("ErrorOffset", "u32"), + ("ErrorSelector", "u32"), + ("DataOffset", "u32"), + ("DataSelector", "u32"), + ("RegisterArea", "80s"), + ("Cr0NpxState", "u32"), + ] + +class Context_x86(CStruct): + """CONTEXT x86 + https://msdn.microsoft.com/en-us/en-en/library/ms679284(v=vs.85).aspx + http://terminus.rewolf.pl/terminus/structures/ntdll/_CONTEXT_x86.html + """ + + MAXIMUM_SUPPORTED_EXTENSION = 512 + + def is_activated(flag): + mask = contextFlags_x86[flag] + def check_context(ctx): + if (ctx.ContextFlags & mask == mask): + return 1 + return 0 + return check_context + + _fields = [("ContextFlags", "u32"), + # DebugRegisters + ("Dr0", "u32", is_activated("CONTEXT_DEBUG_REGISTERS")), + ("Dr1", "u32", is_activated("CONTEXT_DEBUG_REGISTERS")), + ("Dr2", "u32", is_activated("CONTEXT_DEBUG_REGISTERS")), + ("Dr3", "u32", is_activated("CONTEXT_DEBUG_REGISTERS")), + ("Dr6", "u32", is_activated("CONTEXT_DEBUG_REGISTERS")), + ("Dr7", "u32", is_activated("CONTEXT_DEBUG_REGISTERS")), + + ("FloatSave", "FloatingSaveArea", + is_activated("CONTEXT_FLOATING_POINT")), + + # SegmentRegisters + ("SegGs", "u32", is_activated("CONTEXT_SEGMENTS")), + ("SegFs", "u32", is_activated("CONTEXT_SEGMENTS")), + ("SegEs", "u32", is_activated("CONTEXT_SEGMENTS")), + ("SegDs", "u32", is_activated("CONTEXT_SEGMENTS")), + # IntegerRegisters + ("Edi", "u32", is_activated("CONTEXT_INTEGER")), + ("Esi", "u32", is_activated("CONTEXT_INTEGER")), + ("Ebx", "u32", is_activated("CONTEXT_INTEGER")), + ("Edx", "u32", is_activated("CONTEXT_INTEGER")), + ("Ecx", "u32", is_activated("CONTEXT_INTEGER")), + ("Eax", "u32", is_activated("CONTEXT_INTEGER")), + # ControlRegisters + ("Ebp", "u32", is_activated("CONTEXT_CONTROL")), + ("Eip", "u32", is_activated("CONTEXT_CONTROL")), + ("SegCs", "u32", is_activated("CONTEXT_CONTROL")), + ("EFlags", "u32", is_activated("CONTEXT_CONTROL")), + ("Esp", "u32", is_activated("CONTEXT_CONTROL")), + ("SegSs", "u32", is_activated("CONTEXT_CONTROL")), + + ("ExtendedRegisters", "%ds" % MAXIMUM_SUPPORTED_EXTENSION, + is_activated("CONTEXT_EXTENDED_REGISTERS")), + ] + + +contextFlags_AMD64 = Enumeration({ + "CONTEXT_AMD64" : 0x00100000, + "CONTEXT_CONTROL" : 0x00100001, + "CONTEXT_INTEGER" : 0x00100002, + "CONTEXT_SEGMENTS" : 0x00100004, + "CONTEXT_FLOATING_POINT" : 0x00100008, + "CONTEXT_DEBUG_REGISTERS" : 0x00100010, + "CONTEXT_XSTATE" : 0x00100020, + "CONTEXT_EXCEPTION_ACTIVE" : 0x08000000, + "CONTEXT_SERVICE_ACTIVE" : 0x10000000, + "CONTEXT_EXCEPTION_REQUEST" : 0x40000000, + "CONTEXT_EXCEPTION_REPORTING" : 0x80000000, +}) + + +class M128A(CStruct): + """M128A + http://terminus.rewolf.pl/terminus/structures/ntdll/_M128A_x64.html + """ + _fields = [("Low", "u64"), + ("High", "u64"), + ] + +class Context_AMD64(CStruct): + """CONTEXT AMD64 + https://github.com/duarten/Threadjack/blob/master/WinNT.h + """ + + def is_activated(flag): + mask = contextFlags_AMD64[flag] + def check_context(ctx): + if (ctx.ContextFlags & mask == mask): + return 1 + return 0 + return check_context + + _fields = [ + + # Only used for Convenience + ("P1Home", "u64"), + ("P2Home", "u64"), + ("P3Home", "u64"), + ("P4Home", "u64"), + ("P5Home", "u64"), + ("P6Home", "u64"), + + # Control + ("ContextFlags", "u32"), + ("MxCsr", "u32"), + + # Segment & processor + # /!\ activation depends on multiple flags + ("SegCs", "u16", is_activated("CONTEXT_CONTROL")), + ("SegDs", "u16", is_activated("CONTEXT_SEGMENTS")), + ("SegEs", "u16", is_activated("CONTEXT_SEGMENTS")), + ("SegFs", "u16", is_activated("CONTEXT_SEGMENTS")), + ("SegGs", "u16", is_activated("CONTEXT_SEGMENTS")), + ("SegSs", "u16", is_activated("CONTEXT_CONTROL")), + ("EFlags", "u32", is_activated("CONTEXT_CONTROL")), + + # Debug registers + ("Dr0", "u64", is_activated("CONTEXT_DEBUG_REGISTERS")), + ("Dr1", "u64", is_activated("CONTEXT_DEBUG_REGISTERS")), + ("Dr2", "u64", is_activated("CONTEXT_DEBUG_REGISTERS")), + ("Dr3", "u64", is_activated("CONTEXT_DEBUG_REGISTERS")), + ("Dr6", "u64", is_activated("CONTEXT_DEBUG_REGISTERS")), + ("Dr7", "u64", is_activated("CONTEXT_DEBUG_REGISTERS")), + + # Integer registers + # /!\ activation depends on multiple flags + ("Rax", "u64", is_activated("CONTEXT_INTEGER")), + ("Rcx", "u64", is_activated("CONTEXT_INTEGER")), + ("Rdx", "u64", is_activated("CONTEXT_INTEGER")), + ("Rbx", "u64", is_activated("CONTEXT_INTEGER")), + ("Rsp", "u64", is_activated("CONTEXT_CONTROL")), + ("Rbp", "u64", is_activated("CONTEXT_INTEGER")), + ("Rsi", "u64", is_activated("CONTEXT_INTEGER")), + ("Rdi", "u64", is_activated("CONTEXT_INTEGER")), + ("R8", "u64", is_activated("CONTEXT_INTEGER")), + ("R9", "u64", is_activated("CONTEXT_INTEGER")), + ("R10", "u64", is_activated("CONTEXT_INTEGER")), + ("R11", "u64", is_activated("CONTEXT_INTEGER")), + ("R12", "u64", is_activated("CONTEXT_INTEGER")), + ("R13", "u64", is_activated("CONTEXT_INTEGER")), + ("R14", "u64", is_activated("CONTEXT_INTEGER")), + ("R15", "u64", is_activated("CONTEXT_INTEGER")), + ("Rip", "u64", is_activated("CONTEXT_CONTROL")), + + # Floating point + ("Header", "M128A", lambda ctx: 2), + ("Legacy", "M128A", lambda ctx: 8), + ("Xmm0", "M128A"), + ("Xmm1", "M128A"), + ("Xmm2", "M128A"), + ("Xmm3", "M128A"), + ("Xmm4", "M128A"), + ("Xmm5", "M128A"), + ("Xmm6", "M128A"), + ("Xmm7", "M128A"), + ("Xmm8", "M128A"), + ("Xmm9", "M128A"), + ("Xmm10", "M128A"), + ("Xmm11", "M128A"), + ("Xmm12", "M128A"), + ("Xmm13", "M128A"), + ("Xmm14", "M128A"), + ("Xmm15", "M128A"), + + + # Vector registers + ("VectorRegister", "M128A", lambda ctx: 16), + ("VectorControl", "u64"), + + # Special debug control regs + ("DebugControl", "u64"), + ("LastBranchToRip", "u64"), + ("LastBranchFromRip", "u64"), + ("LastExceptionToRip", "u64"), + ("LastExceptionFromRip", "u64"), + ] + +processorArchitecture = Enumeration({ + "PROCESSOR_ARCHITECTURE_X86" : 0, + "PROCESSOR_ARCHITECTURE_MIPS" : 1, + "PROCESSOR_ARCHITECTURE_ALPHA" : 2, + "PROCESSOR_ARCHITECTURE_PPC" : 3, + "PROCESSOR_ARCHITECTURE_SHX" : 4, + "PROCESSOR_ARCHITECTURE_ARM" : 5, + "PROCESSOR_ARCHITECTURE_IA64" : 6, + "PROCESSOR_ARCHITECTURE_ALPHA64" : 7, + "PROCESSOR_ARCHITECTURE_MSIL" : 8, + "PROCESSOR_ARCHITECTURE_AMD64" : 9, + "PROCESSOR_ARCHITECTURE_X86_WIN64" : 10, + "PROCESSOR_ARCHITECTURE_UNKNOWN" : 0xffff, +}) + +class Thread(CStruct): + """MINIDUMP_THREAD + https://msdn.microsoft.com/en-us/library/ms680517(v=vs.85).aspx + """ + + arch2context_cls = { + processorArchitecture.PROCESSOR_ARCHITECTURE_X86: Context_x86, + processorArchitecture.PROCESSOR_ARCHITECTURE_AMD64: Context_AMD64, + } + + def parse_context(self, content, offset): + loc_desc = LocationDescriptor.unpack(content, offset, self.parent_head) + + # Use the correct context depending on architecture + systeminfo = self.parent_head.systeminfo + context_cls = self.arch2context_cls.get(systeminfo.ProcessorArchitecture, + None) + if context_cls is None: + raise ValueError("Unsupported architecture: %s" % systeminfo.pretty_processor_architecture) + + ctxt = context_cls.unpack(content, loc_desc.Rva.rva, self.parent_head) + fake_loc_descriptor = LocationDescriptor(DataSize=0, Rva=Rva(rva=0)) + return ctxt, offset + len(fake_loc_descriptor) + + _fields = [("ThreadId", "u32"), + ("SuspendCount", "u32"), + ("PriorityClass", "u32"), + ("Priority", "u32"), + ("Teb", "u64"), + ("Stack", "MemoryDescriptor"), + ("ThreadContext", (parse_context, + lambda thread, value: NotImplemented)), + ] + +class ThreadList(CStruct): + """MINIDUMP_THREAD_LIST + https://msdn.microsoft.com/en-us/library/ms680515(v=vs.85).aspx + """ + _fields = [("NumberOfThreads", "u32"), + ("Threads", "Thread", + lambda mlist: mlist.NumberOfThreads), + ] + + +class SystemInfo(CStruct): + """MINIDUMP_SYSTEM_INFO + https://msdn.microsoft.com/en-us/library/ms680396(v=vs.85).aspx + """ + _fields = [("ProcessorArchitecture", "u16"), + ("ProcessorLevel", "u16"), + ("ProcessorRevision", "u16"), + ("NumberOfProcessors", "u08"), + ("ProductType", "u08"), + ("MajorVersion", "u32"), + ("MinorVersion", "u32"), + ("BuildNumber", "u32"), + ("PlatformId", "u32"), + ("CSDVersionRva", "Rva"), + ("SuiteMask", "u16"), + ("Reserved2", "u16"), + ("VendorId", "u32", lambda sinfo: 3), + ("VersionInformation", "u32"), + ("FeatureInformation", "u32"), + ("AMDExtendedCpuFeatures", "u32"), + ] + + @property + def pretty_processor_architecture(self): + return processorArchitecture[self.ProcessorArchitecture] + diff --git a/miasm/elfesteem/minidump_init.py b/miasm/elfesteem/minidump_init.py new file mode 100644 index 000000000..0a9022b9e --- /dev/null +++ b/miasm/elfesteem/minidump_init.py @@ -0,0 +1,194 @@ +""" +High-level abstraction of Minidump file +""" +from builtins import range +import struct + +from miasm.elfesteem.strpatchwork import StrPatchwork +from miasm.elfesteem import minidump as mp + + +class MemorySegment(object): + """Stand for a segment in memory with additional information""" + + def __init__(self, offset, memory_desc, module=None, memory_info=None): + self.offset = offset + self.memory_desc = memory_desc + self.module = module + self.memory_info = memory_info + self.minidump = self.memory_desc.parent_head + + @property + def address(self): + return self.memory_desc.StartOfMemoryRange + + @property + def size(self): + if isinstance(self.memory_desc, mp.MemoryDescriptor64): + return self.memory_desc.DataSize + elif isinstance(self.memory_desc, mp.MemoryDescriptor): + return self.memory_desc.Memory.DataSize + raise TypeError + + @property + def name(self): + if not self.module: + return "" + name = mp.MinidumpString.unpack(self.minidump._content, + self.module.ModuleNameRva.rva, + self.minidump) + return b"".join( + struct.pack("B", x) for x in name.Buffer + ).decode("utf-16") + + @property + def content(self): + return self.minidump._content[self.offset:self.offset + self.size] + + @property + def protect(self): + if self.memory_info: + return self.memory_info.Protect + return None + + @property + def pretty_protect(self): + if self.protect is None: + return "UNKNOWN" + return mp.memProtect[self.protect] + + +class Minidump(object): + """Stand for a Minidump file + + Here is a few limitation: + - only < 4GB Minidump are supported (LocationDescriptor handling) + - only Stream relative to memory mapping are implemented + + Official description is available on MSDN: + https://msdn.microsoft.com/en-us/library/ms680378(VS.85).aspx + """ + + _sex = 0 + _wsize = 32 + + def __init__(self, minidump_str): + self._content = StrPatchwork(minidump_str) + + # Specific streams + self.modulelist = None + self.memory64list = None + self.memorylist = None + self.memoryinfolist = None + self.systeminfo = None + + # Get information + self.streams = [] + self.threads = None + self.parse_content() + + # Memory information + self.memory = {} # base address (virtual) -> Memory information + self.build_memory() + + def parse_content(self): + """Build structures corresponding to current content""" + + # Header + offset = 0 + self.minidumpHDR = mp.MinidumpHDR.unpack(self._content, offset, self) + assert self.minidumpHDR.Magic == 0x504d444d + + # Streams + base_offset = self.minidumpHDR.StreamDirectoryRva.rva + empty_stream = mp.StreamDirectory( + StreamType=0, + Location=mp.LocationDescriptor( + DataSize=0, + Rva=mp.Rva(rva=0) + ) + ) + streamdir_size = len(empty_stream) + for i in range(self.minidumpHDR.NumberOfStreams): + stream_offset = base_offset + i * streamdir_size + stream = mp.StreamDirectory.unpack(self._content, stream_offset, self) + self.streams.append(stream) + + # Launch specific action depending on the stream + datasize = stream.Location.DataSize + offset = stream.Location.Rva.rva + if stream.StreamType == mp.streamType.ModuleListStream: + self.modulelist = mp.ModuleList.unpack(self._content, offset, self) + elif stream.StreamType == mp.streamType.MemoryListStream: + self.memorylist = mp.MemoryList.unpack(self._content, offset, self) + elif stream.StreamType == mp.streamType.Memory64ListStream: + self.memory64list = mp.Memory64List.unpack(self._content, offset, self) + elif stream.StreamType == mp.streamType.MemoryInfoListStream: + self.memoryinfolist = mp.MemoryInfoList.unpack(self._content, offset, self) + elif stream.StreamType == mp.streamType.SystemInfoStream: + self.systeminfo = mp.SystemInfo.unpack(self._content, offset, self) + + # Some streams need the SystemInfo stream to work + for stream in self.streams: + datasize = stream.Location.DataSize + offset = stream.Location.Rva.rva + if (self.systeminfo is not None and + stream.StreamType == mp.streamType.ThreadListStream): + self.threads = mp.ThreadList.unpack(self._content, offset, self) + + + def build_memory(self): + """Build an easier to use memory view based on ModuleList and + Memory64List streams""" + + addr2module = dict((module.BaseOfImage, module) + for module in (self.modulelist.Modules if + self.modulelist else [])) + addr2meminfo = dict((memory.BaseAddress, memory) + for memory in (self.memoryinfolist.MemoryInfos if + self.memoryinfolist else [])) + + mode64 = self.minidumpHDR.Flags & mp.minidumpType.MiniDumpWithFullMemory + + if mode64: + offset = self.memory64list.BaseRva + memranges = self.memory64list.MemoryRanges + else: + memranges = self.memorylist.MemoryRanges + + for memory in memranges: + if not mode64: + offset = memory.Memory.Rva.rva + + # Create a MemorySegment with augmented information + base_address = memory.StartOfMemoryRange + module = addr2module.get(base_address, None) + meminfo = addr2meminfo.get(base_address, None) + self.memory[base_address] = MemorySegment(offset, memory, + module, meminfo) + + if mode64: + offset += memory.DataSize + + # Sanity check + if mode64: + assert all(addr in self.memory for addr in addr2module) + + def get(self, virt_start, virt_stop): + """Return the content at the (virtual addresses) + [virt_start:virt_stop]""" + + # Find the corresponding memory segment + for addr in self.memory: + if virt_start <= addr <= virt_stop: + break + else: + return b"" + + memory = self.memory[addr] + shift = addr - virt_start + last = virt_stop - addr + if last > memory.size: + raise RuntimeError("Multi-page not implemented") + + return self._content[memory.offset + shift:memory.offset + last] diff --git a/miasm/elfesteem/new_cstruct.py b/miasm/elfesteem/new_cstruct.py new file mode 100644 index 000000000..ec591aa82 --- /dev/null +++ b/miasm/elfesteem/new_cstruct.py @@ -0,0 +1,265 @@ +#! /usr/bin/env python + +from __future__ import print_function +import re +import struct + +from future.utils import PY3, viewitems, with_metaclass + +type2realtype = {} +size2type = {} +size2type_s = {} + +for t in 'B', 'H', 'I', 'Q': + s = struct.calcsize(t) + type2realtype[t] = s * 8 + size2type[s * 8] = t + +for t in 'b', 'h', 'i', 'q': + s = struct.calcsize(t) + type2realtype[t] = s * 8 + size2type_s[s * 8] = t + +type2realtype['u08'] = size2type[8] +type2realtype['u16'] = size2type[16] +type2realtype['u32'] = size2type[32] +type2realtype['u64'] = size2type[64] + +type2realtype['s08'] = size2type_s[8] +type2realtype['s16'] = size2type_s[16] +type2realtype['s32'] = size2type_s[32] +type2realtype['s64'] = size2type_s[64] + +type2realtype['d'] = 'd' +type2realtype['f'] = 'f' +type2realtype['q'] = 'q' +type2realtype['ptr'] = 'ptr' + +sex_types = {0: '<', 1: '>'} + + +def fix_size(fields, wsize): + out = [] + for name, v in fields: + if v.endswith("s"): + pass + elif v == "ptr": + v = size2type[wsize] + elif not v in type2realtype: + raise ValueError("unknown Cstruct type", v) + else: + v = type2realtype[v] + out.append((name, v)) + fields = out + return fields + + +def real_fmt(fmt, wsize): + if fmt == "ptr": + v = size2type[wsize] + elif fmt in type2realtype: + v = type2realtype[fmt] + else: + v = fmt + return v + +all_cstructs = {} + + +class Cstruct_Metaclass(type): + field_suffix = "_value" + + def __new__(cls, name, bases, dct): + for fields in dct['_fields']: + fname = fields[0] + if fname in ['parent', 'parent_head']: + raise ValueError('field name will confuse internal structs', + repr(fname)) + dct[fname] = property(dct.pop("get_" + fname, + lambda self, fname=fname: getattr( + self, fname + self.__class__.field_suffix)), + dct.pop("set_" + fname, + lambda self, v, fname=fname: setattr( + self, fname + self.__class__.field_suffix, v)), + dct.pop("del_" + fname, None)) + + o = super(Cstruct_Metaclass, cls).__new__(cls, name, bases, dct) + if name != "CStruct": + all_cstructs[name] = o + return o + + def unpack_l(cls, s, off=0, parent_head=None, _sex=None, _wsize=None): + if _sex is None and _wsize is None: + # get sex and size from parent + if parent_head is not None: + _sex = parent_head._sex + _wsize = parent_head._wsize + else: + _sex = 0 + _wsize = 32 + c = cls(_sex=_sex, _wsize=_wsize) + if parent_head is None: + parent_head = c + c.parent_head = parent_head + + of1 = off + for field in c._fields: + cpt = None + if len(field) == 2: + fname, ffmt = field + elif len(field) == 3: + fname, ffmt, cpt = field + if ffmt in type2realtype or (isinstance(ffmt, str) and re.match(r'\d+s', ffmt)): + # basic types + if cpt: + value = [] + i = 0 + while i < cpt(c): + fmt = real_fmt(ffmt, _wsize) + of2 = of1 + struct.calcsize(fmt) + value.append(struct.unpack(c.sex + fmt, s[of1:of2])[0]) + of1 = of2 + i += 1 + else: + fmt = real_fmt(ffmt, _wsize) + of2 = of1 + struct.calcsize(fmt) + if not (0 <= of1 < len(s) and 0 <= of2 < len(s)): + raise RuntimeError("not enough data") + value = struct.unpack(c.sex + fmt, s[of1:of2])[0] + elif ffmt == "sz": # null terminated special case + of2 = s.find(b'\x00', of1) + if of2 == -1: + raise ValueError('no null char in string!') + of2 += 1 + value = s[of1:of2 - 1] + elif ffmt in all_cstructs: + of2 = of1 + # sub structures + if cpt: + value = [] + i = 0 + while i < cpt(c): + v, l = all_cstructs[ffmt].unpack_l( + s, of1, parent_head, _sex, _wsize) + v.parent = c + value.append(v) + of2 = of1 + l + of1 = of2 + i += 1 + else: + value, l = all_cstructs[ffmt].unpack_l( + s, of1, parent_head, _sex, _wsize) + value.parent = c + of2 = of1 + l + elif isinstance(ffmt, tuple): + f_get, f_set = ffmt + value, of2 = f_get(c, s, of1) + else: + raise ValueError('unknown class', ffmt) + of1 = of2 + setattr(c, fname + c.__class__.field_suffix, value) + + return c, of2 - off + + def unpack(cls, s, off=0, parent_head=None, _sex=None, _wsize=None): + c, l = cls.unpack_l(s, off=off, + parent_head=parent_head, _sex=_sex, _wsize=_wsize) + return c + + +class CStruct(with_metaclass(Cstruct_Metaclass, object)): + _packformat = "" + _fields = [] + + def __init__(self, parent_head=None, _sex=None, _wsize=None, **kargs): + self.parent_head = parent_head + self._size = None + kargs = dict(kargs) + # if not sex or size: get the one of the parent + if _sex == None and _wsize == None: + if parent_head: + _sex = parent_head._sex + _wsize = parent_head._wsize + else: + # else default sex & size + _sex = 0 + _wsize = 32 + # _sex is 0 or 1, sex is '<' or '>' + self._sex = _sex + self._wsize = _wsize + if self._packformat: + self.sex = self._packformat + else: + self.sex = sex_types[_sex] + for f in self._fields: + setattr(self, f[0] + self.__class__.field_suffix, None) + if kargs: + for k, v in viewitems(kargs): + self.__dict__[k + self.__class__.field_suffix] = v + + def pack(self): + out = b'' + for field in self._fields: + cpt = None + if len(field) == 2: + fname, ffmt = field + elif len(field) == 3: + fname, ffmt, cpt = field + + value = getattr(self, fname + self.__class__.field_suffix) + if ffmt in type2realtype or (isinstance(ffmt, str) and re.match(r'\d+s', ffmt)): + # basic types + fmt = real_fmt(ffmt, self._wsize) + if cpt == None: + if value == None: + o = struct.calcsize(fmt) * b"\x00" + else: + if isinstance(value, str): + value = value.encode() + o = struct.pack(self.sex + fmt, value) + else: + o = b"" + for v in value: + if value == None: + o += struct.calcsize(fmt) * b"\x00" + else: + o += struct.pack(self.sex + fmt, v) + + elif ffmt == "sz": # null terminated special case + o = value + b'\x00' + elif ffmt in all_cstructs: + # sub structures + if cpt == None: + o = bytes(value) + else: + o = b"" + for v in value: + o += bytes(v) + elif isinstance(ffmt, tuple): + f_get, f_set = ffmt + o = f_set(self, value) + + else: + raise ValueError('unknown class', ffmt) + out += o + + return out + + def __bytes__(self): + return self.pack() + + def __str__(self): + if PY3: + return repr(self) + return self.__bytes__() + + def __len__(self): + return len(self.pack()) + + def __repr__(self): + return "<%s=%s>" % (self.__class__.__name__, "/".join( + repr(getattr(self, x[0])) for x in self._fields) + ) + + def __getitem__(self, item): # to work with format strings + return getattr(self, item) diff --git a/miasm/elfesteem/pe.py b/miasm/elfesteem/pe.py new file mode 100644 index 000000000..56bffbaab --- /dev/null +++ b/miasm/elfesteem/pe.py @@ -0,0 +1,1668 @@ +#! /usr/bin/env python + +from __future__ import print_function +from builtins import range, str +from collections import defaultdict +import logging +import struct + +from future.builtins import int as int_types +from future.utils import PY3 + +from miasm.core.utils import force_bytes +from miasm.elfesteem.new_cstruct import CStruct +from miasm.elfesteem.strpatchwork import StrPatchwork + +log = logging.getLogger("pepy") +console_handler = logging.StreamHandler() +console_handler.setFormatter(logging.Formatter("%(levelname)-5s: %(message)s")) +log.addHandler(console_handler) +log.setLevel(logging.WARN) + + +class InvalidOffset(Exception): + pass + + +class Doshdr(CStruct): + _fields = [("magic", "u16"), + ("cblp", "u16"), + ("cp", "u16"), + ("crlc", "u16"), + ("cparhdr", "u16"), + ("minalloc", "u16"), + ("maxalloc", "u16"), + ("ss", "u16"), + ("sp", "u16"), + ("csum", "u16"), + ("ip", "u16"), + ("cs", "u16"), + ("lfarlc", "u16"), + ("ovno", "u16"), + ("res", "8s"), + ("oemid", "u16"), + ("oeminfo", "u16"), + ("res2", "20s"), + ("lfanew", "u32")] + + +class NTsig(CStruct): + _fields = [("signature", "u32"), + ] + + +class Coffhdr(CStruct): + _fields = [("machine", "u16"), + ("numberofsections", "u16"), + ("timedatestamp", "u32"), + ("pointertosymboltable", "u32"), + ("numberofsymbols", "u32"), + ("sizeofoptionalheader", "u16"), + ("characteristics", "u16")] + + +class Optehdr(CStruct): + _fields = [("rva", "u32"), + ("size", "u32")] + + +def get_optehdr_num(nthdr): + numberofrva = nthdr.numberofrvaandsizes + parent = nthdr.parent_head + entry_size = 8 + if parent.Coffhdr.sizeofoptionalheader < numberofrva * entry_size + len(parent.Opthdr): + numberofrva = (parent.Coffhdr.sizeofoptionalheader - len(parent.Opthdr)) // entry_size + log.warn('Bad number of rva.. using default %d' % numberofrva) + numberofrva = 0x10 + return numberofrva + + +class Opthdr32(CStruct): + _fields = [("magic", "u16"), + ("majorlinkerversion", "u08"), + ("minorlinkerversion", "u08"), + ("SizeOfCode", "u32"), + ("sizeofinitializeddata", "u32"), + ("sizeofuninitializeddata", "u32"), + ("AddressOfEntryPoint", "u32"), + ("BaseOfCode", "u32"), + ("BaseOfData", "u32"), + ] + + +class Opthdr64(CStruct): + _fields = [("magic", "u16"), + ("majorlinkerversion", "u08"), + ("minorlinkerversion", "u08"), + ("SizeOfCode", "u32"), + ("sizeofinitializeddata", "u32"), + ("sizeofuninitializeddata", "u32"), + ("AddressOfEntryPoint", "u32"), + ("BaseOfCode", "u32"), + ] + + +class NThdr(CStruct): + _fields = [("ImageBase", "ptr"), + ("sectionalignment", "u32"), + ("filealignment", "u32"), + ("majoroperatingsystemversion", "u16"), + ("minoroperatingsystemversion", "u16"), + ("MajorImageVersion", "u16"), + ("MinorImageVersion", "u16"), + ("majorsubsystemversion", "u16"), + ("minorsubsystemversion", "u16"), + ("Reserved1", "u32"), + ("sizeofimage", "u32"), + ("sizeofheaders", "u32"), + ("CheckSum", "u32"), + ("subsystem", "u16"), + ("dllcharacteristics", "u16"), + ("sizeofstackreserve", "ptr"), + ("sizeofstackcommit", "ptr"), + ("sizeofheapreserve", "ptr"), + ("sizeofheapcommit", "ptr"), + ("loaderflags", "u32"), + ("numberofrvaandsizes", "u32"), + ("optentries", "Optehdr", lambda c:get_optehdr_num(c)) + ] + + +class Shdr(CStruct): + _fields = [("name", "8s"), + ("size", "u32"), + ("addr", "u32"), + ("rawsize", "u32"), + ("offset", "u32"), + ("pointertorelocations", "u32"), + ("pointertolinenumbers", "u32"), + ("numberofrelocations", "u16"), + ("numberoflinenumbers", "u16"), + ("flags", "u32")] + + + def get_data(self): + parent = self.parent_head + data = parent.img_rva[self.addr:self.addr + self.size] + return data + + def set_data(self, data): + parent = self.parent_head + parent.img_rva[self.addr] = data + + + data = property(get_data, set_data) + +class SHList(CStruct): + _fields = [ + ("shlist", "Shdr", lambda c:c.parent_head.Coffhdr.numberofsections)] + + def add_section(self, name="default", data=b"", **args): + s_align = self.parent_head.NThdr.sectionalignment + s_align = max(0x1000, s_align) + + f_align = self.parent_head.NThdr.filealignment + f_align = max(0x200, f_align) + size = len(data) + rawsize = len(data) + if len(self): + addr = self[-1].addr + self[-1].size + s_last = self[0] + for section in self: + if s_last.offset + s_last.rawsize < section.offset + section.rawsize: + s_last = section + offset = s_last.offset + s_last.rawsize + else: + s_null = bytes(Shdr.unpack(b"\x00" * 0x100)) + offset = self.parent_head.Doshdr.lfanew + len(self.parent_head.NTsig) + len( + self.parent_head.Coffhdr) + self.parent_head.Coffhdr.sizeofoptionalheader + len(bytes(self.parent_head.SHList) + s_null) + addr = 0x2000 + # round addr + addr = (addr + (s_align - 1)) & ~(s_align - 1) + offset = (offset + (f_align - 1)) & ~(f_align - 1) + + attrs = {"name": name, "size": size, + "addr": addr, "rawsize": rawsize, + "offset": offset, + "pointertorelocations": 0, + "pointertolinenumbers": 0, + "numberofrelocations": 0, + "numberoflinenumbers": 0, + "flags": 0xE0000020, + "data": data + } + attrs.update(args) + section = Shdr(self.parent_head, _sex=self.parent_head._sex, + _wsize=self.parent_head._wsize, **attrs) + section.data = data + + if section.rawsize > len(data): + section.data = section.data + b'\x00' * (section.rawsize - len(data)) + section.size = section.rawsize + section.data = bytes(StrPatchwork(section.data)) + section.size = max(s_align, section.size) + + self.append(section) + self.parent_head.Coffhdr.numberofsections = len(self) + + length = (section.addr + section.size + (s_align - 1)) & ~(s_align - 1) + self.parent_head.NThdr.sizeofimage = length + return section + + def align_sections(self, f_align=None, s_align=None): + if f_align == None: + f_align = self.parent_head.NThdr.filealignment + f_align = max(0x200, f_align) + if s_align == None: + s_align = self.parent_head.NThdr.sectionalignment + s_align = max(0x1000, s_align) + + if self is None: + return + + addr = self[0].offset + for section in self: + raw_off = f_align * ((addr + f_align - 1) // f_align) + section.offset = raw_off + section.rawsize = len(section.data) + addr = raw_off + section.rawsize + + def __repr__(self): + rep = ["# section offset size addr flags rawsize "] + for i, section in enumerate(self): + name = force_bytes(section.name) + out = "%-15s" % name.strip(b'\x00').decode() + out += "%(offset)08x %(size)06x %(addr)08x %(flags)08x %(rawsize)08x" % section + out = ("%2i " % i) + out + rep.append(out) + return "\n".join(rep) + + def __getitem__(self, item): + return self.shlist[item] + + def __len__(self): + return len(self.shlist) + + def append(self, section): + self.shlist.append(section) + + +class Rva(CStruct): + _fields = [("rva", "ptr"), + ] + + +class Rva32(CStruct): + _fields = [("rva", "u32"), + ] + + +class DescName(CStruct): + _fields = [("name", (lambda c, raw, off: c.gets(raw, off), + lambda c, value: c.sets(value))) + ] + + def gets(self, raw, off): + name = raw[off:raw.find(b'\x00', off)] + return name, off + len(name) + 1 + + def sets(self, value): + return bytes(value) + b"\x00" + + +class ImportByName(CStruct): + _fields = [("hint", "u16"), + ("name", "sz") + ] + + +class ImpDesc_e(CStruct): + _fields = [("originalfirstthunk", "u32"), + ("timestamp", "u32"), + ("forwarderchain", "u32"), + ("name", "u32"), + ("firstthunk", "u32") + ] + + +class struct_array(object): + + def __init__(self, target_class, raw, off, cstr, num=None): + self.l = [] + self.cls = target_class + self.end = None + i = 0 + if not raw: + return + + while (num == None) or (num and i < num): + entry, length = cstr.unpack_l(raw, off, + target_class.parent_head, + target_class.parent_head._sex, + target_class.parent_head._wsize) + if num == None: + if raw[off:off + length] == b'\x00' * length: + self.end = b'\x00' * length + break + self.l.append(entry) + off += length + i += 1 + + def __bytes__(self): + out = b"".join(bytes(x) for x in self.l) + if self.end is not None: + out += self.end + return out + + def __str__(self): + if PY3: + return repr(self) + return self.__bytes__() + + def __getitem__(self, item): + return self.l.__getitem__(item) + + def __len__(self): + return len(self.l) + + def append(self, entry): + self.l.append(entry) + + def insert(self, index, entry): + self.l.insert(index, entry) + + +class DirImport(CStruct): + _fields = [("impdesc", (lambda c, raw, off:c.gete(raw, off), + lambda c, value:c.sete(value)))] + + def gete(self, raw, off): + if not off: + return None, off + if self.parent_head._wsize == 32: + mask_ptr = 0x80000000 + elif self.parent_head._wsize == 64: + mask_ptr = 0x8000000000000000 + + ofend = off + \ + self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_IMPORT].size + out = [] + while off < ofend: + if not 0 <= off < len(self.parent_head.img_rva): + break + imp, length = ImpDesc_e.unpack_l(raw, off) + if (raw[off:off+length] == b'\x00' * length or + imp.name == 0): + # Special case + break + if not (imp.originalfirstthunk or imp.firstthunk): + log.warning("no thunk!!") + break + + out.append(imp) + off += length + imp.dlldescname = DescName.unpack(raw, imp.name, self.parent_head) + if imp.originalfirstthunk and imp.originalfirstthunk < len(self.parent_head.img_rva): + imp.originalfirstthunks = struct_array(self, raw, + imp.originalfirstthunk, + Rva) + else: + imp.originalfirstthunks = None + + if imp.firstthunk and imp.firstthunk < len(self.parent_head.img_rva): + imp.firstthunks = struct_array(self, raw, + imp.firstthunk, + Rva) + else: + imp.firstthunks = None + imp.impbynames = [] + if imp.originalfirstthunk and imp.originalfirstthunk < len(self.parent_head.img_rva): + tmp_thunk = imp.originalfirstthunks + elif imp.firstthunk: + tmp_thunk = imp.firstthunks + for i in range(len(tmp_thunk)): + if tmp_thunk[i].rva & mask_ptr == 0: + try: + entry = ImportByName.unpack(raw, + tmp_thunk[i].rva, + self.parent_head) + except: + log.warning( + 'cannot import from add %s' % tmp_thunk[i].rva + ) + entry = 0 + imp.impbynames.append(entry) + else: + imp.impbynames.append(tmp_thunk[i].rva & (mask_ptr - 1)) + return out, off + + def sete(self, entries): + return b"".join(bytes(entry) for entry in entries) + b"\x00" * (4 * 5) + + def __len__(self): + length = (len(self.impdesc) + 1) * (5 * 4) # ImpDesc_e size + rva_size = self.parent_head._wsize // 8 + for entry in self.impdesc: + length += len(entry.dlldescname) + if entry.originalfirstthunk and self.parent_head.rva2off(entry.originalfirstthunk): + length += (len(entry.originalfirstthunks) + 1) * rva_size + if entry.firstthunk: + length += (len(entry.firstthunks) + 1) * rva_size + for imp in entry.impbynames: + if isinstance(imp, ImportByName): + length += len(imp) + return length + + def set_rva(self, rva, size=None): + self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_IMPORT].rva = rva + rva_size = self.parent_head._wsize // 8 + if not size: + self.parent_head.NThdr.optentries[ + DIRECTORY_ENTRY_IMPORT].size = len(self) + else: + self.parent_head.NThdr.optentries[ + DIRECTORY_ENTRY_IMPORT].size = size + rva += (len(self.impdesc) + 1) * 5 * 4 # ImpDesc size + for entry in self.impdesc: + entry.name = rva + rva += len(entry.dlldescname) + if entry.originalfirstthunk: # and self.parent_head.rva2off(entry.originalfirstthunk): + entry.originalfirstthunk = rva + rva += (len(entry.originalfirstthunks) + 1) * rva_size + # XXX rva fthunk not patched => keep original func addr + # if entry.firstthunk: + # entry.firstthunk = rva + # rva+=(len(entry.firstthunks)+1)*self.parent_head._wsize//8 # Rva size + if entry.originalfirstthunk and entry.firstthunk: + if isinstance(entry.originalfirstthunk, struct_array): + tmp_thunk = entry.originalfirstthunks + elif isinstance(entry.firstthunks, struct_array): + tmp_thunk = entry.firstthunks + else: + raise RuntimeError("No thunk!") + elif entry.originalfirstthunk: # and self.parent_head.rva2off(entry.originalfirstthunk): + tmp_thunk = entry.originalfirstthunks + elif entry.firstthunk: + tmp_thunk = entry.firstthunks + else: + raise RuntimeError("No thunk!") + + if tmp_thunk == entry.originalfirstthunks: + entry.firstthunks = tmp_thunk + else: + entry.originalfirstthunks = tmp_thunk + for i, imp in enumerate(entry.impbynames): + if isinstance(imp, ImportByName): + tmp_thunk[i].rva = rva + rva += len(imp) + + def build_content(self, raw): + dirimp = self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_IMPORT] + of1 = dirimp.rva + if not of1: # No Import + return + raw[self.parent_head.rva2off(of1)] = bytes(self) + for entry in self.impdesc: + raw[self.parent_head.rva2off(entry.name)] = bytes(entry.dlldescname) + if (entry.originalfirstthunk and + self.parent_head.rva2off(entry.originalfirstthunk)): + # Add thunks list and terminating null entry + off = self.parent_head.rva2off(entry.originalfirstthunk) + raw[off] = bytes(entry.originalfirstthunks) + if entry.firstthunk: + # Add thunks list and terminating null entry + off = self.parent_head.rva2off(entry.firstthunk) + raw[off] = bytes(entry.firstthunks) + if (entry.originalfirstthunk and + self.parent_head.rva2off(entry.originalfirstthunk)): + tmp_thunk = entry.originalfirstthunks + elif entry.firstthunk: + tmp_thunk = entry.firstthunks + else: + raise RuntimeError("No thunk!") + for j, imp in enumerate(entry.impbynames): + if isinstance(imp, ImportByName): + raw[self.parent_head.rva2off(tmp_thunk[j].rva)] = bytes(imp) + + def get_dlldesc(self): + out = [] + for impdesc in self.impdesc: + dllname = impdesc.dlldescname.name + funcs = [] + for imp in impdesc.impbynames: + if isinstance(imp, ImportByName): + funcs.append(imp.name) + else: + funcs.append(imp) + entry = ({"name": dllname, "firstthunk": impdesc.firstthunk}, funcs) + out.append(entry) + return out + + def __repr__(self): + rep = ["<%s>" % self.__class__.__name__] + for i, entry in enumerate(self.impdesc): + out = "%2d %-25s %s" % (i, repr(entry.dlldescname), repr(entry)) + rep.append(out) + for index, imp in enumerate(entry.impbynames): + out = " %2d %-16s" % (index, repr(imp)) + rep.append(out) + return "\n".join(rep) + + def add_dlldesc(self, new_dll): + rva_size = self.parent_head._wsize // 8 + if self.parent_head._wsize == 32: + mask_ptr = 0x80000000 + elif self.parent_head._wsize == 64: + mask_ptr = 0x8000000000000000 + new_impdesc = [] + of1 = None + for import_descriptor, new_functions in new_dll: + if isinstance(import_descriptor.get("name"), str): + import_descriptor["name"] = import_descriptor["name"].encode() + new_functions = [ + funcname.encode() if isinstance(funcname, str) else funcname + for funcname in new_functions + ] + for attr in ["timestamp", "forwarderchain", "originalfirstthunk"]: + if attr not in import_descriptor: + import_descriptor[attr] = 0 + entry = ImpDesc_e(self.parent_head, **import_descriptor) + if entry.firstthunk != None: + of1 = entry.firstthunk + elif of1 == None: + raise RuntimeError("set fthunk") + else: + entry.firstthunk = of1 + entry.dlldescname = DescName(self.parent_head, name=entry.name) + entry.originalfirstthunk = 0 + entry.originalfirstthunks = struct_array(self, None, + None, + Rva) + entry.firstthunks = struct_array(self, None, + None, + Rva) + + impbynames = [] + for new_function in new_functions: + rva_ofirstt = Rva(self.parent_head) + if isinstance(new_function, int_types): + rva_ofirstt.rva = mask_ptr + new_function + ibn = new_function + elif isinstance(new_function, bytes): + rva_ofirstt.rva = True + ibn = ImportByName(self.parent_head) + ibn.name = new_function + ibn.hint = 0 + else: + raise RuntimeError('unknown func type %s' % new_function) + impbynames.append(ibn) + entry.originalfirstthunks.append(rva_ofirstt) + rva_func = Rva(self.parent_head) + if isinstance(ibn, ImportByName): + rva_func.rva = 0xDEADBEEF # default func addr + else: + # ord ?XXX? + rva_func.rva = rva_ofirstt.rva + entry.firstthunks.append(rva_func) + of1 += rva_size + # for null thunk + of1 += rva_size + entry.impbynames = impbynames + new_impdesc.append(entry) + if self.impdesc is None: + self.impdesc = struct_array(self, None, + None, + ImpDesc_e) + self.impdesc.l = new_impdesc + else: + for entry in new_impdesc: + self.impdesc.append(entry) + + def get_funcrva(self, dllname, funcname): + dllname = force_bytes(dllname) + funcname = force_bytes(funcname) + + rva_size = self.parent_head._wsize // 8 + if self.parent_head._wsize == 32: + mask_ptr = 0x80000000 - 1 + elif self.parent_head._wsize == 64: + mask_ptr = 0x8000000000000000 - 1 + + for entry in self.impdesc: + if entry.dlldescname.name.lower() != dllname.lower(): + continue + if entry.originalfirstthunk and self.parent_head.rva2off(entry.originalfirstthunk): + tmp_thunk = entry.originalfirstthunks + elif entry.firstthunk: + tmp_thunk = entry.firstthunks + else: + raise RuntimeError("No thunk!") + if isinstance(funcname, bytes): + for j, imp in enumerate(entry.impbynames): + if isinstance(imp, ImportByName): + if funcname == imp.name: + return entry.firstthunk + j * rva_size + elif isinstance(funcname, int_types): + for j, imp in enumerate(entry.impbynames): + if not isinstance(imp, ImportByName): + if tmp_thunk[j].rva & mask_ptr == funcname: + return entry.firstthunk + j * rva_size + else: + raise ValueError('Unknown: %s %s' % (dllname, funcname)) + + def get_funcvirt(self, dllname, funcname): + rva = self.get_funcrva(dllname, funcname) + if rva == None: + return + return self.parent_head.rva2virt(rva) + + +class ExpDesc_e(CStruct): + _fields = [("characteristics", "u32"), + ("timestamp", "u32"), + ("majorv", "u16"), + ("minorv", "u16"), + ("name", "u32"), + ("base", "u32"), + ("numberoffunctions", "u32"), + ("numberofnames", "u32"), + ("addressoffunctions", "u32"), + ("addressofnames", "u32"), + ("addressofordinals", "u32"), + ] + + +class DirExport(CStruct): + _fields = [("expdesc", (lambda c, raw, off:c.gete(raw, off), + lambda c, value:c.sete(value)))] + + def gete(self, raw, off): + off_o = off + if not off: + return None, off + off_sav = off + if off >= len(raw): + log.warn("export dir malformed!") + return None, off_o + expdesc = ExpDesc_e.unpack(raw, + off, + self.parent_head) + if self.parent_head.rva2off(expdesc.addressoffunctions) == None or \ + self.parent_head.rva2off(expdesc.addressofnames) == None or \ + self.parent_head.rva2off(expdesc.addressofordinals) == None: + log.warn("export dir malformed!") + return None, off_o + self.dlldescname = DescName.unpack(raw, expdesc.name, self.parent_head) + try: + self.f_address = struct_array(self, raw, + expdesc.addressoffunctions, + Rva32, expdesc.numberoffunctions) + self.f_names = struct_array(self, raw, + expdesc.addressofnames, + Rva32, expdesc.numberofnames) + self.f_nameordinals = struct_array(self, raw, + expdesc.addressofordinals, + Ordinal, expdesc.numberofnames) + except RuntimeError: + log.warn("export dir malformed!") + return None, off_o + for func in self.f_names: + func.name = DescName.unpack(raw, func.rva, self.parent_head) + return expdesc, off_sav + + def sete(self, _): + return bytes(self.expdesc) + + def build_content(self, raw): + direxp = self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_EXPORT] + of1 = direxp.rva + if self.expdesc is None: # No Export + return + raw[self.parent_head.rva2off(of1)] = bytes(self.expdesc) + raw[self.parent_head.rva2off(self.expdesc.name)] = bytes(self.dlldescname) + raw[self.parent_head.rva2off(self.expdesc.addressoffunctions)] = bytes(self.f_address) + if self.expdesc.addressofnames != 0: + raw[self.parent_head.rva2off(self.expdesc.addressofnames)] = bytes(self.f_names) + if self.expdesc.addressofordinals != 0: + raw[self.parent_head.rva2off(self.expdesc.addressofordinals)] = bytes(self.f_nameordinals) + for func in self.f_names: + raw[self.parent_head.rva2off(func.rva)] = bytes(func.name) + + # XXX BUG names must be alphanumeric ordered + names = [func.name for func in self.f_names] + names_ = names[:] + if names != names_: + log.warn("unsorted export names, may bug") + + def set_rva(self, rva, size=None): + rva_size = self.parent_head._wsize // 8 + if self.expdesc is None: + return + self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_EXPORT].rva = rva + if not size: + self.parent_head.NThdr.optentries[ + DIRECTORY_ENTRY_EXPORT].size = len(self) + else: + self.parent_head.NThdr.optentries[ + DIRECTORY_ENTRY_EXPORT].size = size + rva += len(self.expdesc) + self.expdesc.name = rva + rva += len(self.dlldescname) + self.expdesc.addressoffunctions = rva + rva += len(self.f_address) * rva_size + self.expdesc.addressofnames = rva + rva += len(self.f_names) * rva_size + self.expdesc.addressofordinals = rva + rva += len(self.f_nameordinals) * 2 # Ordinal size + for func in self.f_names: + func.rva = rva + rva += len(func.name) + + def __len__(self): + rva_size = self.parent_head._wsize // 8 + length = 0 + if self.expdesc is None: + return length + length += len(self.expdesc) + length += len(self.dlldescname) + length += len(self.f_address) * rva_size + length += len(self.f_names) * rva_size + length += len(self.f_nameordinals) * 2 # Ordinal size + for entry in self.f_names: + length += len(entry.name) + return length + + def __repr__(self): + rep = ["<%s>" % self.__class__.__name__] + if self.expdesc is None: + return "\n".join(rep) + + rep = ["<%s %d (%s) %s>" % (self.__class__.__name__, + self.expdesc.numberoffunctions, self.dlldescname, repr(self.expdesc))] + tmp_names = [[] for _ in range(self.expdesc.numberoffunctions)] + for i, entry in enumerate(self.f_names): + tmp_names[self.f_nameordinals[i].ordinal].append(entry.name) + for i, entry in enumerate(self.f_address): + tmpn = [] + if not entry.rva: + continue + out = "%2d %.8X %s" % (i + self.expdesc.base, entry.rva, repr(tmp_names[i])) + rep.append(out) + return "\n".join(rep) + + def create(self, name='default.dll'): + self.expdesc = ExpDesc_e(self.parent_head) + for attr in ["characteristics", + "timestamp", + "majorv", + "minorv", + "name", + "base", + "numberoffunctions", + "numberofnames", + "addressoffunctions", + "addressofnames", + "addressofordinals", + ]: + setattr(self.expdesc, attr, 0) + + self.dlldescname = DescName(self.parent_head) + self.dlldescname.name = name + self.f_address = struct_array(self, None, + None, + Rva) + self.f_names = struct_array(self, None, + None, + Rva) + self.f_nameordinals = struct_array(self, None, + None, + Ordinal) + self.expdesc.base = 1 + + def add_name(self, name, rva=0xdeadc0fe): + if self.expdesc is None: + return + names = [func.name.name for func in self.f_names] + names_s = names[:] + names_s.sort() + if names_s != names: + log.warn('tab names was not sorted may bug') + names.append(name) + names.sort() + index = names.index(name) + descname = DescName(self.parent_head) + + descname.name = name + wname = Rva(self.parent_head) + + wname.name = descname + woffset = Rva(self.parent_head) + woffset.rva = rva + wordinal = Ordinal(self.parent_head) + # func is append to list + wordinal.ordinal = len(self.f_address) + self.f_address.append(woffset) + # self.f_names.insert(index, wname) + # self.f_nameordinals.insert(index, wordinal) + self.f_names.insert(index, wname) + self.f_nameordinals.insert(index, wordinal) + self.expdesc.numberofnames += 1 + self.expdesc.numberoffunctions += 1 + + def get_funcrva(self, f_str): + if self.expdesc is None: + return None + for i, entry in enumerate(self.f_names): + if f_str != entry.name.name: + continue + ordinal = self.f_nameordinals[i].ordinal + rva = self.f_address[ordinal].rva + return rva + return None + + def get_funcvirt(self, addr): + rva = self.get_funcrva(addr) + if rva == None: + return + return self.parent_head.rva2virt(rva) + + +class Delaydesc_e(CStruct): + _fields = [("attrs", "u32"), + ("name", "u32"), + ("hmod", "u32"), + ("firstthunk", "u32"), + ("originalfirstthunk", "u32"), + ("boundiat", "u32"), + ("unloadiat", "u32"), + ("timestamp", "u32"), + ] + + +class DirDelay(CStruct): + _fields = [("delaydesc", (lambda c, raw, off:c.gete(raw, off), + lambda c, value:c.sete(value)))] + + def gete(self, raw, off): + if not off: + return None, off + + ofend = off + \ + self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_DELAY_IMPORT].size + out = [] + while off < ofend: + if off >= len(raw): + log.warn('warning bad reloc offset') + break + + delaydesc, length = Delaydesc_e.unpack_l(raw, + off, + self.parent_head) + if raw[off:off+length] == b'\x00' * length: + # Special case + break + off += length + out.append(delaydesc) + + if self.parent_head._wsize == 32: + mask_ptr = 0x80000000 + elif self.parent_head._wsize == 64: + mask_ptr = 0x8000000000000000 + + parent = self.parent_head + for entry in out: + isfromva = (entry.attrs & 1) == 0 + if isfromva: + isfromva = lambda x: parent.virt2rva(x) + else: + isfromva = lambda x: x + entry.dlldescname = DescName.unpack(raw, isfromva(entry.name), + self.parent_head) + if entry.originalfirstthunk: + addr = isfromva(entry.originalfirstthunk) + if not 0 <= addr < len(raw): + log.warning("Bad delay") + break + entry.originalfirstthunks = struct_array(self, raw, + addr, + Rva) + else: + entry.originalfirstthunks + + if entry.firstthunk: + entry.firstthunks = struct_array(self, raw, + isfromva(entry.firstthunk), + Rva) + else: + entry.firstthunk = None + + entry.impbynames = [] + if entry.originalfirstthunk and self.parent_head.rva2off(isfromva(entry.originalfirstthunk)): + tmp_thunk = entry.originalfirstthunks + elif entry.firstthunk: + tmp_thunk = entry.firstthunks + else: + print(ValueError("no thunk in delay dir!! ")) + return + for i in range(len(tmp_thunk)): + if tmp_thunk[i].rva & mask_ptr == 0: + imp = ImportByName.unpack(raw, + isfromva(tmp_thunk[i].rva), + self.parent_head) + entry.impbynames.append(imp) + else: + entry.impbynames.append( + isfromva(tmp_thunk[i].rva & (mask_ptr - 1))) + # print(repr(entry[-1])) + # raise ValueError('XXX to check') + return out, off + + def sete(self, entries): + return "".join(bytes(entry) for entry in entries) + b"\x00" * (4 * 8) # DelayDesc_e + + def __len__(self): + rva_size = self.parent_head._wsize // 8 + length = (len(self.delaydesc) + 1) * (4 * 8) # DelayDesc_e + for entry in self.delaydesc: + length += len(entry.dlldescname) + if entry.originalfirstthunk and self.parent_head.rva2off(entry.originalfirstthunk): + length += (len(entry.originalfirstthunks) + 1) * rva_size + if entry.firstthunk: + length += (len(entry.firstthunks) + 1) * rva_size + for imp in entry.impbynames: + if isinstance(imp, ImportByName): + length += len(imp) + return length + + def set_rva(self, rva, size=None): + rva_size = self.parent_head._wsize // 8 + self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_DELAY_IMPORT].rva = rva + if not size: + self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_DELAY_IMPORT].size = len(self) + else: + self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_DELAY_IMPORT].size = size + rva += (len(self.delaydesc) + 1) * (4 * 8) # DelayDesc_e + parent = self.parent_head + for entry in self.delaydesc: + isfromva = (entry.attrs & 1) == 0 + if isfromva: + isfromva = lambda x: self.parent_head.rva2virt(x) + else: + isfromva = lambda x: x + + entry.name = isfromva(rva) + rva += len(entry.dlldescname) + if entry.originalfirstthunk: # and self.parent_head.rva2off(entry.originalfirstthunk): + entry.originalfirstthunk = isfromva(rva) + rva += (len(entry.originalfirstthunks) + 1) * rva_size + # XXX rva fthunk not patched => fun addr + # if entry.firstthunk: + # entry.firstthunk = rva + # rva+=(len(entry.firstthunks)+1)*pe.Rva._size + if entry.originalfirstthunk and self.parent_head.rva2off(entry.originalfirstthunk): + tmp_thunk = entry.originalfirstthunks + elif entry.firstthunk: + tmp_thunk = entry.firstthunks + else: + raise RuntimeError("No thunk!") + for i, imp in enumerate(entry.impbynames): + if isinstance(imp, ImportByName): + tmp_thunk[i].rva = isfromva(rva) + rva += len(imp) + + def build_content(self, raw): + if len(self.parent_head.NThdr.optentries) < DIRECTORY_ENTRY_DELAY_IMPORT: + return + dirdelay = self.parent_head.NThdr.optentries[ + DIRECTORY_ENTRY_DELAY_IMPORT] + of1 = dirdelay.rva + if not of1: # No Delay Import + return + raw[self.parent_head.rva2off(of1)] = bytes(self) + for entry in self.delaydesc: + raw[self.parent_head.rva2off(entry.name)] = bytes(entry.dlldescname) + if entry.originalfirstthunk and self.parent_head.rva2off(entry.originalfirstthunk): + raw[self.parent_head.rva2off(entry.originalfirstthunk)] = bytes(entry.originalfirstthunks) + if entry.firstthunk: + raw[self.parent_head.rva2off(entry.firstthunk)] = bytes(entry.firstthunks) + if entry.originalfirstthunk and self.parent_head.rva2off(entry.originalfirstthunk): + tmp_thunk = entry.originalfirstthunks + elif entry.firstthunk: + tmp_thunk = entry.firstthunks + else: + raise RuntimeError("No thunk!") + for j, imp in enumerate(entry.impbynames): + if isinstance(imp, ImportByName): + raw[self.parent_head.rva2off(tmp_thunk[j].rva)] = bytes(imp) + + def __repr__(self): + rep = ["<%s>" % self.__class__.__name__] + for i, entry in enumerate(self.delaydesc): + out = "%2d %-25s %s" % (i, repr(entry.dlldescname), repr(entry)) + rep.append(out) + for index, func in enumerate(entry.impbynames): + out = " %2d %-16s" % (index, repr(func)) + rep.append(out) + return "\n".join(rep) + + def add_dlldesc(self, new_dll): + if self.parent_head._wsize == 32: + mask_ptr = 0x80000000 + elif self.parent_head._wsize == 64: + mask_ptr = 0x8000000000000000 + new_impdesc = [] + of1 = None + new_delaydesc = [] + for import_descriptor, new_functions in new_dll: + if isinstance(import_descriptor.get("name"), str): + import_descriptor["name"] = import_descriptor["name"].encode() + new_functions = [ + funcname.encode() if isinstance(funcname, str) else funcname + for funcname in new_functions + ] + for attr in ["attrs", "name", "hmod", "firstthunk", "originalfirstthunk", "boundiat", "unloadiat", "timestamp"]: + if not attr in import_descriptor: + import_descriptor[attr] = 0 + entry = Delaydesc_e(self.parent_head, **import_descriptor) + # entry.cstr.__dict__.update(import_descriptor) + if entry.firstthunk != None: + of1 = entry.firstthunk + elif of1 == None: + raise RuntimeError("set fthunk") + else: + entry.firstthunk = of1 + entry.dlldescname = DescName(self.parent_head, name=entry.name) + entry.originalfirstthunk = 0 + entry.originalfirstthunks = struct_array(self, None, + None, + Rva) + entry.firstthunks = struct_array(self, None, + None, + Rva) + + impbynames = [] + for new_function in new_functions: + rva_ofirstt = Rva(self.parent_head) + if isinstance(new_function, int_types): + rva_ofirstt.rva = mask_ptr + new_function + ibn = None + elif isinstance(new_function, bytes): + rva_ofirstt.rva = True + ibn = ImportByName(self.parent_head) + ibn.name = new_function + ibn.hint = 0 + else: + raise RuntimeError('unknown func type %s' % new_function) + impbynames.append(ibn) + entry.originalfirstthunks.append(rva_ofirstt) + + rva_func = Rva(self.parent_head) + if ibn != None: + rva_func.rva = 0xDEADBEEF # default func addr + else: + # ord ?XXX? + rva_func.rva = rva_ofirstt.rva + entry.firstthunks.append(rva_func) + of1 += 4 + # for null thunk + of1 += 4 + entry.impbynames = impbynames + new_delaydesc.append(entry) + if self.delaydesc is None: + self.delaydesc = struct_array(self, None, + None, + Delaydesc_e) + self.delaydesc.l = new_delaydesc + else: + for entry in new_delaydesc: + self.delaydesc.append(entry) + + def get_funcrva(self, func): + for entry in self.delaydesc: + isfromva = (entry.attrs & 1) == 0 + if isfromva: + isfromva = lambda x: self.parent_head.virt2rva(x) + else: + isfromva = lambda x: x + if entry.originalfirstthunk and self.parent_head.rva2off(isfromva(entry.originalfirstthunk)): + tmp_thunk = entry.originalfirstthunks + elif entry.firstthunk: + tmp_thunk = entry.firstthunks + else: + raise RuntimeError("No thunk!") + if isinstance(func, bytes): + for j, imp in enumerate(entry.impbynames): + if isinstance(imp, ImportByName): + if func == imp.name: + return isfromva(entry.firstthunk) + j * 4 + elif isinstance(func, int_types): + for j, imp in enumerate(entry.impbynames): + if not isinstance(imp, ImportByName): + if isfromva(tmp_thunk[j].rva & 0x7FFFFFFF) == func: + return isfromva(entry.firstthunk) + j * 4 + else: + raise ValueError('unknown func tpye %r' % func) + + def get_funcvirt(self, addr): + rva = self.get_funcrva(addr) + if rva == None: + return + return self.parent_head.rva2virt(rva) + + +class Rel(CStruct): + _fields = [("rva", "u32"), + ("size", "u32") + ] + + +class Reloc(CStruct): + _fields = [("rel", (lambda c, raw, off:c.gete(raw, off), + lambda c, value:c.sete(value)))] + + def gete(self, raw, off): + rel = struct.unpack('H', raw[off:off + 2])[0] + return (rel >> 12, rel & 0xfff), off + 2 + + def sete(self, value): + return struct.pack('H', (value[0] << 12) | value[1]) + + def __repr__(self): + return '<%d %d>' % (self.rel[0], self.rel[1]) + + +class DirReloc(CStruct): + _fields = [("reldesc", (lambda c, raw, off:c.gete(raw, off), + lambda c, value:c.sete(value)))] + + def gete(self, raw, off): + if not off: + return None, off + + ofend = off + \ + self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_BASERELOC].size + out = [] + while off < ofend: + if off >= len(raw): + log.warn('warning bad reloc offset') + break + reldesc, length = Rel.unpack_l(raw, + off, + self.parent_head) + if reldesc.size == 0: + log.warn('warning null reldesc') + reldesc.size = length + break + of2 = off + length + if of2 + reldesc.size > len(self.parent_head.img_rva): + log.warn('relocation too big, skipping') + break + reldesc.rels = struct_array(self, raw, + of2, + Reloc, + (reldesc.size - length) // 2) # / Reloc size + reldesc.patchrel = False + out.append(reldesc) + off += reldesc.size + return out, off + + def sete(self, entries): + return b"".join( + bytes(entry) + bytes(entry.rels) + for entry in entries + ) + + def set_rva(self, rva, size=None): + if self.reldesc is None: + return + self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_BASERELOC].rva = rva + if not size: + self.parent_head.NThdr.optentries[ + DIRECTORY_ENTRY_BASERELOC].size = len(self) + else: + self.parent_head.NThdr.optentries[ + DIRECTORY_ENTRY_BASERELOC].size = size + + def build_content(self, raw): + dirrel = self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_BASERELOC] + dirrel.size = len(self) + of1 = dirrel.rva + if self.reldesc is None: # No Reloc + return + raw[self.parent_head.rva2off(of1)] = bytes(self) + + def __len__(self): + if self.reldesc is None: + return 0 + length = 0 + for entry in self.reldesc: + length += entry.size + return length + + def __bytes__(self): + return b"".join( + bytes(entry) + bytes(entry.rels) + for entry in self.reldesc + ) + + def __str__(self): + if PY3: + return repr(self) + return self.__bytes__() + + def __repr__(self): + rep = ["<%s>" % self.__class__.__name__] + if self.reldesc is None: + return "\n".join(rep) + for i, entry in enumerate(self.reldesc): + out = "%2d %s" % (i, repr(entry)) + rep.append(out) + """ + #display too many lines... + for ii, m in enumerate(entry.rels): + l = "\t%2d %s"%(ii, repr(m) ) + rep.append(l) + """ + out = "\t%2d rels..." % (len(entry.rels)) + rep.append(out) + return "\n".join(rep) + + def add_reloc(self, rels, rtype=3, patchrel=True): + dirrel = self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_BASERELOC] + if not rels: + return + rels.sort() + all_base_ad = set([x & 0xFFFFF000 for x in rels]) + all_base_ad = list(all_base_ad) + all_base_ad.sort() + rels_by_base = defaultdict(list) + while rels: + reloc = rels.pop() + if reloc >= all_base_ad[-1]: + rels_by_base[all_base_ad[-1]].append(reloc) + else: + all_base_ad.pop() + rels_by_base[all_base_ad[-1]].append(reloc) + rels_by_base = [x for x in list(rels_by_base.items())] + rels_by_base.sort() + for o_init, rels in rels_by_base: + # o_init = rels[0]&0xFFFFF000 + offsets = struct_array(self, None, None, Reloc, 0) + for reloc_value in rels: + if (reloc_value & 0xFFFFF000) != o_init: + raise RuntimeError("relocs must be in same range") + reloc = Reloc(self.parent_head) + reloc.rel = (rtype, reloc_value - o_init) + offsets.append(reloc) + while len(offsets) & 3: + reloc = Reloc(self.parent_head) + reloc.rel = (0, 0) + offsets.append(reloc) + reldesc = Rel(self.parent_head) # Reloc(self.parent_head) + reldesc.rva = o_init + reldesc.size = (len(offsets) * 2 + 8) + reldesc.rels = offsets + reldesc.patchrel = patchrel + # if self.reldesc is None: + # self.reldesc = [] + self.reldesc.append(reldesc) + dirrel.size += reldesc.size + + def del_reloc(self, taboffset): + if self.reldesc is None: + return + for rel in self.reldesc: + of1 = rel.rva + i = 0 + while i < len(rel.rels): + reloc = rel.rels[i] + if reloc.rel[0] != 0 and reloc.rel[1] + of1 in taboffset: + print('del reloc', hex(reloc.rel[1] + of1)) + del rel.rels[i] + rel.size -= Reloc._size + else: + i += 1 + + +class DirRes(CStruct): + _fields = [("resdesc", (lambda c, raw, off:c.gete(raw, off), + lambda c, value:c.sete(value)))] + + def gete(self, raw, off): + if not off: + return None, off + if off >= len(self.parent_head.img_rva): + log.warning('cannot parse resources, %X' % off) + return None, off + + off_orig = off + ofend = off + self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_RESOURCE].size + + resdesc, length = ResDesc_e.unpack_l(raw, + off, + self.parent_head) + off += length + nbr = resdesc.numberofnamedentries + resdesc.numberofidentries + + out = [] + tmp_off = off + for _ in range(nbr): + if tmp_off >= ofend: + break + if tmp_off + length >= len(raw): + log.warn('warning bad resource offset') + break + try: + entry, length = ResEntry.unpack_l(raw, tmp_off, self.parent_head) + except RuntimeError: + log.warn('bad resentry') + return None, tmp_off + out.append(entry) + tmp_off += length + resdesc.resentries = struct_array(self, raw, + off, + ResEntry, + nbr) + dir_todo = {off_orig: resdesc} + dir_done = {} + while dir_todo: + off, my_dir = dir_todo.popitem() + dir_done[off] = my_dir + for entry in my_dir.resentries: + off = entry.offsettosubdir + if not off: + # data dir + off = entry.offsettodata + if not 0 <= off < len(raw): + log.warn('bad resrouce entry') + continue + data = ResDataEntry.unpack(raw, + off, + self.parent_head) + off = data.offsettodata + data.s = StrPatchwork(raw[off:off + data.size]) + entry.data = data + continue + # subdir + if off in dir_done: + log.warn('warning recusif subdir') + continue + if not 0 <= off < len(self.parent_head.img_rva): + log.warn('bad resrouce entry') + continue + subdir, length = ResDesc_e.unpack_l(raw, + off, + self.parent_head) + nbr = subdir.numberofnamedentries + subdir.numberofidentries + try: + subdir.resentries = struct_array(self, raw, + off + length, + ResEntry, + nbr) + except RuntimeError: + log.warn('bad resrouce entry') + continue + + entry.subdir = subdir + dir_todo[off] = entry.subdir + return resdesc, off + + def build_content(self, raw): + if self.resdesc is None: + return + of1 = self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_RESOURCE].rva + raw[self.parent_head.rva2off(of1)] = bytes(self.resdesc) + dir_todo = {self.parent_head.NThdr.optentries[ + DIRECTORY_ENTRY_RESOURCE].rva: self.resdesc} + dir_done = {} + while dir_todo: + of1, my_dir = dir_todo.popitem() + dir_done[of1] = my_dir + raw[self.parent_head.rva2off(of1)] = bytes(my_dir) + of1 += len(my_dir) + of_base = of1 + for entry in my_dir.resentries: + raw[of_base] = bytes(entry) + of_base += len(entry) + if entry.name_s: + raw[self.parent_head.rva2off(entry.name)] = bytes(entry.name_s) + of1 = entry.offsettosubdir + if not of1: + raw[self.parent_head.rva2off(entry.offsettodata)] = bytes(entry.data) + raw[self.parent_head.rva2off(entry.data.offsettodata)] = bytes(entry.data.s) + continue + dir_todo[of1] = entry.subdir + + def __len__(self): + length = 0 + if self.resdesc is None: + return length + dir_todo = [self.resdesc] + dir_done = [] + while dir_todo: + my_dir = dir_todo.pop() + if my_dir in dir_done: + raise ValueError('Recursive directory') + dir_done.append(my_dir) + length += len(my_dir) + length += len(my_dir.resentries) * 8 # ResEntry size + for entry in my_dir.resentries: + if not entry.offsettosubdir: + continue + if not entry.subdir in dir_todo: + dir_todo.append(entry.subdir) + else: + raise RuntimeError("recursive dir") + + dir_todo = dir_done + while dir_todo: + my_dir = dir_todo.pop() + for entry in my_dir.resentries: + if entry.name_s: + length += len(entry.name_s) + of1 = entry.offsettosubdir + if not of1: + length += 4 * 4 # WResDataEntry size + # XXX because rva may be even rounded + length += 1 + length += entry.data.size + continue + return length + + def set_rva(self, rva, size=None): + if self.resdesc is None: + return + self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_RESOURCE].rva = rva + if not size: + self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_RESOURCE].size = len(self) + else: + self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_RESOURCE].size = size + dir_todo = [self.resdesc] + dir_done = {} + while dir_todo: + my_dir = dir_todo.pop() + dir_done[rva] = my_dir + rva += len(my_dir) + rva += len(my_dir.resentries) * 8 # ResEntry size + for entry in my_dir.resentries: + if not entry.offsettosubdir: + continue + if not entry.subdir in dir_todo: + dir_todo.append(entry.subdir) + else: + raise RuntimeError("recursive dir") + dir_todo = dir_done + dir_inv = dict([(x[1], x[0]) for x in list(dir_todo.items())]) + while dir_todo: + rva_tmp, my_dir = dir_todo.popitem() + for entry in my_dir.resentries: + if entry.name_s: + entry.name = rva + rva += len(entry.name_s) + of1 = entry.offsettosubdir + if not of1: + entry.offsettodata = rva + rva += 4 * 4 # ResDataEntry size + # XXX menu rsrc must be even aligned? + if rva % 2: + rva += 1 + entry.data.offsettodata = rva + rva += entry.data.size + continue + entry.offsettosubdir = dir_inv[entry.subdir] + + def __repr__(self): + rep = ["<%s>" % (self.__class__.__name__)] + if self.resdesc is None: + return "\n".join(rep) + dir_todo = [self.resdesc] + resources = [] + index = -1 + while dir_todo: + entry = dir_todo.pop(0) + if isinstance(entry, int): + index += entry + elif isinstance(entry, ResDesc_e): + # resources.append((index, repr(entry))) + dir_todo = [1] + entry.resentries.l + [-1] + dir_todo + elif isinstance(entry, ResEntry): + if entry.offsettosubdir: + resources.append((index, repr(entry))) + dir_todo = [entry.subdir] + dir_todo + else: + resources.append((index, repr(entry))) + else: + raise RuntimeError("zarb") + for i, resource in resources: + rep.append(' ' * 4 * i + resource) + return "\n".join(rep) + + +class Ordinal(CStruct): + _fields = [("ordinal", "u16"), + ] + + +class ResDesc_e(CStruct): + _fields = [("characteristics", "u32"), + ("timestamp", "u32"), + ("majorv", "u16"), + ("minorv", "u16"), + ("numberofnamedentries", "u16"), + ("numberofidentries", "u16") + ] + + +class SUnicode(CStruct): + _fields = [("length", "u16"), + ("value", (lambda c, raw, off:c.gets(raw, off), + lambda c, value:c.sets(value))) + ] + + def gets(self, raw, off): + value = raw[off:off + self.length * 2] + return value, off + self.length + + def sets(self, value): + return self.value + + +class ResEntry(CStruct): + _fields = [("name", (lambda c, raw, off:c._get_name(raw, off), + lambda c, value:c._set_name(value))), + ("offsettodata", (lambda c, raw, off:c._get_offset(raw, off), + lambda c, value:c._set_offset(value))) + ] + + def _get_name(self, raw, off): + self.data = None + # off = self.parent_head.rva2off(off) + name = struct.unpack('I', raw[off:off + 4])[0] + self.name_s = None + if name & 0x80000000: + name = (name & 0x7FFFFFFF) + self.parent_head.NThdr.optentries[ + DIRECTORY_ENTRY_RESOURCE].rva # XXX res rva?? + name &= 0x7FFFFFFF + if name >= len(raw): + raise RuntimeError("Bad resentry") + self.name_s = SUnicode.unpack(raw, + name, + self.parent_head) + return name, off + 4 + + def _set_name(self, name): + if self.name_s: + rva = self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_RESOURCE].rva + name = (self.name - rva) + 0x80000000 + return struct.pack('I', name) + + def _get_offset(self, raw, off): + self.offsettosubdir = None + rva = self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_RESOURCE].rva + offsettodata_o = struct.unpack('I', raw[off:off + 4])[0] + offsettodata = (offsettodata_o & 0x7FFFFFFF) + rva # XXX res rva?? + if offsettodata_o & 0x80000000: + self.offsettosubdir = offsettodata + return offsettodata, off + 4 + + def _set_offset(self, offset): + rva = self.parent_head.NThdr.optentries[DIRECTORY_ENTRY_RESOURCE].rva + offsettodata = offset - rva + if self.offsettosubdir: + offsettodata = (self.offsettosubdir - rva) + 0x80000000 + return struct.pack('I', offsettodata) + + def __repr__(self): + if self.name_s: + nameid = "%s" % repr(self.name_s) + else: + if self.name in RT: # and not self.offsettosubdir: + nameid = "ID %s" % RT[self.name] + else: + nameid = "ID %d" % self.name + if self.offsettosubdir: + offsettodata = "subdir: %x" % self.offsettosubdir + else: + offsettodata = "data: %x" % self.offsettodata + return "<%s %s>" % (nameid, offsettodata) + + +class ResDataEntry(CStruct): + _fields = [("offsettodata", "u32"), + ("size", "u32"), + ("codepage", "u32"), + ("reserved", "u32"), + ] + + +class Symb(CStruct): + _fields = [("name", "8s"), + ("res1", "u32"), + ("res2", "u32"), + ("res3", "u16")] + + +DIRECTORY_ENTRY_EXPORT = 0 +DIRECTORY_ENTRY_IMPORT = 1 +DIRECTORY_ENTRY_RESOURCE = 2 +DIRECTORY_ENTRY_EXCEPTION = 3 +DIRECTORY_ENTRY_SECURITY = 4 +DIRECTORY_ENTRY_BASERELOC = 5 +DIRECTORY_ENTRY_DEBUG = 6 +DIRECTORY_ENTRY_COPYRIGHT = 7 +DIRECTORY_ENTRY_GLOBALPTR = 8 +DIRECTORY_ENTRY_TLS = 9 +DIRECTORY_ENTRY_LOAD_CONFIG = 10 +DIRECTORY_ENTRY_BOUND_IMPORT = 11 +DIRECTORY_ENTRY_IAT = 12 +DIRECTORY_ENTRY_DELAY_IMPORT = 13 +DIRECTORY_ENTRY_COM_DESCRIPTOR = 14 +DIRECTORY_ENTRY_RESERVED = 15 + + +RT_CURSOR = 1 +RT_BITMAP = 2 +RT_ICON = 3 +RT_MENU = 4 +RT_DIALOG = 5 +RT_STRING = 6 +RT_FONTDIR = 7 +RT_FONT = 8 +RT_ACCELERATOR = 9 +RT_RCDATA = 10 +RT_MESSAGETABLE = 11 +RT_GROUP_CURSOR = 12 +RT_GROUP_ICON = 14 +RT_VERSION = 16 +RT_DLGINCLUDE = 17 +RT_PLUGPLAY = 19 +RT_VXD = 20 +RT_ANICURSOR = 21 +RT_ANIICON = 22 +RT_HTML = 23 +RT_MANIFEST = 24 + + +RT = { + RT_CURSOR: "RT_CURSOR", + RT_BITMAP: "RT_BITMAP", + RT_ICON: "RT_ICON", + RT_MENU: "RT_MENU", + RT_DIALOG: "RT_DIALOG", + RT_STRING: "RT_STRING", + RT_FONTDIR: "RT_FONTDIR", + RT_FONT: "RT_FONT", + RT_ACCELERATOR: "RT_ACCELERATOR", + RT_RCDATA: "RT_RCDATA", + RT_MESSAGETABLE: "RT_MESSAGETABLE", + RT_GROUP_CURSOR: "RT_GROUP_CURSOR", + RT_GROUP_ICON: "RT_GROUP_ICON", + RT_VERSION: "RT_VERSION", + RT_DLGINCLUDE: "RT_DLGINCLUDE", + RT_PLUGPLAY: "RT_PLUGPLAY", + RT_VXD: "RT_VXD", + RT_ANICURSOR: "RT_ANICURSOR", + RT_ANIICON: "RT_ANIICON", + RT_HTML: "RT_HTML", + RT_MANIFEST: "RT_MANIFEST", +} diff --git a/miasm/elfesteem/pe_init.py b/miasm/elfesteem/pe_init.py new file mode 100644 index 000000000..e243cecb6 --- /dev/null +++ b/miasm/elfesteem/pe_init.py @@ -0,0 +1,603 @@ +#! /usr/bin/env python + +from __future__ import print_function + +from builtins import range +import array +from functools import reduce +import logging +import struct + +from future.builtins import int as int_types +from future.utils import PY3 + +from miasm.elfesteem import pe +from miasm.elfesteem.strpatchwork import StrPatchwork + +log = logging.getLogger("peparse") +console_handler = logging.StreamHandler() +console_handler.setFormatter(logging.Formatter("%(levelname)-5s: %(message)s")) +log.addHandler(console_handler) +log.setLevel(logging.WARN) + + +class ContentManager(object): + + def __get__(self, owner, _): + if hasattr(owner, '_content'): + return owner._content + + def __set__(self, owner, new_content): + owner.resize(len(owner._content), len(new_content)) + owner._content = new_content + + def __delete__(self, owner): + self.__set__(owner, None) + + +class ContectRva(object): + + def __init__(self, parent): + self.parent = parent + + def get(self, rva_start, rva_stop=None): + """ + Get data in RVA view starting at @rva_start, stopping at @rva_stop + @rva_start: rva start address + @rva_stop: rva stop address + """ + if rva_start < 0: + raise ValueError("Out of range") + if rva_stop is not None: + if rva_stop > len(self.parent.img_rva): + rva_stop = len(self.parent.img_rva) + if rva_start > len(self.parent.img_rva): + raise ValueError("Out of range") + return self.parent.img_rva[rva_start:rva_stop] + if rva_start > len(self.parent.img_rva): + raise ValueError("Out of range") + return self.parent.img_rva[rva_start] + + def set(self, rva, data): + """ + Set @data in RVA view starting at @start + @rva: rva start address + @data: data to set + """ + if not isinstance(rva, int_types): + raise ValueError('addr must be int/long') + + if rva < 0: + raise ValueError("Out of range") + + if rva + len(data) > len(self.parent.img_rva): + raise ValueError("Out of range") + self.parent.img_rva[rva] = data + + def __getitem__(self, item): + if isinstance(item, slice): + assert(item.step is None) + return self.get(item.start, item.stop) + return self.get(item) + + def __setitem__(self, item, data): + if isinstance(item, slice): + rva = item.start + else: + rva = item + self.set(rva, data) + + +class ContentVirtual(object): + + def __init__(self, parent): + self.parent = parent + + def __getitem__(self, item): + raise DeprecationWarning("Replace code by virt.get(start, [stop])") + + def __setitem__(self, item, data): + raise DeprecationWarning("Replace code by virt.set(start, data)") + + def __call__(self, ad_start, ad_stop=None, ad_step=None): + raise DeprecationWarning("Replace code by virt.get(start, stop)") + + def get(self, virt_start, virt_stop=None): + """ + Get data in VIRTUAL view starting at @virt_start, stopping at @virt_stop + @virt_start: virt start address + @virt_stop: virt stop address + """ + rva_start = self.parent.virt2rva(virt_start) + if virt_stop != None: + rva_stop = self.parent.virt2rva(virt_stop) + else: + rva_stop = None + return self.parent.rva.get(rva_start, rva_stop) + + def set(self, addr, data): + """ + Set @data in VIRTUAL view starting at @start + @addr: virtual start address + @data: data to set + """ + if not isinstance(addr, int_types): + raise ValueError('addr must be int/long') + self.parent.rva.set(self.parent.virt2rva(addr), data) + + def max_addr(self): + section = self.parent.SHList[-1] + length = section.addr + section.size + self.parent.NThdr.ImageBase + return int(length) + + def find(self, pattern, start=0, end=None): + if start != 0: + start = self.parent.virt2rva(start) + if end != None: + end = self.parent.virt2rva(end) + + ret = self.parent.img_rva.find(pattern, start, end) + if ret == -1: + return -1 + return self.parent.rva2virt(ret) + + def rfind(self, pattern, start=0, end=None): + if start != 0: + start = self.parent.virt2rva(start) + if end != None: + end = self.parent.virt2rva(end) + + ret = self.parent.img_rva.rfind(pattern, start, end) + if ret == -1: + return -1 + return self.parent.rva2virt(ret) + + def is_addr_in(self, addr): + return self.parent.is_in_virt_address(addr) + + + +def compute_crc(raw, olds): + out = 0 + data = raw[:] + if len(raw) % 2: + end = struct.unpack('B', data[-1])[0] + data = data[:-1] + if (len(raw) & ~0x1) % 4: + out += struct.unpack('H', data[:2])[0] + data = data[2:] + data = array.array('I', data) + out = reduce(lambda x, y: x + y, data, out) + out -= olds + while out > 0xFFFFFFFF: + out = (out >> 32) + (out & 0xFFFFFFFF) + while out > 0xFFFF: + out = (out & 0xFFFF) + ((out >> 16) & 0xFFFF) + if len(raw) % 2: + out += end + out += len(data) + return out + + + +# PE object +class PE(object): + content = ContentManager() + + def __init__(self, pestr=None, + loadfrommem=False, + parse_resources=True, + parse_delay=True, + parse_reloc=True, + wsize=32): + self._rva = ContectRva(self) + self._virt = ContentVirtual(self) + self.img_rva = StrPatchwork() + if pestr is None: + self._content = StrPatchwork() + self._sex = 0 + self._wsize = wsize + self.Doshdr = pe.Doshdr(self) + self.NTsig = pe.NTsig(self) + self.Coffhdr = pe.Coffhdr(self) + + if self._wsize == 32: + Opthdr = pe.Opthdr32 + else: + Opthdr = pe.Opthdr64 + + self.Opthdr = Opthdr(self) + self.NThdr = pe.NThdr(self) + self.NThdr.optentries = [pe.Optehdr(self) for _ in range(0x10)] + self.NThdr.CheckSum = 0 + self.SHList = pe.SHList(self) + self.SHList.shlist = [] + + self.NThdr.sizeofheaders = 0x1000 + + self.DirImport = pe.DirImport(self) + self.DirExport = pe.DirExport(self) + self.DirDelay = pe.DirDelay(self) + self.DirReloc = pe.DirReloc(self) + self.DirRes = pe.DirRes(self) + + self.Doshdr.magic = 0x5a4d + self.Doshdr.lfanew = 0xe0 + + self.NTsig.signature = 0x4550 + if wsize == 32: + self.Opthdr.magic = 0x10b + elif wsize == 64: + self.Opthdr.magic = 0x20b + else: + raise ValueError('unknown pe size %r' % wsize) + self.Opthdr.majorlinkerversion = 0x7 + self.Opthdr.minorlinkerversion = 0x0 + self.NThdr.filealignment = 0x1000 + self.NThdr.sectionalignment = 0x1000 + self.NThdr.majoroperatingsystemversion = 0x5 + self.NThdr.minoroperatingsystemversion = 0x1 + self.NThdr.MajorImageVersion = 0x5 + self.NThdr.MinorImageVersion = 0x1 + self.NThdr.majorsubsystemversion = 0x4 + self.NThdr.minorsubsystemversion = 0x0 + self.NThdr.subsystem = 0x3 + if wsize == 32: + self.NThdr.dllcharacteristics = 0x8000 + else: + self.NThdr.dllcharacteristics = 0x8000 + + # for createthread + self.NThdr.sizeofstackreserve = 0x200000 + self.NThdr.sizeofstackcommit = 0x1000 + self.NThdr.sizeofheapreserve = 0x100000 + self.NThdr.sizeofheapcommit = 0x1000 + + self.NThdr.ImageBase = 0x400000 + self.NThdr.sizeofheaders = 0x1000 + self.NThdr.numberofrvaandsizes = 0x10 + + self.NTsig.signature = 0x4550 + if wsize == 32: + self.Coffhdr.machine = 0x14c + elif wsize == 64: + self.Coffhdr.machine = 0x8664 + else: + raise ValueError('unknown pe size %r' % wsize) + if wsize == 32: + self.Coffhdr.characteristics = 0x10f + self.Coffhdr.sizeofoptionalheader = 0xe0 + else: + self.Coffhdr.characteristics = 0x22 # 0x2f + self.Coffhdr.sizeofoptionalheader = 0xf0 + + else: + self._content = StrPatchwork(pestr) + self.loadfrommem = loadfrommem + self.parse_content(parse_resources=parse_resources, + parse_delay=parse_delay, + parse_reloc=parse_reloc) + + def isPE(self): + if self.NTsig is None: + return False + return self.NTsig.signature == 0x4550 + + def parse_content(self, + parse_resources=True, + parse_delay=True, + parse_reloc=True): + off = 0 + self._sex = 0 + self._wsize = 32 + self.Doshdr = pe.Doshdr.unpack(self.content, off, self) + off = self.Doshdr.lfanew + if off > len(self.content): + log.warn('ntsig after eof!') + self.NTsig = None + return + self.NTsig = pe.NTsig.unpack(self.content, + off, self) + self.DirImport = None + self.DirExport = None + self.DirDelay = None + self.DirReloc = None + self.DirRes = None + + if self.NTsig.signature != 0x4550: + log.warn('not a valid pe!') + return + off += len(self.NTsig) + self.Coffhdr, length = pe.Coffhdr.unpack_l(self.content, + off, + self) + + off += length + self._wsize = ord(self.content[off+1]) * 32 + + if self._wsize == 32: + Opthdr = pe.Opthdr32 + else: + Opthdr = pe.Opthdr64 + + if len(self.content) < 0x200: + # Fix for very little PE + self.content += (0x200 - len(self.content)) * b'\x00' + + self.Opthdr, length = Opthdr.unpack_l(self.content, off, self) + self.NThdr = pe.NThdr.unpack(self.content, off + length, self) + self.img_rva[0] = self.content[:self.NThdr.sizeofheaders] + off += self.Coffhdr.sizeofoptionalheader + self.SHList = pe.SHList.unpack(self.content, off, self) + + # load section data + filealignment = self.NThdr.filealignment + sectionalignment = self.NThdr.sectionalignment + for section in self.SHList.shlist: + virt_size = (section.size // sectionalignment + 1) * sectionalignment + if self.loadfrommem: + section.offset = section.addr + if self.NThdr.sectionalignment > 0x1000: + raw_off = 0x200 * (section.offset // 0x200) + else: + raw_off = section.offset + if raw_off != section.offset: + log.warn('unaligned raw section (%x %x)!', raw_off, section.offset) + section.data = StrPatchwork() + + if section.rawsize == 0: + rounded_size = 0 + else: + if section.rawsize % filealignment: + rs = (section.rawsize // filealignment + 1) * filealignment + else: + rs = section.rawsize + rounded_size = rs + if rounded_size > virt_size: + rounded_size = min(rounded_size, section.size) + data = self.content[raw_off:raw_off + rounded_size] + section.data = data + # Pad data to page size 0x1000 + length = len(data) + data += b"\x00" * ((((length + 0xfff)) & 0xFFFFF000) - length) + self.img_rva[section.addr] = data + # Fix img_rva + self.img_rva = self.img_rva + + try: + self.DirImport = pe.DirImport.unpack(self.img_rva, + self.NThdr.optentries[ + pe.DIRECTORY_ENTRY_IMPORT].rva, + self) + except pe.InvalidOffset: + log.warning('cannot parse DirImport, skipping') + self.DirImport = pe.DirImport(self) + + try: + self.DirExport = pe.DirExport.unpack(self.img_rva, + self.NThdr.optentries[ + pe.DIRECTORY_ENTRY_EXPORT].rva, + self) + except pe.InvalidOffset: + log.warning('cannot parse DirExport, skipping') + self.DirExport = pe.DirExport(self) + + if len(self.NThdr.optentries) > pe.DIRECTORY_ENTRY_DELAY_IMPORT: + self.DirDelay = pe.DirDelay(self) + if parse_delay: + try: + self.DirDelay = pe.DirDelay.unpack(self.img_rva, + self.NThdr.optentries[ + pe.DIRECTORY_ENTRY_DELAY_IMPORT].rva, + self) + except pe.InvalidOffset: + log.warning('cannot parse DirDelay, skipping') + if len(self.NThdr.optentries) > pe.DIRECTORY_ENTRY_BASERELOC: + self.DirReloc = pe.DirReloc(self) + if parse_reloc: + try: + self.DirReloc = pe.DirReloc.unpack(self.img_rva, + self.NThdr.optentries[ + pe.DIRECTORY_ENTRY_BASERELOC].rva, + self) + except pe.InvalidOffset: + log.warning('cannot parse DirReloc, skipping') + if len(self.NThdr.optentries) > pe.DIRECTORY_ENTRY_RESOURCE: + self.DirRes = pe.DirRes(self) + if parse_resources: + self.DirRes = pe.DirRes(self) + try: + self.DirRes = pe.DirRes.unpack(self.img_rva, + self.NThdr.optentries[ + pe.DIRECTORY_ENTRY_RESOURCE].rva, + self) + except pe.InvalidOffset: + log.warning('cannot parse DirRes, skipping') + + def resize(self, old, new): + pass + + def __getitem__(self, item): + return self.content[item] + + def __setitem__(self, item, data): + self.content.__setitem__(item, data) + return + + def getsectionbyrva(self, rva): + if self.SHList is None: + return None + for section in self.SHList.shlist: + """ + TODO CHECK: + some binaries have import rva outside section, but addresses + seems to be rounded + """ + mask = self.NThdr.sectionalignment - 1 + if section.addr <= rva < (section.addr + section.size + mask) & ~(mask): + return section + return None + + def getsectionbyvad(self, vad): + return self.getsectionbyrva(self.virt2rva(vad)) + + def getsectionbyoff(self, off): + if self.SHList is None: + return None + for section in self.SHList.shlist: + if section.offset <= off < section.offset + section.rawsize: + return section + return None + + def getsectionbyname(self, name): + if self.SHList is None: + return None + for section in self.SHList: + if section.name.strip(b'\x00').decode() == name: + return section + return None + + def is_rva_ok(self, rva): + return self.getsectionbyrva(rva) is not None + + def rva2off(self, rva): + # Special case rva in header + if rva < self.NThdr.sizeofheaders: + return rva + section = self.getsectionbyrva(rva) + if section is None: + raise pe.InvalidOffset('cannot get offset for 0x%X' % rva) + soff = (section.offset // self.NThdr.filealignment) * self.NThdr.filealignment + return rva - section.addr + soff + + def off2rva(self, off): + section = self.getsectionbyoff(off) + if section is None: + return + return off - section.offset + section.addr + + def virt2rva(self, virt): + if virt is None: + return + return virt - self.NThdr.ImageBase + + def rva2virt(self, rva): + if rva is None: + return + return rva + self.NThdr.ImageBase + + def virt2off(self, virt): + return self.rva2off(self.virt2rva(virt)) + + def off2virt(self, off): + return self.rva2virt(self.off2rva(off)) + + def is_in_virt_address(self, addr): + if addr < self.NThdr.ImageBase: + return False + addr = self.virt2rva(addr) + for section in self.SHList.shlist: + if section.addr <= addr < section.addr + section.size: + return True + return False + + def get_drva(self): + print('Deprecated: Use PE.rva instead of PE.drva') + return self._rva + + def get_rva(self): + return self._rva + + # TODO XXX remove drva api + drva = property(get_drva) + rva = property(get_rva) + + def get_virt(self): + return self._virt + + virt = property(get_virt) + + def build_content(self): + + content = StrPatchwork() + content[0] = bytes(self.Doshdr) + + for section in self.SHList.shlist: + content[section.offset:section.offset + section.rawsize] = bytes(section.data) + + # fix image size + section_last = self.SHList.shlist[-1] + size = section_last.addr + section_last.size + (self.NThdr.sectionalignment - 1) + size &= ~(self.NThdr.sectionalignment - 1) + self.NThdr.sizeofimage = size + + off = self.Doshdr.lfanew + content[off] = bytes(self.NTsig) + off += len(self.NTsig) + content[off] = bytes(self.Coffhdr) + off += len(self.Coffhdr) + off_shlist = off + self.Coffhdr.sizeofoptionalheader + content[off] = bytes(self.Opthdr) + off += len(self.Opthdr) + content[off] = bytes(self.NThdr) + off += len(self.NThdr) + # content[off] = bytes(self.Optehdr) + + off = off_shlist + content[off] = bytes(self.SHList) + + for section in self.SHList: + if off + len(bytes(self.SHList)) > section.offset: + log.warn("section offset overlap pe hdr 0x%x 0x%x" % + (off + len(bytes(self.SHList)), section.offset)) + self.DirImport.build_content(content) + self.DirExport.build_content(content) + self.DirDelay.build_content(content) + self.DirReloc.build_content(content) + self.DirRes.build_content(content) + + if (self.Doshdr.lfanew + len(self.NTsig) + len(self.Coffhdr)) % 4: + log.warn("non aligned coffhdr, bad crc calculation") + crcs = compute_crc(bytes(content), self.NThdr.CheckSum) + content[self.Doshdr.lfanew + len(self.NTsig) + len(self.Coffhdr) + 64] = struct.pack('I', crcs) + return bytes(content) + + def __bytes__(self): + return self.build_content() + + def __str__(self): + if PY3: + return repr(self) + return self.__bytes__() + + def export_funcs(self): + if self.DirExport is None: + print('no export dir found') + return None, None + + all_func = {} + for i, export in enumerate(self.DirExport.f_names): + all_func[export.name.name] = self.rva2virt( + self.DirExport.f_address[self.DirExport.f_nameordinals[i].ordinal].rva) + all_func[self.DirExport.f_nameordinals[i].ordinal + self.DirExport.expdesc.base] = self.rva2virt( + self.DirExport.f_address[self.DirExport.f_nameordinals[i].ordinal].rva) + # XXX todo: test if redirected export + return all_func + + def reloc_to(self, imgbase): + offset = imgbase - self.NThdr.ImageBase + if self.DirReloc is None: + log.warn('no relocation found!') + for rel in self.DirReloc.reldesc: + rva = rel.rva + for reloc in rel.rels: + reloc_type, off = reloc.rel + if reloc_type == 0 and off == 0: + continue + if reloc_type != 3: + raise NotImplementedError('Reloc type not supported') + off += rva + value = struct.unpack('I', self.rva.get(off, off + 4))[0] + value += offset + self.rva.set(off, struct.pack('I', value & 0xFFFFFFFF)) + self.NThdr.ImageBase = imgbase diff --git a/miasm/elfesteem/strpatchwork.py b/miasm/elfesteem/strpatchwork.py new file mode 100644 index 000000000..e1a5de91f --- /dev/null +++ b/miasm/elfesteem/strpatchwork.py @@ -0,0 +1,106 @@ +from array import array +import struct +from sys import maxsize + +from future.utils import PY3 + +if PY3: + + def array_frombytes(arr, value): + return arr.frombytes(value) + + def array_tobytes(arr): + return arr.tobytes() + + +else: + + def array_frombytes(arr, value): + return arr.fromstring(value) + + def array_tobytes(arr): + return arr.tostring() + + +class StrPatchwork(object): + + def __init__(self, s=b"", paddingbyte=b"\x00"): + s_raw = bytes(s) + val = array("B") + array_frombytes(val, s_raw) + self.s = val + # cache s to avoid rebuilding str after each find + self.s_cache = s_raw + self.paddingbyte = paddingbyte + + def __bytes__(self): + return array_tobytes(self.s) + + def __str__(self): + if PY3: + return repr(self) + return self.__bytes__() + + def __getitem__(self, item): + s = self.s + if isinstance(item, slice): + end = item.stop + l = len(s) + if (end is not None and l < end) and end != maxsize: + # XXX hack [x:] give 2GB limit + # This is inefficient but avoids complicated maths if step is + # not 1 + s = s[:] + + tmp = array("B") + array_frombytes(tmp, self.paddingbyte * (end - l)) + s.extend(tmp) + r = s[item] + return array_tobytes(r) + + else: + if item > len(s): + return self.paddingbyte + else: + return struct.pack("B", s[item]) + + def __setitem__(self, item, val): + if val is None: + return + val_array = array("B") + array_frombytes(val_array, bytes(val)) + if type(item) is not slice: + item = slice(item, item + len(val_array)) + end = item.stop + l = len(self.s) + if l < end: + tmp = array("B") + array_frombytes(tmp, self.paddingbyte * (end - l)) + self.s.extend(tmp) + self.s[item] = val_array + self.s_cache = None + + def __repr__(self): + return "" % array_tobytes(self.s) + + def __len__(self): + return len(self.s) + + def __contains__(self, val): + return val in bytes(self) + + def __iadd__(self, other): + tmp = array("B") + array_frombytes(tmp, bytes(other)) + self.s.extend(tmp) + return self + + def find(self, pattern, start=0, end=None): + if not self.s_cache: + self.s_cache = array_tobytes(self.s) + return self.s_cache.find(pattern, start, end) + + def rfind(self, pattern, start=0, end=None): + if not self.s_cache: + self.s_cache = array_tobytes(self.s) + return self.s_cache.rfind(pattern, start, end) diff --git a/miasm/jitter/loader/elf.py b/miasm/jitter/loader/elf.py index b36638f37..4c68fc919 100644 --- a/miasm/jitter/loader/elf.py +++ b/miasm/jitter/loader/elf.py @@ -3,9 +3,9 @@ from future.utils import viewitems -from elfesteem import cstruct -from elfesteem import * -import elfesteem.elf as elf_csts +from miasm.elfesteem import cstruct +from miasm.elfesteem import * +import miasm.elfesteem.elf as elf_csts from miasm.jitter.csts import * from miasm.jitter.loader.utils import canon_libname_libfunc, libimp @@ -56,11 +56,11 @@ def preload_elf(vm, e, runtime_lib, patch_vm_imp=True, loc_db=None): return runtime_lib, dyn_funcs def fill_loc_db_with_symbols(elf, loc_db, base_addr=0): - """Parse the elfesteem's ELF @elf to extract symbols, and fill the LocationDB + """Parse the miasm.elfesteem's ELF @elf to extract symbols, and fill the LocationDB instance @loc_db with parsed symbols. The ELF is considered mapped at @base_addr - @elf: elfesteem's ELF instance + @elf: miasm.elfesteem's ELF instance @loc_db: LocationDB used to retrieve symbols'offset @base_addr: addr to reloc to (if any) """ @@ -163,7 +163,7 @@ def fill_loc_db_with_symbols(elf, loc_db, base_addr=0): def apply_reloc_x86(elf, vm, section, base_addr, loc_db): """Apply relocation for x86 ELF contained in the section @section - @elf: elfesteem's ELF instance + @elf: miasm.elfesteem's ELF instance @vm: VmMngr instance @section: elf's section containing relocation to perform @base_addr: addr to reloc to diff --git a/miasm/jitter/loader/pe.py b/miasm/jitter/loader/pe.py index 7145a817e..a2bdd3ac9 100644 --- a/miasm/jitter/loader/pe.py +++ b/miasm/jitter/loader/pe.py @@ -6,9 +6,9 @@ from future.utils import viewitems, viewvalues -from elfesteem import pe -from elfesteem import cstruct -from elfesteem import * +from miasm.elfesteem import pe +from miasm.elfesteem import cstruct +from miasm.elfesteem import * from miasm.jitter.csts import * from miasm.jitter.loader.utils import canon_libname_libfunc, libimp diff --git a/miasm/os_dep/win_api_x86_32_seh.py b/miasm/os_dep/win_api_x86_32_seh.py index 90a68eecd..5d8ed3d74 100644 --- a/miasm/os_dep/win_api_x86_32_seh.py +++ b/miasm/os_dep/win_api_x86_32_seh.py @@ -23,7 +23,7 @@ from future.utils import viewitems -from elfesteem import pe_init +from miasm.elfesteem import pe_init from miasm.jitter.csts import PAGE_READ, PAGE_WRITE from miasm.core.utils import pck32 diff --git a/requirements.txt b/requirements.txt index 84530589e..135ca071c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ pyparsing future -git+https://github.com/serpilliere/elfesteem@py23_lalet#egg=elfesteem-0.1 llvmlite==0.26.0 diff --git a/setup.py b/setup.py index c52e1f9e0..3aaeaf277 100755 --- a/setup.py +++ b/setup.py @@ -30,6 +30,7 @@ def buil_all(): "miasm/analysis", "miasm/os_dep", "miasm/os_dep/linux", + "miasm/elfesteem", "miasm/jitter", "miasm/jitter/arch", "miasm/jitter/loader", diff --git a/test/analysis/dse.py b/test/analysis/dse.py index 8691551cc..21225f54b 100644 --- a/test/analysis/dse.py +++ b/test/analysis/dse.py @@ -3,7 +3,7 @@ from future.utils import viewitems -from elfesteem.strpatchwork import StrPatchwork +from miasm.elfesteem.strpatchwork import StrPatchwork from miasm.core import parse_asm from miasm.expression.expression import ExprCompose, ExprOp, ExprInt, ExprId from miasm.core.asmblock import asm_resolve_final diff --git a/test/arch/aarch64/unit/asm_test.py b/test/arch/aarch64/unit/asm_test.py index 65a537a03..9d193b47f 100644 --- a/test/arch/aarch64/unit/asm_test.py +++ b/test/arch/aarch64/unit/asm_test.py @@ -7,7 +7,7 @@ from miasm.core import parse_asm from miasm.expression.expression import * from miasm.core import asmblock -from elfesteem.strpatchwork import StrPatchwork +from miasm.elfesteem.strpatchwork import StrPatchwork from miasm.analysis.machine import Machine from miasm.jitter.csts import * diff --git a/test/arch/mips32/unit/asm_test.py b/test/arch/mips32/unit/asm_test.py index 38a2d9286..dd95c3afe 100644 --- a/test/arch/mips32/unit/asm_test.py +++ b/test/arch/mips32/unit/asm_test.py @@ -7,7 +7,7 @@ from miasm.core import parse_asm from miasm.expression.expression import * from miasm.core import asmblock -from elfesteem.strpatchwork import StrPatchwork +from miasm.elfesteem.strpatchwork import StrPatchwork from miasm.analysis.machine import Machine from miasm.jitter.csts import * diff --git a/test/arch/x86/unit/asm_test.py b/test/arch/x86/unit/asm_test.py index 0059f511a..cf87ac933 100644 --- a/test/arch/x86/unit/asm_test.py +++ b/test/arch/x86/unit/asm_test.py @@ -9,7 +9,7 @@ from miasm.core import parse_asm from miasm.expression.expression import * from miasm.core import asmblock -from elfesteem.strpatchwork import StrPatchwork +from miasm.elfesteem.strpatchwork import StrPatchwork from miasm.analysis.machine import Machine from miasm.jitter.csts import *