#!/usr/bin/env python3 # *****************************************************************************/ # yet another elfdump in python # Copyright (C) 2018 Farzad Sadeghi # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 3 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA.*/ # *****************************************************************************/ import argparse import code import os import subprocess import sys from capstone import CS_ARCH_X86, CS_MODE_64, Cs # from capstone.x86 import Cs class ELF_TYPE_SIZES: ELF32_HALF = 2 ELF64_HALF = 2 ELF32_WORD = 4 ELF32_SWORD = 4 ELF64_WORD = 4 ELF64_SWORD = 4 ELF32_XWORD = 8 ELF32_SXWORD = 8 ELF64_XWORD = 8 ELF64_SXWORD = 8 ELF32_ADDR = 4 ELF64_ADDR = 8 ELF32_OFF = 4 ELF64_OFF = 8 ELF32_SECTION = 2 ELF64_SECTION = 2 def SigHandler_SIGINT(signum, frame): print() sys.exit(0) class CLIArgParser(object): def __init__(self): parser = argparse.ArgumentParser() parser.add_argument("--dbg", action="store_true", help="debug", default=False) parser.add_argument( "--obj", type=str, help="path to the executbale, shared object " "or object you want to load in bruiser", ) parser.add_argument( "--header", action="store_true", help="dump headers", default=False ) parser.add_argument( "--symboltable", action="store_true", help="dump symbol table", default=False, ) parser.add_argument( "--phdrs", action="store_true", help="dump program haeders", default=False, ) parser.add_argument( "--shdrs", action="store_true", help="dump section haeders", default=False, ) parser.add_argument( "--symbolindex", action="store_true", help="dump symbol index", default=False, ) parser.add_argument( "--stentries", action="store_true", help="dump section table entries", default=False, ) parser.add_argument( "--objcode", action="store_true", help="dump objects", default=False, ) parser.add_argument( "--test", action="store_true", help="test switch", default=False ) parser.add_argument( "--test2", action="store_true", help="test switch 2", default=False ) parser.add_argument( "--listdso", action="store_true", help="list DSOs", default=False ) parser.add_argument( "--funcs", action="store_true", help="dump functions", default=False, ) parser.add_argument( "--objs", action="store_true", help="dump objects", default=False ) parser.add_argument( "--dynsym", action="store_true", help="dump dynamic symbol table", default=False, ) parser.add_argument( "--dlpath", action="store_true", help="dump dynamic linker path", default=False, ) parser.add_argument( "--phdynent", action="store_true", help="dump ph PT_DYNAMIC entries", default=False, ) parser.add_argument("--section", type=str, help="dump a section") parser.add_argument( "--dumpfunc", type=str, help="dump a functions machine code" ) parser.add_argument( "--dumpfuncasm", type=str, help="dump a functions assembly code" ) parser.add_argument( "--textasm", action="store_true", help="disassemble the text section", default=False, ) parser.add_argument( "--dynsecents", action="store_true", help="dynamic section entries", default=False, ) parser.add_argument( "--reladyn", action="store_true", help=".rela.dyn entries", default=False, ) parser.add_argument( "--relaplt", action="store_true", help=".rela.plt entries", default=False, ) parser.add_argument( "--rodata", action="store_true", help="dump .rodata", default=False ) parser.add_argument( "--disass", type=str, help="disassembls a section by " "name in section headers", ) parser.add_argument( "--disassp", type=int, help="disassembls a section " "by index in program headers", ) parser.add_argument( "--got", action="store_true", help="dump .got section", default=False, ) parser.add_argument( "--gotplt", action="store_true", help="dump .got.plt section", default=False, ) self.args = parser.parse_args() if self.args.obj is None: raise Exception( "no object file provided. " "please specify an object with --obj." ) def byte2int(value, sign=False): return int.from_bytes(value, byteorder="little", signed=sign) def byte2hex(value): return hex(int.from_bytes(value, byteorder="little", signed=False)) def LEB128UnsignedDecode(bytelist): result = 0 shift = 0 for byte in bytelist: result |= (byte & 0x7F) << shift if (byte & 0x80) == 0: break shift += 7 return result def LEB128SignedDecode(bytelist): result = 0 shift = 0 for byte in bytelist: result |= (byte & 0x7F) << shift last_byte = byte shift += 7 if (byte & 0x80) == 0: break if last_byte & 0x40: result |= -(1 << shift) return result def LEB128UnsignedEncode(int_val): if int_val < 0: raise Exception("value must not be negative") if int_val == 0: return bytes([0]) byte_array = bytearray() while int_val: byte = int_val & 0x7F byte_array.append(byte | 0x80) int_val >>= 7 byte_array[-1] ^= 0x80 return byte_array def LEB128SignedEncode(int_val): byte_array = bytearray() while True: byte = int_val & 0x7F byte_array.append(byte | 0x80) int_val >>= 7 if (int_val == 0 and byte & 0x40 == 0) or (int_val == -1 and byte & 0x40): byte_array[-1] ^= 0x80 break return byte_array class ELF_REL: def __init__(self, r_offset, r_info): self.r_offset = r_offset self.r_info = r_info class ELF_RELA: def __init__(self, r_offset, r_info, r_addend): self.r_offset = r_offset self.r_info = r_info self.r_addend = r_addend def ffs(offset, header_list, numbered, *args): # cn = Colors.green ch = Colors.cyan cd = Colors.blue cb = Colors.BOLD ci = Colors.red ce = Colors.ENDC max_column_width = [] lines = [] numbers_f = [] dummy = [] if numbered: numbers_f.extend(range(1, len(args[-1]) + 1)) max_column_width.append( max([len(repr(number)) for number in numbers_f]) if numbers_f else 6 ) header_list.insert(0, "idx") for arg in args: max_column_width.append( max([len(repr(argette)) for argette in arg]) if arg else 6 ) index = range(0, len(header_list)) for header, width, i in zip(header_list, max_column_width, index): max_column_width[i] = max(len(header), width) + offset for i in index: dummy.append(ch + cb + header_list[i].ljust(max_column_width[i]) + ce) lines.append("".join(dummy)) dummy.clear() index2 = range(0, len(args[-1])) for i in index2: if numbered: dummy.append(ci + cb + repr(i).ljust(max_column_width[0]) + ce) for arg, width in zip(args, max_column_width[1:]): dummy.append(cd + repr(arg[i]).ljust(width) + ce) else: for arg, width in zip(args, max_column_width): dummy.append(cd + repr(arg[i]).ljust(width) + ce) lines.append("".join(dummy)) dummy.clear() return lines def get_section_type_string(number): if number == 0x0: return "NULL" if number == 0x1: return "PROGBITS" if number == 0x2: return "SYMTAB" if number == 0x3: return "STRTAB" if number == 0x4: return "RELA" if number == 0x5: return "HASH" if number == 0x6: return "DYNAMIC" if number == 0x7: return "NOTE" if number == 0x8: return "NOBITS" if number == 0x9: return "REL" if number == 0xA: return "SHLIB" if number == 0xB: return "DYNSYM" if number == 0xE: return "INIT_ARRAY" if number == 0xF: return "FINI_ARRAY" if number == 0x10: return "PREINIT" if number == 0x11: return "GROUP" if number == 0x12: return "SYMTAB" if number == 0x13: return "NUM" if number == 0x60000000: return "LOOS" if number == 0x6FFFFFF6: return "GNU_HASH" if number == 0x6FFFFFFF: return "VERSYM" if number == 0x6FFFFFFE: return "VERNEED" class sh_type_e: SHT_NULL = 0x0 SHT_PROGBITS = 0x1 SHT_SYMTAB = 0x2 SHT_STRTAB = 0x3 SHT_RELA = 0x4 SHT_HASH = 0x5 SHT_DYNAMIC = 0x6 SHT_NOTE = 0x7 SHT_NOBITS = 0x8 SHT_REL = 0x9 SHT_SHLIB = 0xA SHT_DYNSYM = 0xB SHT_INIT_ARRAY = 0xE SHT_FINI_ARRAY = 0xF SHT_PREINIT = 0x10 SHT_GROUP = 0x11 SHT_SYMTAB_SHNDX = 0x12 SHT_NUM = 0x13 SHT_LOOS = 0x60000000 GNU_HASH = 0x6FFFFFF6 VERSYM = 0x6FFFFFFF VERNEED = 0x6FFFFFFE class sh_flags_e: SHF_WRITE = 0x1 SHF_ALLOC = 0x2 SHF_EXECINSTR = 0x4 SHF_MERGE = 0x10 SHF_STRINGS = 0x20 SHF_INFO_LINK = 0x40 SHF_LINK_ORDER = 0x80 SHF_OS_NONCONFORMING = 0x100 SHF_GROUP = 0x200 SHF_TLS = 0x400 SHF_MASKOS = 0x0FF00000 SHF_MASKPROC = 0xF0000000 SHF_ORDERED = 0x4000000 SHF_EXCLUDE = 0x8000000 class p_type_e: PT_NULL = 0x0 PT_LOAD = 0x1 PT_DYNAMIC = 0x2 PT_INTERP = 0x3 PT_NOTE = 0x4 PT_SHLIB = 0x5 PT_PHDR = 0x6 PT_LOOS = 0x60000000 PT_HIOS = 0x6FFFFFFF PT_LOPROC = 0x70000000 PT_HIPROC = 0x7FFFFFFF GNU_EH_FRAME = 0x6474E550 GNU_STACK = 0x6474E551 GNU_RELRO = 0x6474E552 def get_ph_type(value): if value == p_type_e.PT_NULL: return "NULL" elif value == p_type_e.PT_LOAD: return "LOAD" elif value == p_type_e.PT_DYNAMIC: return "DYNAMIC" elif value == p_type_e.PT_INTERP: return "INTERP" elif value == p_type_e.PT_NOTE: return "NOTE" elif value == p_type_e.PT_SHLIB: return "SHLIB" elif value == p_type_e.PT_PHDR: return "PHDR" elif value == p_type_e.PT_LOOS: return "LOOS" elif value == p_type_e.PT_HIOS: return "HIOS" elif value == p_type_e.PT_LOPROC: return "LOPROC" elif value == p_type_e.PT_HIPROC: return "HIPROC" elif value == p_type_e.GNU_EH_FRAME: return "GNU_EH_FRAME" elif value == p_type_e.GNU_STACK: return "GNU_STACK" elif value == p_type_e.GNU_RELRO: return "GNU_RELRO" else: return None class ph_dynamic_entry: def __init__(self, d_tag, d_un): self.d_tag = d_tag self.d_un = d_un class elf_seg_flags: PF_X = 0x1 PF_W = 0x2 PF_R = 0x4 def get_elf_seg_flag(value): ret = [] if value & 0x01 == 1: ret.append("X") if (value & 0x02) >> 1 == 1: ret.append("W") if (value & 0x04) >> 2 == 1: ret.append("R") return "".join(ret) class PH_DYN_TAG_TYPE: DT_NULL = 0 DT_NEEDED = 1 DT_PLTRELSZ = 2 DT_PLTGOT = 3 DT_HASH = 4 DT_STRTAB = 5 DT_SYMTAB = 6 DT_RELA = 7 DT_RELASZ = 8 DT_RELAENT = 9 DT_STRSZ = 10 DT_SYMENT = 11 DT_INIT = 12 DT_FINI = 13 DT_SONAME = 14 DT_RPATH = 15 DT_SYMBOLIC = 16 DT_REL = 17 DT_RELSZ = 18 DT_RELENT = 19 DT_PLTREL = 20 DT_DEBUG = 21 DT_TEXTREL = 22 DT_JMPREL = 23 DT_LOPROC = 0x70000000 DT_HIPROC = 0x7FFFFFFF DT_BIND_NOW = 24 DT_INIT_ARRAY = 25 DT_FINI_ARRAY = 26 DT_INIT_ARRAYSZ = 27 DT_FINI_ARRAYSZ = 28 DT_RUNPATH = 29 DT_FLAGS = 30 DT_ENCODING = 32 DT_PREINIT_ARRAY = 32 DT_PREINIT_ARRAYSZ = 33 DT_NUM = 34 DT_LOOS = 0x6000000D DT_HIOS = 0x6FFFF000 DT_PROC_NUM = 0x0 DT_MIPS_NUM = 0x0 DT_VALRNGLO = 0x6FFFFD00 DT_GNU_PRELINKED = 0x6FFFFDF5 DT_GNU_CONFLICTSZ = 0x6FFFFDF6 DT_GNU_LIBLISTSZ = 0x6FFFFDF7 DT_CHECKSUM = 0x6FFFFDF8 DT_PLTPADSZ = 0x6FFFFDF9 DT_MOVEENT = 0x6FFFFDFA DT_MOVESZ = 0x6FFFFDFB DT_FEATURE_1 = 0x6FFFFDFC DT_POSFLAG_1 = 0x6FFFFDFD DT_SYMINSZ = 0x6FFFFDFE DT_SYMINENT = 0x6FFFFDFF DT_VALRNGHI = 0x6FFFFDFF DT_VALNUM = 12 DT_ADDRRNGLO = 0x6FFFFE00 DT_GNU_HASH = 0x6FFFFEF5 DT_TLSDESC_PLT = 0x6FFFFEF6 DT_TLSDESC_GOT = 0x6FFFFEF7 DT_GNU_CONFLICT = 0x6FFFFEF8 DT_GNU_LIBLIST = 0x6FFFFEF9 DT_CONFIG = 0x6FFFFEFA DT_DEPAUDIT = 0x6FFFFEFB DT_AUDIT = 0x6FFFFEFC DT_PLTPAD = 0x6FFFFEFD DT_MOVETAB = 0x6FFFFEFE DT_SYMINFO = 0x6FFFFEFF DT_ADDRRNGHI = 0x6FFFFEFF DT_ADDRNUM = 11 DT_VERSYM = 0x6FFFFFF0 DT_RELACOUNT = 0x6FFFFFF9 DT_RELCOUNT = 0x6FFFFFFA DT_FLAGS_1 = 0x6FFFFFFB DT_VERDEF = 0x6FFFFFFC DT_VERDEFNUM = 0x6FFFFFFD DT_VERNEED = 0x6FFFFFFE DT_VERNEEDNUM = 0x6FFFFFFF DT_VERSIONTAGNUM = 16 DT_AUXILIARY = 0x7FFFFFFD DT_FILTER = 0x7FFFFFFF DT_EXTRANUM = 3 def get_ph_dynamic_ent_tag_type(value): if value == PH_DYN_TAG_TYPE.DT_NULL: return "DT_NULL" elif value == PH_DYN_TAG_TYPE.DT_NEEDED: return "DT_NEEDED" elif value == PH_DYN_TAG_TYPE.DT_PLTRELSZ: return "DT_PLTRELSZ" elif value == PH_DYN_TAG_TYPE.DT_PLTGOT: return "DT_PLTGOT" elif value == PH_DYN_TAG_TYPE.DT_HASH: return "DT_HASH" elif value == PH_DYN_TAG_TYPE.DT_STRTAB: return "DT_STRTAB" elif value == PH_DYN_TAG_TYPE.DT_SYMTAB: return "DT_SYMTAB" elif value == PH_DYN_TAG_TYPE.DT_RELA: return "DT_RELA" elif value == PH_DYN_TAG_TYPE.DT_RELASZ: return "DT_RELASZ" elif value == PH_DYN_TAG_TYPE.DT_RELAENT: return "DT_RELAENT" elif value == PH_DYN_TAG_TYPE.DT_STRSZ: return "DT_STRSZ" elif value == PH_DYN_TAG_TYPE.DT_SYMENT: return "DT_SYMENT" elif value == PH_DYN_TAG_TYPE.DT_INIT: return "DT_INIT" elif value == PH_DYN_TAG_TYPE.DT_FINI: return "DT_FINI" elif value == PH_DYN_TAG_TYPE.DT_SONAME: return "DT_SONAME" elif value == PH_DYN_TAG_TYPE.DT_RPATH: return "DT_RPATH" elif value == PH_DYN_TAG_TYPE.DT_SYMBOLIC: return "DT_SYMBOLIC" elif value == PH_DYN_TAG_TYPE.DT_REL: return "DT_REL" elif value == PH_DYN_TAG_TYPE.DT_RELSZ: return "DT_RELSZ" elif value == PH_DYN_TAG_TYPE.DT_RELENT: return "DT_RELENT" elif value == PH_DYN_TAG_TYPE.DT_PLTREL: return "DT_PLTREL" elif value == PH_DYN_TAG_TYPE.DT_DEBUG: return "DT_DEBUG" elif value == PH_DYN_TAG_TYPE.DT_TEXTREL: return "DT_TEXTREL" elif value == PH_DYN_TAG_TYPE.DT_JMPREL: return "DT_JMPREL" elif value == PH_DYN_TAG_TYPE.DT_LOPROC: return "DT_LOPROC" elif value == PH_DYN_TAG_TYPE.DT_HIPROC: return "DT_HIPROC" elif value == PH_DYN_TAG_TYPE.DT_BIND_NOW: return "DT_BIND_NOW" elif value == PH_DYN_TAG_TYPE.DT_INIT_ARRAY: return "DT_INIT_ARRAY" elif value == PH_DYN_TAG_TYPE.DT_FINI_ARRAY: return "DT_FINI_ARRAY" elif value == PH_DYN_TAG_TYPE.DT_INIT_ARRAYSZ: return "DT_INIT_ARRAYSZ" elif value == PH_DYN_TAG_TYPE.DT_FINI_ARRAYSZ: return "DT_FINI_ARRAYSZ" elif value == PH_DYN_TAG_TYPE.DT_RUNPATH: return "DT_RUNPATH" elif value == PH_DYN_TAG_TYPE.DT_FLAGS: return "DT_FLAGS" elif value == PH_DYN_TAG_TYPE.DT_ENCODING: return "DT_ENCODING" elif value == PH_DYN_TAG_TYPE.DT_PREINIT_ARRAY: return "DT_PREINIT_ARRAY" elif value == PH_DYN_TAG_TYPE.DT_PREINIT_ARRAYSZ: return "DT_PREINIT_ARRAYSZ" elif value == PH_DYN_TAG_TYPE.DT_NUM: return "DT_NUM" elif value == PH_DYN_TAG_TYPE.DT_LOOS: return "DT_LOOS" elif value == PH_DYN_TAG_TYPE.DT_HIOS: return "DT_HIOS" # elif value == PH_DYN_TAG_TYPE.DT_PROC_NUM: return "DT_PROC_NUM" # elif value == PH_DYN_TAG_TYPE.DT_MIPS_NUM: return "DT_MIPS_NUM" elif value == PH_DYN_TAG_TYPE.DT_VALRNGLO: return "DT_VALRNGLO" elif value == PH_DYN_TAG_TYPE.DT_GNU_PRELINKED: return "DT_GNU_PRELINKED" elif value == PH_DYN_TAG_TYPE.DT_GNU_CONFLICTSZ: return "DT_GNU_CONFLICTSZ" elif value == PH_DYN_TAG_TYPE.DT_GNU_LIBLISTSZ: return "DT_GNU_LIBLISTSZ" elif value == PH_DYN_TAG_TYPE.DT_CHECKSUM: return "DT_CHECKSUM" elif value == PH_DYN_TAG_TYPE.DT_PLTPADSZ: return "DT_PLTPADSZ" elif value == PH_DYN_TAG_TYPE.DT_MOVEENT: return "DT_MOVEENT" elif value == PH_DYN_TAG_TYPE.DT_MOVESZ: return "DT_MOVESZ" elif value == PH_DYN_TAG_TYPE.DT_FEATURE_1: return "DT_FEATURE_1" elif value == PH_DYN_TAG_TYPE.DT_POSFLAG_1: return "DT_POSFLAG_1" elif value == PH_DYN_TAG_TYPE.DT_SYMINSZ: return "DT_SYMINSZ" elif value == PH_DYN_TAG_TYPE.DT_SYMINENT: return "DT_SYMINENT" elif value == PH_DYN_TAG_TYPE.DT_VALRNGHI: return "DT_VALRNGHI" # DT_VALNUM = 12 elif value == PH_DYN_TAG_TYPE.DT_ADDRRNGLO: return "DT_ADDRRNGLO" elif value == PH_DYN_TAG_TYPE.DT_GNU_HASH: return "DT_GNU_HASH" elif value == PH_DYN_TAG_TYPE.DT_TLSDESC_PLT: return "DT_TLSDESC_PLT" elif value == PH_DYN_TAG_TYPE.DT_TLSDESC_GOT: return "DT_TLSDESC_GOT" elif value == PH_DYN_TAG_TYPE.DT_GNU_CONFLICT: return "DT_GNU_CONFLICT" elif value == PH_DYN_TAG_TYPE.DT_GNU_LIBLIST: return "DT_GNU_LIBLIST" elif value == PH_DYN_TAG_TYPE.DT_CONFIG: return "DT_CONFIG" elif value == PH_DYN_TAG_TYPE.DT_DEPAUDIT: return "DT_DEPAUDIT" elif value == PH_DYN_TAG_TYPE.DT_AUDIT: return "DT_AUDIT" elif value == PH_DYN_TAG_TYPE.DT_PLTPAD: return "DT_PLTPAD" elif value == PH_DYN_TAG_TYPE.DT_MOVETAB: return "DT_MOVETAB" elif value == PH_DYN_TAG_TYPE.DT_SYMINFO: return "DT_SYMINFO" elif value == PH_DYN_TAG_TYPE.DT_ADDRRNGHI: return "DT_ADDRRNGHI" # DT_ADDRNUM = 11 elif value == PH_DYN_TAG_TYPE.DT_VERSYM: return "DT_VERSYM" elif value == PH_DYN_TAG_TYPE.DT_RELACOUNT: return "DT_RELACOUNT" elif value == PH_DYN_TAG_TYPE.DT_RELCOUNT: return "DT_RELCOUNT" elif value == PH_DYN_TAG_TYPE.DT_FLAGS_1: return "DT_FLAGS_1" elif value == PH_DYN_TAG_TYPE.DT_VERDEF: return "DT_VERDEF" elif value == PH_DYN_TAG_TYPE.DT_VERDEFNUM: return "DT_VERDEFNUM" elif value == PH_DYN_TAG_TYPE.DT_VERNEED: return "DT_VERNEED" elif value == PH_DYN_TAG_TYPE.DT_VERNEEDNUM: return "DT_VERNEEDNUM" elif value == PH_DYN_TAG_TYPE.DT_VERSIONTAGNUM: return "DT_VERSIONTAGNUM" elif value == PH_DYN_TAG_TYPE.DT_AUXILIARY: return "DT_AUXILIARY" elif value == PH_DYN_TAG_TYPE.DT_FILTER: return "DT_FILTER" # DT_EXTRANUM = 3 else: return str(value) # else: return "UNKNOWN" class X86_REL_TYPE: R_386_NONE = 0 R_386_32 = 1 R_386_PC32 = 2 R_386_GOT32 = 3 R_386_PLT32 = 4 R_386_COPY = 5 R_386_GLOB_DAT = 6 R_386_JMP_SLOT = 7 R_386_RELATIVE = 8 R_386_GOTOFF = 9 R_386_GOTPC = 10 R_386_32PLT = 11 R_386_16 = 12 R_386_PC16 = 13 R_386_8 = 14 R_386_PC8 = 15 R_386_SIZE32 = 16 def get_x86_rel_type(val): if val == X86_REL_TYPE.R_386_NONE: return "R_386_NONE" elif val == X86_REL_TYPE.R_386_32: return "R_386_32" elif val == X86_REL_TYPE.R_386_PC32: return "R_386_PC32" elif val == X86_REL_TYPE.R_386_GOT32: return "R_386_GOT32" elif val == X86_REL_TYPE.R_386_PLT32: return "R_386_PLT32" elif val == X86_REL_TYPE.R_386_COPY: return "R_386_COPY" elif val == X86_REL_TYPE.R_386_GLOB_DAT: return "R_386_GLOB_DAT" elif val == X86_REL_TYPE.R_386_JMP_SLOT: return "R_386_JMP_SLOT" elif val == X86_REL_TYPE.R_386_RELATIVE: return "R_386_RELATIVE" elif val == X86_REL_TYPE.R_386_GOTOFF: return "R_386_GOTOFF" elif val == X86_REL_TYPE.R_386_GOTPC: return "R_386_GOTPC" elif val == X86_REL_TYPE.R_386_32PLT: return "R_386_32PLT" elif val == X86_REL_TYPE.R_386_16: return "R_386_16" elif val == X86_REL_TYPE.R_386_PC16: return "R_386_PC16" elif val == X86_REL_TYPE.R_386_8: return "R_386_8" elif val == X86_REL_TYPE.R_386_PC8: return "R_386_PC8" elif val == X86_REL_TYPE.R_386_SIZE32: return "R_386_SIZE32" else: return "UNKNOWN" class X86_64_REL_TYPE: R_AMD64_NONE = 0 R_AMD64_64 = 1 R_AMD64_PC32 = 2 R_AMD64_GOT32 = 3 R_AMD64_PLT32 = 4 R_AMD64_COPY = 5 R_AMD64_GLOB_DAT = 6 R_AMD64_JUMP_SLOT = 7 R_AMD64_RELATIVE = 8 R_AMD64_GOTPCREL = 9 R_AMD64_32 = 10 R_AMD64_32S = 11 R_AMD64_16 = 12 R_AMD64_PC16 = 13 R_AMD64_8 = 14 R_AMD64_PC8 = 15 R_AMD64_PC64 = 24 R_AMD64_GOTOFF64 = 25 R_AMD64_GOTPC32 = 26 R_AMD64_SIZE32 = 32 R_AMD64_SIZE64 = 33 class X86_64_REL_TYPE_2: R_X86_64_NONE = 0 R_X86_64_64 = 1 R_X86_64_PC32 = 2 R_X86_64_GOT32 = 3 R_X86_64_PLT32 = 4 R_X86_64_COPY = 5 R_X86_64_GLOB_DAT = 6 R_X86_64_JUMP_SLOT = 7 R_X86_64_RELATIVE = 8 R_X86_64_GOTPCREL = 9 R_X86_64_32 = 10 R_X86_64_32S = 11 R_X86_64_16 = 12 R_X86_64_PC16 = 13 R_X86_64_64_8 = 14 R_X86_64_PC8 = 15 R_X86_64_DTPMOD64 = 16 R_X86_64_DTPOFF64 = 17 R_X86_64_TPOFF64 = 18 R_X86_64_TLSGD = 19 R_X86_64_TLSLD = 20 R_X86_64_DTPOFF32 = 21 R_X86_64_GOTTPOFF = 22 R_X86_64_TPOFF32 = 23 R_X86_64_PC64 = 24 R_X86_64_GOTOFF64 = 25 R_X86_64_GOTPC32 = 26 R_X86_64_SIZE32 = 32 R_X86_64_SIZE64 = 33 R_X86_64_GOTPC32_TLDSEC = 34 R_X86_64_TLDSEC_CALL = 35 R_X86_64_TLDSEC = 36 R_X86_64_IRELATIVE = 37 def get_x86_64_rel_type(val): if val == X86_64_REL_TYPE.R_AMD64_NONE: return "R_386_NONE" elif val == X86_64_REL_TYPE.R_AMD64_64: return "R_AMD64_64" elif val == X86_64_REL_TYPE.R_AMD64_PC32: return "R_AMD64_PC32" elif val == X86_64_REL_TYPE.R_AMD64_GOT32: return "R_AMD64_GOT32" elif val == X86_64_REL_TYPE.R_AMD64_PLT32: return "R_AMD64_PLT32" elif val == X86_64_REL_TYPE.R_AMD64_COPY: return "R_AMD64_COPY" elif val == X86_64_REL_TYPE.R_AMD64_GLOB_DAT: return "R_AMD64_GLOB_DAT" elif val == X86_64_REL_TYPE.R_AMD64_JUMP_SLOT: return "R_AMD64_JUMP_SLOT" elif val == X86_64_REL_TYPE.R_AMD64_RELATIVE: return "R_AMD64_RELATIVE" elif val == X86_64_REL_TYPE.R_AMD64_GOTPCREL: return "R_AMD64_GOTPCREL" elif val == X86_64_REL_TYPE.R_AMD64_32: return "R_AMD64_32" elif val == X86_64_REL_TYPE.R_AMD64_32S: return "R_AMD64_32S" elif val == X86_64_REL_TYPE.R_AMD64_16: return "R_AMD64_16" elif val == X86_64_REL_TYPE.R_AMD64_PC16: return "R_AMD64_PC16" elif val == X86_64_REL_TYPE.R_AMD64_8: return "R_AMD64_8" elif val == X86_64_REL_TYPE.R_AMD64_PC8: return "R_AMD64_PC8" elif val == X86_64_REL_TYPE.R_AMD64_PC64: return "R_AMD64_PC64" elif val == X86_64_REL_TYPE.R_AMD64_GOTOFF64: return "R_AMD64_GOTOFF64" elif val == X86_64_REL_TYPE.R_AMD64_GOTPC32: return "R_AMD64_GOTPC32" elif val == X86_64_REL_TYPE.R_AMD64_SIZE32: return "R_AMD64_SIZE32" elif val == X86_64_REL_TYPE.R_AMD64_SIZE64: return "R_AMD64_SIZE64" else: return "UNKNOWN" def get_x86_64_rel_type_2(val): if val == X86_64_REL_TYPE_2.R_X86_64_NONE: return "R_X86_64_NONE" elif val == X86_64_REL_TYPE_2.R_X86_64_64: return "R_X86_64_64" elif val == X86_64_REL_TYPE_2.R_X86_64_PC32: return "R_X86_64_PC32" elif val == X86_64_REL_TYPE_2.R_X86_64_GOT32: return "R_X86_64_GOT32" elif val == X86_64_REL_TYPE_2.R_X86_64_PLT32: return "R_X86_64_PLT32" elif val == X86_64_REL_TYPE_2.R_X86_64_COPY: return "R_X86_64_COPY" elif val == X86_64_REL_TYPE_2.R_X86_64_GLOB_DAT: return "R_X86_64_GLOB_DAT" elif val == X86_64_REL_TYPE_2.R_X86_64_JUMP_SLOT: return "R_X86_64_JUMP_SLOT" elif val == X86_64_REL_TYPE_2.R_X86_64_RELATIVE: return "R_X86_64_RELATIVE" elif val == X86_64_REL_TYPE_2.R_X86_64_GOTPCREL: return "R_X86_64_GOTPCREL" elif val == X86_64_REL_TYPE_2.R_X86_64_32: return "R_X86_64_32" elif val == X86_64_REL_TYPE_2.R_X86_64_32S: return "R_X86_64_32S" elif val == X86_64_REL_TYPE_2.R_X86_64_16: return "R_X86_64_16" elif val == X86_64_REL_TYPE_2.R_X86_64_PC16: return "R_X86_64_PC16" elif val == X86_64_REL_TYPE_2.R_X86_64_64_8: return "R_X86_64_64_8" elif val == X86_64_REL_TYPE_2.R_X86_64_PC8: return "R_X86_64_PC8" elif val == X86_64_REL_TYPE_2.R_X86_64_DTPMOD64: return "R_X86_64_DTPMOD64" elif val == X86_64_REL_TYPE_2.R_X86_64_DTPOFF64: return "R_X86_64_DTPOFF64" elif val == X86_64_REL_TYPE_2.R_X86_64_TPOFF64: return "R_X86_64_TPOFF64" elif val == X86_64_REL_TYPE_2.R_X86_64_TLSGD: return "R_X86_64_TLSGD" elif val == X86_64_REL_TYPE_2.R_X86_64_TLSLD: return "R_X86_64_TLSLD" elif val == X86_64_REL_TYPE_2.R_X86_64_DTPOFF32: return "R_X86_64_DTPOFF32" elif val == X86_64_REL_TYPE_2.R_X86_64_GOTTPOFF: return "R_X86_64_GOTTPOFF" elif val == X86_64_REL_TYPE_2.R_X86_64_TPOFF32: return "R_X86_64_TPOFF32" elif val == X86_64_REL_TYPE_2.R_X86_64_PC64: return "R_X86_64_PC64" elif val == X86_64_REL_TYPE_2.R_X86_64_GOTOFF64: return "R_X86_64_GOTOFF64" elif val == X86_64_REL_TYPE_2.R_X86_64_GOTPC32: return "R_X86_64_GOTPC32" elif val == X86_64_REL_TYPE_2.R_X86_64_SIZE32: return "R_X86_64_SIZE32" elif val == X86_64_REL_TYPE_2.R_X86_64_SIZE64: return "R_X86_64_SIZE64" elif val == X86_64_REL_TYPE_2.R_X86_64_GOTPC32_TLDSEC: return "R_X86_64_GOTPC32_TLDSEC" elif val == X86_64_REL_TYPE_2.R_X86_64_TLDSEC_CALL: return "R_X86_64_TLDSEC_CALL" elif val == X86_64_REL_TYPE_2.R_X86_64_TLDSEC: return "R_X86_64_TLDSEC" elif val == X86_64_REL_TYPE_2.R_X86_64_IRELATIVE: return "R_X86_64_IRELATIVE" else: return "UNKNOWN" class ELF_ST_BIND: STB_LOCAL = 0 STB_GLOBAL = 1 STB_WEAK = 2 STB_LOOS = 10 STB_HIOS = 12 STB_LOPROC = 13 STB_HIPROC = 15 def get_elf_st_bind_string(value): if value == ELF_ST_BIND.STB_LOCAL: return "STB_LOCAL" elif value == ELF_ST_BIND.STB_GLOBAL: return "STB_GLOBAL" elif value == ELF_ST_BIND.STB_WEAK: return "STB_WEAK" elif value == ELF_ST_BIND.STB_LOOS: return "STB_LOOS" elif value == ELF_ST_BIND.STB_HIOS: return "STB_HIOS" elif value == ELF_ST_BIND.STB_LOPROC: return "STB_LOPROC" elif value == ELF_ST_BIND.STB_LOPROC: return "STB_HIPROC" else: return None class ELF_ST_TYPE: STT_NOTYPE = 0 STT_OBJECT = 1 STT_FUNC = 2 STT_SECTION = 3 STT_FILE = 4 STT_COMMON = 5 STT_TLS = 6 STT_LOOS = 10 STT_HIOS = 12 STT_LOPROC = 13 STT_SPARC_REGISTER = 13 STT_HIPROC = 15 def get_elf_st_type_string(value): if value == ELF_ST_TYPE.STT_NOTYPE: return "STT_NOTYPE" elif value == ELF_ST_TYPE.STT_OBJECT: return "STT_OBJECT" elif value == ELF_ST_TYPE.STT_FUNC: return "STT_FUNC" elif value == ELF_ST_TYPE.STT_SECTION: return "STT_SECTION" elif value == ELF_ST_TYPE.STT_FILE: return "STT_FILE" elif value == ELF_ST_TYPE.STT_COMMON: return "STT_COMMON" elif value == ELF_ST_TYPE.STT_TLS: return "STT_TLS" elif value == ELF_ST_TYPE.STT_LOOS: return "STT_LOOS" elif value == ELF_ST_TYPE.STT_HIOS: return "STT_HIOS" elif value == ELF_ST_TYPE.STT_LOPROC: return "STT_LOPROC" elif value == ELF_ST_TYPE.STT_SPARC_REGISTER: return "STT_SPARC_REGISTER" elif value == ELF_ST_TYPE.STT_HIPROC: return "STT_HIPROC" else: return None class ELF_VIS: STV_DEFAULT = 0 STV_INTERNAL = 1 STV_HIDDEN = 2 STV_PROTECTED = 3 STV_EXPORTED = 4 STV_SINGLETON = 5 STV_ELIMINATE = 6 def get_elf_vis_string(value): if value == ELF_VIS.STV_DEFAULT: return "STV_DEFAULT" elif value == ELF_VIS.STV_INTERNAL: return "STV_INTERNAL" elif value == ELF_VIS.STV_HIDDEN: return "STV_HIDDEN" elif value == ELF_VIS.STV_PROTECTED: return "STV_PROTECTED" elif value == ELF_VIS.STV_EXPORTED: return "STV_EXPORTED" elif value == ELF_VIS.STV_SINGLETON: return "STV_SINGLETON" elif value == ELF_VIS.STV_ELIMINATE: return "STV_ELIMINATE" else: return None class Colors: purple = "\033[95m" blue = "\033[94m" green = "\033[92m" yellow = "\033[93m" red = "\033[91m" grey = "\033[1;37m" darkgrey = "\033[1;30m" cyan = "\033[1;36m" ENDC = "\033[0m" BOLD = "\033[1m" UNDERLINE = "\033[4m" def openSO_r(path): so = open(path, "rb") return so def openSO_w(path): so = open(path, "wb") return so class ELFHDR: def __init__( self, ei_mag, ei_class, ei_data, ei_version, ei_osabi, ei_abiversion, ei_pad, e_type, e_machine, e_version, e_entry, e_phoff, e_shoff, e_flags, e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum, e_shstrndx, ): self.ei_mag = ei_mag self.ei_class = ei_class self.ei_data = ei_data self.ei_version = ei_version self.ei_osabi = ei_osabi self.ei_abiversion = ei_abiversion self.ei_pad = ei_pad self.e_type = e_type self.e_machine = e_machine self.e_version = e_version self.e_entry = e_entry self.e_phoff = e_phoff self.e_shoff = e_shoff self.e_flags = e_flags self.e_ehsize = e_ehsize self.e_phentsize = e_phentsize self.e_phnum = e_phnum self.e_shentsize = e_shentsize self.e_shnum = e_shnum self.e_shstrndx = e_shstrndx class PHDR: def __init__( self, p_type, p_flags, p_offset, p_vaddr, p_paddr, p_filesz, p_memsz, p_flags2, p_align, ): self.p_type = p_type self.p_flags = p_flags self.p_offset = p_offset self.p_vaddr = p_vaddr self.p_paddr = p_paddr self.p_filesz = p_filesz self.p_memsz = p_memsz self.p_flags2 = p_flags2 self.p_align = p_align class SHDR: def __init__( self, sh_name, sh_type, sh_flags, sh_addr, sh_offset, sh_size, sh_link, sh_info, sh_addralign, sh_entsize, ): self.sh_name = sh_name self.sh_type = sh_type self.sh_flags = sh_flags self.sh_addr = sh_addr self.sh_offset = sh_offset self.sh_size = sh_size self.sh_link = sh_link self.sh_info = sh_info self.sh_addralign = sh_addralign self.sh_entsize = sh_entsize class Symbol_Table_Entry64: def __init__( self, st_name, st_info, st_other, st_shndx, st_value, st_size, st_bind, st_type, ): self.st_name = st_name self.st_info = st_info self.st_other = st_other self.st_shndx = st_shndx self.st_value = st_value self.st_size = st_size self.st_bind = st_bind self.st_type = st_type class ELF(object): def __init__(self, so): self.so = so self.so.seek(0, 0) self.elfhdr = ELFHDR(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) self.phdr = [] self.shhdr = [] self.size = int() self.string_tb_e = [] self.string_tb_e_dyn = [] self.symbol_table_e = [] self.data_section = [] self.text_section = [] self.dlpath = str() self.ph_dyn_ent = [] self.dyn_section = [] self.dyn_section_ents = [] self.rela_dyn = [] self.rela_dyn_ents = [] self.rela_plt = [] self.rela_plt_ents = [] self.rodata = [] self.plt = [] self.got = [] self.got_plt = [] self.plt_got = [] self.plt_ents = [] self.plt_got_ents = [] self.got_ents = [] self.got_plt_ents = [] def init(self, size): self.size = size self.read_ELF_H(size) self.so.seek(byte2int(self.elfhdr.e_phoff)) phnum = byte2int(self.elfhdr.e_phnum) for i in range(0, phnum): self.read_PHDR(size) self.so.seek(byte2int(self.elfhdr.e_shoff)) shnum = byte2int(self.elfhdr.e_shnum) for i in range(0, shnum): self.read_SHDR(size) for i in range(0, shnum): type = byte2int(self.shhdr[i].sh_type) if type == sh_type_e.SHT_SYMTAB: self.so.seek(byte2int(self.shhdr[i].sh_offset), 0) symbol_tb = self.so.read(byte2int(self.shhdr[i].sh_size)) offset = 0 num = int(byte2int(self.shhdr[i].sh_size) / 24) for j in range(0, num): self.read_st_entry( symbol_tb[offset : offset + 24], self.string_tb_e ) offset += 24 if type == sh_type_e.SHT_DYNSYM: self.so.seek(byte2int(self.shhdr[i].sh_offset), 0) symbol_tb = self.so.read(byte2int(self.shhdr[i].sh_size)) offset = 0 num = int(byte2int(self.shhdr[i].sh_size) / 24) for j in range(0, num): self.read_st_entry( symbol_tb[offset : offset + 24], self.string_tb_e_dyn ) offset += 24 self.pop_data_section() self.pop_text_section() self.get_ph_dyn_entries() self.pop_dynamic_entries(".dynamic", self.dyn_section_ents) self.pop_rela(".rela.plt", self.rela_plt, self.rela_plt_ents) self.pop_rela(".rela.dyn", self.rela_dyn, self.rela_dyn_ents) # self.pop_rel() def read_ELF_H(self, size): self.elfhdr.ei_mag = self.so.read(4) self.elfhdr.ei_class = self.so.read(1) self.elfhdr.ei_data = self.so.read(1) self.elfhdr.ei_version = self.so.read(1) self.elfhdr.ei_osabi = self.so.read(1) self.elfhdr.ei_abiversion = self.so.read(1) self.elfhdr.ei_pad = self.so.read(7) self.elfhdr.e_type = self.so.read(2) self.elfhdr.e_machine = self.so.read(2) self.elfhdr.e_version = self.so.read(4) if size == 32: self.elfhdr.e_entry = self.so.read(4) elif size == 64: self.elfhdr.e_entry = self.so.read(8) if size == 32: self.elfhdr.e_phoff = self.so.read(4) elif size == 64: self.elfhdr.e_phoff = self.so.read(8) if size == 32: self.elfhdr.e_shoff = self.so.read(4) elif size == 64: self.elfhdr.e_shoff = self.so.read(8) self.elfhdr.e_flags = self.so.read(4) self.elfhdr.e_ehsize = self.so.read(2) self.elfhdr.e_phentsize = self.so.read(2) self.elfhdr.e_phnum = self.so.read(2) self.elfhdr.e_shentsize = self.so.read(2) self.elfhdr.e_shnum = self.so.read(2) self.elfhdr.e_shstrndx = self.so.read(2) def read_PHDR(self, size): dummy = PHDR(0, 0, 0, 0, 0, 0, 0, 0, 0) dummy.p_type = self.so.read(4) if size == 64: dummy.p_flags = self.so.read(4) if size == 32: dummy.p_offset = self.so.read(4) elif size == 64: dummy.p_offset = self.so.read(8) if size == 32: dummy.p_vaddr = self.so.read(4) elif size == 64: dummy.p_vaddr = self.so.read(8) if size == 32: dummy.p_paddr = self.so.read(4) elif size == 64: dummy.p_paddr = self.so.read(8) if size == 32: dummy.p_filesz = self.so.read(4) elif size == 64: dummy.p_filesz = self.so.read(8) if size == 32: dummy.p_memsz = self.so.read(4) elif size == 64: dummy.p_memsz = self.so.read(8) if size == 32: dummy.p_flags2 = self.so.read(4) elif size == 64: pass if size == 32: dummy.p_align = self.so.read(4) elif size == 64: dummy.p_align = self.so.read(8) self.phdr.append(dummy) def read_SHDR(self, size): dummy = SHDR(0, 0, 0, 0, 0, 0, 0, 0, 0, 0) dummy.sh_name = self.so.read(4) dummy.sh_type = self.so.read(4) if size == 32: dummy.sh_flags = self.so.read(4) elif size == 64: dummy.sh_flags = self.so.read(8) if size == 32: dummy.sh_addr = self.so.read(4) elif size == 64: dummy.sh_addr = self.so.read(8) if size == 32: dummy.sh_offset = self.so.read(4) elif size == 64: dummy.sh_offset = self.so.read(8) if size == 32: dummy.sh_size = self.so.read(4) elif size == 64: dummy.sh_size = self.so.read(8) dummy.sh_link = self.so.read(4) dummy.sh_info = self.so.read(4) if size == 32: dummy.sh_addralign = self.so.read(4) elif size == 64: dummy.sh_addralign = self.so.read(8) if size == 32: dummy.sh_entsize = self.so.read(4) elif size == 64: dummy.sh_entsize = self.so.read(8) self.shhdr.append(dummy) def read_st_entry(self, st, entry_list): dummy = Symbol_Table_Entry64(0, 0, 0, 0, 0, 0, 0, 0) dummy.st_name = st[0:4] dummy.st_info = st[4:5] dummy.st_other = st[5:6] dummy.st_shndx = st[6:8] dummy.st_value = st[8:16] dummy.st_size = st[16:24] dummy.st_bind = byte2int(dummy.st_info) >> 4 dummy.st_type = byte2int(dummy.st_info) & 0x0F entry_list.append(dummy) def read_section_name(self, index): shstrtab_index = byte2int(self.elfhdr.e_shstrndx) name = [] self.so.seek(byte2int(self.shhdr[shstrtab_index].sh_offset), 0) strings = self.so.read(byte2int(self.shhdr[shstrtab_index].sh_size)) char = strings[index] while chr(char) != "\0": index += 1 name.append(chr(char)) char = strings[index] return "".join(name) def get_ph_dyn_entries(self): size = 0 for phdr in self.phdr: if byte2int(phdr.p_type) == p_type_e.PT_DYNAMIC: self.so.seek(byte2int(phdr.p_offset), 0) size = byte2int(phdr.p_filesz) ph_dyn = self.so.read(size) for i in range(int(size / 8)): d_tag = byte2int(ph_dyn[8 * i : 8 * i + 4]) d_un = byte2int(ph_dyn[8 * i + 4 : 8 * i + 8]) self.ph_dyn_ent.append(ph_dynamic_entry(d_tag, d_un)) def dump_ph_dyn_entries(self): header = ["d_tag", "d_un"] tag_list = [get_ph_dynamic_ent_tag_type(ph.d_tag) for ph in self.ph_dyn_ent] un_list = [ph.d_un for ph in self.ph_dyn_ent] lines = ffs(2, header, True, tag_list, un_list) for line in lines: print(line) def dump_funcs(self, dump_b): ret_list = [] dummy = [] ret_list_int = [] for iter in self.string_tb_e: if iter.st_type == ELF_ST_TYPE.STT_FUNC: self.so.seek(int.from_bytes(iter.st_value, byteorder="little")) obj = self.so.read(int.from_bytes(iter.st_size, byteorder="little")) ret_list.append(obj) for byte in obj: dummy.append(int(byte)) ret_list_int.append(dummy) dummy = [] if dump_b: for obj in ret_list_int: for byte in obj: print(format(byte, "02x") + " ", end="") print("\n") return ret_list_int def dump_symbol_string(self, stt_type, dump_b): ret_list = [] for entry in self.string_tb_e: if entry.st_type == stt_type: ret_list.append( "".join( self.get_st_entry_symbol_string( byte2int(entry.st_name), ".strtab" ) ) ) if dump_b: for name in ret_list: print(name) return ret_list def dump_section(self, section_name, dump): hit = False for section in self.shhdr: name = self.read_section_name(byte2int(section.sh_name)) if name == section_name: hit = True self.so.seek(byte2int(section.sh_offset)) obj = self.so.read(byte2int(section.sh_size)) if section_name == ".interp": self.dlpath = repr(obj) count = int() if dump: strrep = [] for byte in obj: if count % 16 == 0: for ch in strrep: if ord(ch) > 32 and ord(ch) < 127: print(ch, end="") else: print(" ", end="") print() strrep = [] print(format(count, "06x"), ": ", end="") strrep.append(str(chr(byte))) print(format(byte, "02x") + " ", end="") else: strrep += str(chr(byte)) print(format(byte, "02x") + " ", end="") count += 1 for i in range(0, 16 - count % 16): print(" ", end="") for ch in strrep: if ord(ch) > 32 and ord(ch) < 127: print(ch, end="") else: print(" ", end="") print() ret_dummy = [] for i in range(0, len(obj)): ret_dummy.append(obj[i]) # print(ret_dummy) return ret_dummy if not hit: print(Colors.red + Colors.BOLD + "section is not present" + Colors.ENDC) def dump_obj_size(self, stt_type, dump_b): ret_list = [] for entry in self.string_tb_e: if entry.st_type == stt_type: ret_list.append(byte2int(entry.st_size)) if dump_b: for name in ret_list: print(name) return ret_list def dump_symbol_idx(self): header = ["name", "size", "value", "info", "other", "shndx"] name_list = [byte2int(st.st_name) for st in self.string_tb_e] size_list = [byte2int(st.st_size) for st in self.string_tb_e] value_list = [byte2int(st.st_value) for st in self.string_tb_e] info_list = [byte2int(st.st_info) for st in self.string_tb_e] other_list = [byte2int(st.st_other) for st in self.string_tb_e] shndx_list = [byte2int(st.st_shndx) for st in self.string_tb_e] lines = ffs( 2, header, True, name_list, size_list, value_list, info_list, other_list, shndx_list, ) print(Colors.green + Colors.BOLD + "symbol:" + Colors.ENDC) for line in lines: print(line) print(Colors.green + Colors.BOLD + "dyn symbol:" + Colors.ENDC) header = ["name", "size", "value", "info", "other", "shndx"] name_list = [byte2int(st.st_name) for st in self.string_tb_e_dyn] size_list = [byte2int(st.st_size) for st in self.string_tb_e_dyn] value_list = [byte2int(st.st_value) for st in self.string_tb_e_dyn] info_list = [byte2int(st.st_info) for st in self.string_tb_e_dyn] other_list = [byte2int(st.st_other) for st in self.string_tb_e_dyn] shndx_list = [byte2int(st.st_shndx) for st in self.string_tb_e_dyn] lines = ffs( 2, header, True, name_list, size_list, value_list, info_list, other_list, shndx_list, ) for line in lines: print(line) def dump_header(self): header = [ "ei_mag", "ei_class", "ei_data", "ei_version", "ei_osabi", "ei_abiversion", "ei_pad", "e_type", "e_machine", "e_version", "e_version", "e_entry", "e_phoff", "e_shoff", "e_flags", "e_entsize", "e_phentsize", "e_phnum", "e_shentsize", "e_shnum", "e_shstrndx", ] mag_list = [self.elfhdr.ei_mag] class_list = [byte2int(self.elfhdr.ei_class)] data_list = [byte2int(self.elfhdr.ei_data)] version_list = [byte2int(self.elfhdr.ei_version)] osabi_list = [byte2int(self.elfhdr.ei_osabi)] abiversion_list = [byte2int(self.elfhdr.ei_abiversion)] pad_list = [byte2int(self.elfhdr.ei_pad)] type_list = [byte2int(self.elfhdr.e_type)] machine_list = [byte2int(self.elfhdr.e_machine)] # e_version_list = [byte2int(self.elfhdr.e_version)] entry_list = [byte2int(self.elfhdr.e_entry)] phoff_list = [byte2int(self.elfhdr.e_phoff)] shoff_list = [byte2int(self.elfhdr.e_shoff)] flags_list = [byte2int(self.elfhdr.e_flags)] ehsize_list = [byte2int(self.elfhdr.e_ehsize)] phentsize_list = [byte2int(self.elfhdr.e_phentsize)] phnum_list = [byte2int(self.elfhdr.e_phnum)] shentsize_list = [byte2int(self.elfhdr.e_shentsize)] shnum_list = [byte2int(self.elfhdr.e_shnum)] shstrndx_list = [byte2int(self.elfhdr.e_shstrndx)] lines = ffs( 2, header, True, mag_list, class_list, data_list, version_list, osabi_list, abiversion_list, pad_list, type_list, machine_list, version_list, entry_list, phoff_list, shoff_list, flags_list, ehsize_list, phentsize_list, phnum_list, shentsize_list, phnum_list, shentsize_list, shnum_list, shstrndx_list, ) for line in lines: print(line) def dump_phdrs(self): header = [ "p_type", "p_flags", "p_offset", "p_vaddr", "p_paddr", "p_filesz", "p_memsz", "p_flags2", "p_align", ] type_list = [get_ph_type(byte2int(phdr.p_type)) for phdr in self.phdr] flags_list = [get_elf_seg_flag(byte2int(phdr.p_type)) for phdr in self.phdr] offset_list = [byte2int(phdr.p_offset) for phdr in self.phdr] vaddr_list = [byte2int(phdr.p_vaddr) for phdr in self.phdr] paddr_list = [byte2int(phdr.p_paddr) for phdr in self.phdr] filesz_list = [byte2int(phdr.p_filesz) for phdr in self.phdr] memsz_list = [byte2int(phdr.p_memsz) for phdr in self.phdr] flags2_list = [phdr.p_flags2 for phdr in self.phdr] align_list = [byte2hex(phdr.p_align) for phdr in self.phdr] lines = ffs( 2, header, True, type_list, flags_list, offset_list, vaddr_list, paddr_list, filesz_list, memsz_list, flags2_list, align_list, ) for line in lines: print(line) def dump_shdrs(self): header = [ "sh_name", "sh_type", "sh_flags", "sh_addr", "sh_offset", "sh_size", "sh_link", "sh_info", "sh_addralign", "sh_entsize", ] name_list = [ self.read_section_name(byte2int(shhdr.sh_name)) for shhdr in self.shhdr ] type_list = [ get_section_type_string(byte2int(shhdr.sh_type)) for shhdr in self.shhdr ] flag_list = [byte2int(shhdr.sh_flags) for shhdr in self.shhdr] addr_list = [byte2int(shhdr.sh_addr) for shhdr in self.shhdr] offset_list = [byte2int(shhdr.sh_offset) for shhdr in self.shhdr] size_list = [byte2int(shhdr.sh_size) for shhdr in self.shhdr] link_list = [byte2int(shhdr.sh_link) for shhdr in self.shhdr] info_list = [byte2int(shhdr.sh_info) for shhdr in self.shhdr] allign_list = [byte2int(shhdr.sh_addralign) for shhdr in self.shhdr] entsize_list = [byte2int(shhdr.sh_entsize) for shhdr in self.shhdr] lines = ffs( 2, header, True, name_list, type_list, flag_list, addr_list, offset_list, size_list, link_list, info_list, allign_list, entsize_list, ) for line in lines: print(line) def dump_symbol_tb(self, name, type): for i in range(0, byte2int(self.elfhdr.e_shnum)): if byte2int(self.shhdr[i].sh_type) == type: if name == self.read_section_name(byte2int(self.shhdr[i].sh_name)): print(Colors.BOLD + Colors.yellow + "STRING TABLE:" + Colors.ENDC) self.so.seek(byte2int(self.shhdr[i].sh_offset), 0) symbol_tb = self.so.read(byte2int(self.shhdr[i].sh_size)) for byte in symbol_tb: print(chr(byte), end="") if chr(byte) == "\0": print() def dump_st_entries(self): header = [ "name_index", "name", "value", "size", "info", "other", "shndx", "bind", "type", ] idx_list = [byte2int(entry.st_name) for entry in self.string_tb_e] name_list = [ "".join(self.get_st_entry_symbol_string(byte2int(entry.st_name), ".strtab")) for entry in self.string_tb_e ] value_list = [byte2int(entry.st_value) for entry in self.string_tb_e] size_list = [byte2int(entry.st_size) for entry in self.string_tb_e] info_list = [byte2int(entry.st_info) for entry in self.string_tb_e] other_list = [byte2int(entry.st_other) for entry in self.string_tb_e] shndx_list = [byte2int(entry.st_shndx) for entry in self.string_tb_e] bind_list = [ get_elf_st_bind_string(entry.st_bind) for entry in self.string_tb_e ] type_list = [ get_elf_st_type_string(entry.st_type) for entry in self.string_tb_e ] lines = ffs( 2, header, True, idx_list, name_list, value_list, size_list, info_list, other_list, shndx_list, bind_list, type_list, ) for line in lines: print(line) def dump_st_entries_dyn(self): header = [ "name_index", "name", "value", "size", "info", "other", "shndx", "bind", "type", ] idx_list = [byte2int(entry.st_name) for entry in self.string_tb_e_dyn] name_list = [ "".join(self.get_st_entry_symbol_string(byte2int(entry.st_name), ".dynstr")) for entry in self.string_tb_e_dyn ] value_list = [byte2int(entry.st_value) for entry in self.string_tb_e_dyn] size_list = [byte2int(entry.st_size) for entry in self.string_tb_e_dyn] info_list = [byte2int(entry.st_info) for entry in self.string_tb_e_dyn] other_list = [byte2int(entry.st_other) for entry in self.string_tb_e_dyn] shndx_list = [byte2int(entry.st_shndx) for entry in self.string_tb_e_dyn] bind_list = [ get_elf_st_bind_string(entry.st_bind) for entry in self.string_tb_e_dyn ] type_list = [ get_elf_st_type_string(entry.st_type) for entry in self.string_tb_e_dyn ] lines = ffs( 2, header, True, idx_list, name_list, value_list, size_list, info_list, other_list, shndx_list, bind_list, type_list, ) for line in lines: print(line) def dump_dyn_sec_ents(self, who): header = ["type_string", "tag", "value", "value(hex)"] tag_string_list = [entry["type_string"] for entry in who] tag_list = [entry["tag"] for entry in who] value_list = [entry["value"] for entry in who] value_list_hex = [hex(entry["value"]) for entry in who] lines = ffs( 2, header, True, tag_string_list, tag_list, value_list, value_list_hex, ) for line in lines: print(line) def dump_rela(self, to_dump): header = ["r_offset", "r_info", "r_addend"] r_offset_list = [entry["r_offset"] for entry in to_dump] r_info_list = [entry["r_info"] for entry in to_dump] addend_list = [entry["r_addend"] for entry in to_dump] lines = ffs(2, header, True, r_offset_list, r_info_list, addend_list) for line in lines: print(line) def dump_rel(self, to_dump): header = ["r_offset", "r_info"] r_offset_list = [entry["r_offset"] for entry in to_dump] r_info_list = [entry["r_info"] for entry in to_dump] lines = ffs(2, header, True, r_offset_list, r_info_list) for line in lines: print(line) def get_st_entry_symbol_string(self, index, section_name): symbol = [] for i in range(0, byte2int(self.elfhdr.e_shnum)): name = self.read_section_name(byte2int(self.shhdr[i].sh_name)) if ( byte2int(self.shhdr[i].sh_type) == sh_type_e.SHT_STRTAB and name == section_name ): self.so.seek(byte2int(self.shhdr[i].sh_offset) + index, 0) byte = self.so.read(1) while chr(byte[0]) != "\0": if chr(byte[0]) != "\0": symbol.append(chr(byte[0])) byte = self.so.read(1) return symbol def get_symbol_string_table(self, offset): symbol = [] for i in range( 0, int.from_bytes(self.elfhdr.e_shnum, byteorder="little", signed=False), ): if ( int.from_bytes(self.shhdr[i].sh_type, byteorder="little", signed=False) == sh_type_e.SHT_STRTAB ): self.so.seek( int.from_bytes( self.shhdr[i].sh_offset, byteorder="little", signed=False, ) + offset - 0, 0, ) byte = self.so.read(1) while chr(byte[0]) != "\0": if chr(byte[0]) != "\0": symbol.append(chr(byte[0])) byte = self.so.read(1) return symbol def dump_inst_sections(self): indices = [] for section in self.shhdr: if ( int.from_bytes(section.sh_flags, byteorder="little", signed=False) & sh_flags_e.SHF_EXECINSTR == sh_flags_e.SHF_EXECINSTR ): indices.append(int.from_bytes(section.sh_name, byteorder="little")) return indices def pop_data_section(self): for section in self.shhdr: name = self.read_section_name(byte2int(section.sh_name)) if name == ".data": self.so.seek(byte2int(section.sh_offset)) self.data_section = self.so.read(byte2int(section.sh_size)) def pop_text_section(self): for section in self.shhdr: name = self.read_section_name(byte2int(section.sh_name)) if name == ".text": self.so.seek(byte2int(section.sh_offset)) self.text_section = self.so.read(byte2int(section.sh_size)) def pop_dynamic_entries(self, section_name, struct_to_pop): for section in self.shhdr: name = self.read_section_name(byte2int(section.sh_name)) if name == section_name: self.so.seek(byte2int(section.sh_offset)) self.dyn_section = self.so.read(byte2int(section.sh_size)) length = int(len(self.dyn_section)) dummy = {} if self.size == 64: jmp_val = 8 elif self.size == 32: jmp_val = 4 else: jmp_val = 8 print("self.size is not set for class " "elf.going with 8 as a default.") for offset in range(0, length, jmp_val * 2): tag_type = byte2int(self.dyn_section[offset : offset + jmp_val]) dummy["tag"] = tag_type value = byte2int( self.dyn_section[offset + jmp_val : offset + (jmp_val * 2)] ) dummy["value"] = value type_string = get_ph_dynamic_ent_tag_type(tag_type) dummy["type_string"] = type_string type_string = str() struct_to_pop.append(dummy) dummy = {} def pop_rela(self, section_name, section_whole, to_pop): size = int() entsize = int() dummy = {} step = int() if self.size == 64: step = 8 if self.size == 32: step = 4 for section in self.shhdr: name = self.read_section_name(byte2int(section.sh_name)) if name == section_name: self.so.seek(byte2int(section.sh_offset)) section_whole = self.so.read(byte2int(section.sh_size)) size = byte2int(section.sh_size) entsize = byte2int(section.sh_entsize) if entsize != 0: for i in range(0, int(size / entsize)): dummy["r_offset"] = byte2int( section_whole[i * entsize : i * entsize + step] ) dummy["r_info"] = byte2int( section_whole[i * entsize + step : i * entsize + (step * 2)] ) dummy["r_addend"] = byte2int( section_whole[i * entsize + (step * 2) : i * entsize + (step * 3)], sign=True, ) to_pop.append(dummy) dummy = {} def pop_rel(self, section_name, section_whole, to_pop): size = int() entsize = int() dummy = {} step = int() if self.size == 64: step = 8 if self.size == 32: step = 4 for section in self.shhdr: name = self.read_section_name(byte2int(section.sh_name)) if name == section_name: self.so.seek(byte2int(section.sh_offset)) section_whole = self.so.read(byte2int(section.sh_size)) size = byte2int(section.sh_size) entsize = byte2int(section.sh_entsize) for i in range(0, int(size / entsize)): dummy["r_offset"] = byte2int( section_whole[i * entsize : i * entsize + step] ) dummy["r_info"] = byte2int( section_whole[i * entsize + step : i * entsize + (step * 2)] ) to_pop.append(dummy) dummy = {} # FIXME-ELF64 only def pop_got(self): for shhdr in self.shhdr: name = self.read_section_name(byte2int(shhdr.sh_name)) if name == ".got": self.so.seek(byte2int(shhdr.sh_offset)) self.got = self.so.read(byte2int(shhdr.sh_size)) self.so.seek(byte2int(shhdr.sh_offset)) for i in range(0, int(byte2int(shhdr.sh_size) / 8)): self.got_ents.append(byte2int(self.so.read(8))) # FIXME-ELF64 only def pop_got_plt(self): for shhdr in self.shhdr: name = self.read_section_name(byte2int(shhdr.sh_name)) if name == ".got.plt": self.so.seek(byte2int(shhdr.sh_offset)) self.got_plt = self.so.read(byte2int(shhdr.sh_size)) self.so.seek(byte2int(shhdr.sh_offset)) for i in range(0, int(byte2int(shhdr.sh_size) / 8)): self.got_plt_ents.append(byte2int(self.so.read(8))) def dump_got(self): header = ["value"] value_list = [entry for entry in self.got_ents] lines = ffs(2, header, True, value_list) for line in lines: print(line) def dump_got_plt(self): header = ["value"] value_list = [entry for entry in self.got_plt_ents] lines = ffs(2, header, True, value_list) for line in lines: print(line) class obj_loader: def __init__(self, bytes): self.memory = bytes() def load(self, obj): for byte in obj: self.memory.append(byte) def ch_so_to_exe(path): so = open(path, "r+b") so.seek(16) so.write(bytes([2])) print(Colors.purple + "changed so to exe" + Colors.ENDC) so.close def ch_exe_to_so(path): so = open(path, "r+b") so.seek(16) so.write(bytes([3])) print(Colors.purple + "changed exe to so" + Colors.ENDC) so.close def elf_init(): so = openSO_r(sys.argv[1]) elf = ELF(so) elf.init(64) def elf_get_func_names(): so = openSO_r(sys.argv[1]) elf = ELF(so) elf.init(64) return elf.dump_symbol_string(ELF_ST_TYPE.STT_FUNC, False) def elf_get_text_section(): so = openSO_r(sys.argv[1]) elf = ELF(so) elf.init(64) return elf.dump_section(".text", False) def elf_get_section(name): so = openSO_r(sys.argv[1]) elf = ELF(so) elf.init(64) return elf.dump_section(name, False) def elf_get_rodata_section(): so = openSO_r(sys.argv[1]) elf = ELF(so) elf.init(64) return elf.dump_section(".rodata", False) # obj here means variables or what the C standard means by objects def elf_get_obj_names(): so = openSO_r(sys.argv[1]) elf = ELF(so) elf.init(64) return elf.dump_symbol_string(ELF_ST_TYPE.STT_OBJECT, False) # obj here means variables or what the C standard means by objects def elf_get_obj_sizes(): so = openSO_r(sys.argv[1]) elf = ELF(so) elf.init(64) return elf.dump_obj_size(ELF_ST_TYPE.STT_OBJECT, False) def elf_get_func_code(): so = openSO_r(sys.argv[1]) elf = ELF(so) elf.init(64) return elf.dump_funcs(False) def elf_get_func_code_byname(): so = openSO_r(sys.argv[1]) arg = openSO_r(sys.argv[2]) elf = ELF(so) elf.init(64) counter = 0 # hit = False for name in elf.dump_symbol_string(ELF_ST_TYPE.STT_FUNC, False): if name == arg: code = elf.dump_funcs(False)[counter] # hit = True counter += 1 return code class Call_Rewriter(object): # def __init__(self, obj_code, arch, mode): def __init__(self, obj_code): self.obj_code = bytes(obj_code) self.md = Cs(CS_ARCH_X86, CS_MODE_64) # self.md = Cs(arch, mode) def dumpall(self): for i in self.md.disasm(self.obj_code, 0x1): print("0x%x:\t%s\t%s" % (i.address, i.mnemonic, i.op_str)) def run(self): for i in self.md.disasm(self.obj_code, 0x1): if i.mnemonic == "call": print("0x%x:\t%s\t%s" % (i.address, i.mnemonic, i.op_str)) print(i.bytes) class Global_Rewriter(object): def __init__(self): pass class Rewriter(object): def __init__(self, path, new_name): so = openSO_r(path) self.elf = ELF(so) self.elf.init(64) # shutil.copyfile(path, "/tmp/exe") self.magic_section_number = int() self.new_name = new_name self.shdr_new_size = [] self.shdr_new_offset = [] def fix_section_offsets(self, section_name, new_size: int, new_section: bytes): # file_w = open(self.new_name, "wb") # magic_number = int() for i in range(0, byte2int(self.elf.elfhdr.e_shnum)): name = self.elf.read_section_name(byte2int(self.elf.shhdr[i].sh_name)) if section_name == name: self.magic_section_number = i print(self.magic_section_number) # copy the sections before magic_number # write in the new section # fix section headers end = int() for i in range(0, byte2int(self.elf.elfhdr.e_shnum)): if i > self.magic_section_number: extra_chunk = end % byte2int(self.elf.shhdr[i].sh_addralign) missing_chunk = byte2int(self.elf.shhdr[i].sh_addralign) - extra_chunk assert missing_chunk > 0, "missing chunk is negative" self.shdr_new_size.append(byte2int(self.elf.shhdr[i].sh_size)) self.shdr_new_offset.append( end + missing_chunk % byte2int(self.elf.shhdr[i].sh_addralign) ) end = self.shdr_new_offset[-1] + self.shdr_new_size[-1] elif i < self.magic_section_number: self.shdr_new_size.append(byte2int(self.elf.shhdr[i].sh_size)) self.shdr_new_offset.append(byte2int(self.elf.shhdr[i].sh_offset)) elif i == self.magic_section_number: self.shdr_new_size.append(new_size) self.shdr_new_offset.append(byte2int(self.elf.shhdr[i].sh_offset)) end = byte2int(self.elf.shhdr[i].sh_offset) + new_size for size in self.shdr_new_size: print(repr(i) + " new size is " + repr(size)) for offset in self.shdr_new_offset: print(repr(i) + " new offset is " + repr(offset)) def main() -> None: argparser = CLIArgParser() so = openSO_r(argparser.args.obj) elf = ELF(so) elf.init(64) if argparser.args.header: elf.dump_header() elif argparser.args.symboltable: elf.dump_symbol_tb(".strtab", sh_type_e.SHT_STRTAB) elf.dump_symbol_tb(".dynstr", sh_type_e.SHT_STRTAB) elif argparser.args.phdrs: elf.dump_phdrs() elif argparser.args.shdrs: elf.dump_shdrs() elif argparser.args.symbolindex: elf.dump_symbol_idx() elif argparser.args.stentries: elf.dump_st_entries() elif argparser.args.objcode: elf.dump_funcs(True) elif argparser.args.funcs: elf.dump_symbol_string(ELF_ST_TYPE.STT_FUNC, True) elif argparser.args.objs: elf.dump_symbol_string(ELF_ST_TYPE.STT_OBJECT, True) elif argparser.args.dynsym: elf.dump_st_entries_dyn() elif argparser.args.dlpath: elf.dump_section(".interp", True) elif argparser.args.section: elf.dump_section(argparser.args.section, True) elif argparser.args.test2: rewriter = Rewriter(argparser.args.obj, "new_exe") new_text = bytes() rewriter.fix_section_offsets(".text", 1000, new_text) elif argparser.args.dumpfunc: counter = 0 for name in elf.dump_symbol_string(ELF_ST_TYPE.STT_FUNC, False): if name == argparser.args.dumpfunc: print(Colors.red + Colors.BOLD + name + Colors.ENDC) code = elf.dump_funcs(False)[counter] print(code) counter += 1 elif argparser.args.dumpfuncasm: counter = 0 hit = False for name in elf.dump_symbol_string(ELF_ST_TYPE.STT_FUNC, False): if name == argparser.args.dumpfuncasm: code = elf.dump_funcs(False)[counter] hit = True counter += 1 if hit: md = Cs(CS_ARCH_X86, CS_MODE_64) for i in md.disasm(bytes(code), 0x0): print(hex(i.address).ljust(7), i.mnemonic.ljust(7), i.op_str) elif argparser.args.phdynent: elf.dump_ph_dyn_entries() elif argparser.args.disass: for section in elf.shhdr: name = elf.read_section_name(byte2int(section.sh_name)) if name == argparser.args.disass: if byte2int(section.sh_flags) & 0x4 != 0x04: print( "section is not executable...but, " "since you asked, here you go..." ) elf.so.seek(byte2int(section.sh_offset)) code = elf.so.read(byte2int(section.sh_size)) md = Cs(CS_ARCH_X86, CS_MODE_64) for i in md.disasm(bytes(code), 0x0): print(hex(i.address).ljust(7), i.mnemonic.ljust(7), i.op_str) elif argparser.args.disassp is not None: index = argparser.args.disassp # section not executable message if byte2int(elf.phdr[index].p_flags) & 0x1 != 1: print("program header section is not " "executable but since you asked...") header_offset = elf.phdr[index].p_offset header_size = elf.phdr[index].p_filesz elf.so.seek(byte2int(header_offset)) code = elf.so.read(byte2int(header_size)) md = Cs(CS_ARCH_X86, CS_MODE_64) for i in md.disasm(bytes(code), 0x0): print(hex(i.address).ljust(7), i.mnemonic.ljust(7), i.op_str) elif argparser.args.textasm: md = Cs(CS_ARCH_X86, CS_MODE_64) for i in md.disasm(bytes(elf.text_section), 0x0): print(hex(i.address).ljust(7), i.mnemonic.ljust(7), i.op_str) elif argparser.args.dynsecents: elf.dump_dyn_sec_ents(elf.dyn_section_ents) elif argparser.args.reladyn: elf.dump_rela(elf.rela_dyn_ents) elif argparser.args.relaplt: elf.dump_rela(elf.rela_plt_ents) elif argparser.args.got: elf.pop_got() elf.dump_got() elif argparser.args.gotplt: elf.pop_got_plt() elf.dump_got_plt() elif argparser.args.listdso: os.environ["LD_TRACE_LOADED_OBJECTS"] = "1" os.environ["LD_WARN"] = "yes" os.environ["LD_BIND_NOW"] = "yes" # os.environ["LD_VERBOSE"] = "yes" # os.environ["LD_DEBUG"] = "all" rtldlist = [ "/usr/lib/ld-linux.so.2", "/usr/lib64/ld-linux-x86-64.so.2", "/usr/libx32/ld-linux-x32.so.2", ] for rtld in rtldlist: if os.path.exists(rtld): result = subprocess.run( [rtld, argparser.args.obj], capture_output=True, ) print(result.stdout.decode("utf-8")) break else: print("why even bother if you were not gonna type anythng decent in?") if __name__ == "__main__": main()