security-cw/ROPgadget/ropgadget/loaders/elf.py

351 lines
14 KiB
Python
Raw Normal View History

2020-11-25 15:38:46 +00:00
## -*- coding: utf-8 -*-
##
## Jonathan Salwan - 2014-05-12 - ROPgadget tool
##
## http://twitter.com/JonathanSalwan
## http://shell-storm.org/project/ROPgadget/
##
from capstone import *
from ctypes import *
from struct import unpack
class ELFFlags(object):
ELFCLASS32 = 0x01
ELFCLASS64 = 0x02
EI_CLASS = 0x04
EI_DATA = 0x05
ELFDATA2LSB = 0x01
ELFDATA2MSB = 0x02
EM_386 = 0x03
EM_X86_64 = 0x3e
EM_ARM = 0x28
EM_MIPS = 0x08
EM_SPARCv8p = 0x12
EM_PowerPC = 0x14
EM_ARM64 = 0xb7
class Elf32_Ehdr_LSB(LittleEndianStructure):
_fields_ = [
("e_ident", c_ubyte * 16),
("e_type", c_ushort),
("e_machine", c_ushort),
("e_version", c_uint),
("e_entry", c_uint),
("e_phoff", c_uint),
("e_shoff", c_uint),
("e_flags", c_uint),
("e_ehsize", c_ushort),
("e_phentsize", c_ushort),
("e_phnum", c_ushort),
("e_shentsize", c_ushort),
("e_shnum", c_ushort),
("e_shstrndx", c_ushort)
]
class Elf64_Ehdr_LSB(LittleEndianStructure):
_fields_ = [
("e_ident", c_ubyte * 16),
("e_type", c_ushort),
("e_machine", c_ushort),
("e_version", c_uint),
("e_entry", c_ulonglong),
("e_phoff", c_ulonglong),
("e_shoff", c_ulonglong),
("e_flags", c_uint),
("e_ehsize", c_ushort),
("e_phentsize", c_ushort),
("e_phnum", c_ushort),
("e_shentsize", c_ushort),
("e_shnum", c_ushort),
("e_shstrndx", c_ushort)
]
class Elf32_Phdr_LSB(LittleEndianStructure):
_fields_ = [
("p_type", c_uint),
("p_offset", c_uint),
("p_vaddr", c_uint),
("p_paddr", c_uint),
("p_filesz", c_uint),
("p_memsz", c_uint),
("p_flags", c_uint),
("p_align", c_uint)
]
class Elf64_Phdr_LSB(LittleEndianStructure):
_fields_ = [
("p_type", c_uint),
("p_flags", c_uint),
("p_offset", c_ulonglong),
("p_vaddr", c_ulonglong),
("p_paddr", c_ulonglong),
("p_filesz", c_ulonglong),
("p_memsz", c_ulonglong),
("p_align", c_ulonglong)
]
class Elf32_Shdr_LSB(LittleEndianStructure):
_fields_ = [
("sh_name", c_uint),
("sh_type", c_uint),
("sh_flags", c_uint),
("sh_addr", c_uint),
("sh_offset", c_uint),
("sh_size", c_uint),
("sh_link", c_uint),
("sh_info", c_uint),
("sh_addralign", c_uint),
("sh_entsize", c_uint)
]
class Elf64_Shdr_LSB(LittleEndianStructure):
_fields_ = [
("sh_name", c_uint),
("sh_type", c_uint),
("sh_flags", c_ulonglong),
("sh_addr", c_ulonglong),
("sh_offset", c_ulonglong),
("sh_size", c_ulonglong),
("sh_link", c_uint),
("sh_info", c_uint),
("sh_addralign", c_ulonglong),
("sh_entsize", c_ulonglong)
]
class Elf32_Ehdr_MSB(BigEndianStructure):
_fields_ = [
("e_ident", c_ubyte * 16),
("e_type", c_ushort),
("e_machine", c_ushort),
("e_version", c_uint),
("e_entry", c_uint),
("e_phoff", c_uint),
("e_shoff", c_uint),
("e_flags", c_uint),
("e_ehsize", c_ushort),
("e_phentsize", c_ushort),
("e_phnum", c_ushort),
("e_shentsize", c_ushort),
("e_shnum", c_ushort),
("e_shstrndx", c_ushort)
]
class Elf64_Ehdr_MSB(BigEndianStructure):
_fields_ = [
("e_ident", c_ubyte * 16),
("e_type", c_ushort),
("e_machine", c_ushort),
("e_version", c_uint),
("e_entry", c_ulonglong),
("e_phoff", c_ulonglong),
("e_shoff", c_ulonglong),
("e_flags", c_uint),
("e_ehsize", c_ushort),
("e_phentsize", c_ushort),
("e_phnum", c_ushort),
("e_shentsize", c_ushort),
("e_shnum", c_ushort),
("e_shstrndx", c_ushort)
]
class Elf32_Phdr_MSB(BigEndianStructure):
_fields_ = [
("p_type", c_uint),
("p_offset", c_uint),
("p_vaddr", c_uint),
("p_paddr", c_uint),
("p_filesz", c_uint),
("p_memsz", c_uint),
("p_flags", c_uint),
("p_align", c_uint)
]
class Elf64_Phdr_MSB(BigEndianStructure):
_fields_ = [
("p_type", c_uint),
("p_flags", c_uint),
("p_offset", c_ulonglong),
("p_vaddr", c_ulonglong),
("p_paddr", c_ulonglong),
("p_filesz", c_ulonglong),
("p_memsz", c_ulonglong),
("p_align", c_ulonglong)
]
class Elf32_Shdr_MSB(BigEndianStructure):
_fields_ = [
("sh_name", c_uint),
("sh_type", c_uint),
("sh_flags", c_uint),
("sh_addr", c_uint),
("sh_offset", c_uint),
("sh_size", c_uint),
("sh_link", c_uint),
("sh_info", c_uint),
("sh_addralign", c_uint),
("sh_entsize", c_uint)
]
class Elf64_Shdr_MSB(BigEndianStructure):
_fields_ = [
("sh_name", c_uint),
("sh_type", c_uint),
("sh_flags", c_ulonglong),
("sh_addr", c_ulonglong),
("sh_offset", c_ulonglong),
("sh_size", c_ulonglong),
("sh_link", c_uint),
("sh_info", c_uint),
("sh_addralign", c_ulonglong),
("sh_entsize", c_ulonglong)
]
""" This class parses the ELF """
class ELF(object):
def __init__(self, binary):
self.__binary = bytearray(binary)
self.__ElfHeader = None
self.__shdr_l = []
self.__phdr_l = []
self.__setHeaderElf()
self.__setShdr()
self.__setPhdr()
""" Parse ELF header """
def __setHeaderElf(self):
e_ident = self.__binary[:15]
ei_class = e_ident[ELFFlags.EI_CLASS]
ei_data = e_ident[ELFFlags.EI_DATA]
if ei_class != ELFFlags.ELFCLASS32 and ei_class != ELFFlags.ELFCLASS64:
print("[Error] ELF.__setHeaderElf() - Bad Arch size")
return None
if ei_data != ELFFlags.ELFDATA2LSB and ei_data != ELFFlags.ELFDATA2MSB:
print("[Error] ELF.__setHeaderElf() - Bad architecture endian")
return None
if ei_class == ELFFlags.ELFCLASS32:
if ei_data == ELFFlags.ELFDATA2LSB: self.__ElfHeader = Elf32_Ehdr_LSB.from_buffer_copy(self.__binary)
elif ei_data == ELFFlags.ELFDATA2MSB: self.__ElfHeader = Elf32_Ehdr_MSB.from_buffer_copy(self.__binary)
elif ei_class == ELFFlags.ELFCLASS64:
if ei_data == ELFFlags.ELFDATA2LSB: self.__ElfHeader = Elf64_Ehdr_LSB.from_buffer_copy(self.__binary)
elif ei_data == ELFFlags.ELFDATA2MSB: self.__ElfHeader = Elf64_Ehdr_MSB.from_buffer_copy(self.__binary)
self.getArch() # Check if architecture is supported
""" Parse Section header """
def __setShdr(self):
shdr_num = self.__ElfHeader.e_shnum
base = self.__binary[self.__ElfHeader.e_shoff:]
shdr_l = []
e_ident = self.__binary[:15]
ei_data = e_ident[ELFFlags.EI_DATA]
for i in range(shdr_num):
if self.getArchMode() == CS_MODE_32:
if ei_data == ELFFlags.ELFDATA2LSB: shdr = Elf32_Shdr_LSB.from_buffer_copy(base)
elif ei_data == ELFFlags.ELFDATA2MSB: shdr = Elf32_Shdr_MSB.from_buffer_copy(base)
elif self.getArchMode() == CS_MODE_64:
if ei_data == ELFFlags.ELFDATA2LSB: shdr = Elf64_Shdr_LSB.from_buffer_copy(base)
elif ei_data == ELFFlags.ELFDATA2MSB: shdr = Elf64_Shdr_MSB.from_buffer_copy(base)
self.__shdr_l.append(shdr)
base = base[self.__ElfHeader.e_shentsize:]
# setup name from the strings table
if self.__ElfHeader.e_shstrndx != 0:
string_table = bytes(self.__binary[(self.__shdr_l[self.__ElfHeader.e_shstrndx].sh_offset):])
for i in range(shdr_num):
self.__shdr_l[i].str_name = string_table[self.__shdr_l[i].sh_name:].split(b'\x00')[0].decode('utf8')
""" Parse Program header """
def __setPhdr(self):
pdhr_num = self.__ElfHeader.e_phnum
base = self.__binary[self.__ElfHeader.e_phoff:]
phdr_l = []
e_ident = self.__binary[:15]
ei_data = e_ident[ELFFlags.EI_DATA]
for i in range(pdhr_num):
if self.getArchMode() == CS_MODE_32:
if ei_data == ELFFlags.ELFDATA2LSB: phdr = Elf32_Phdr_LSB.from_buffer_copy(base)
elif ei_data == ELFFlags.ELFDATA2MSB: phdr = Elf32_Phdr_MSB.from_buffer_copy(base)
elif self.getArchMode() == CS_MODE_64:
if ei_data == ELFFlags.ELFDATA2LSB: phdr = Elf64_Phdr_LSB.from_buffer_copy(base)
elif ei_data == ELFFlags.ELFDATA2MSB: phdr = Elf64_Phdr_MSB.from_buffer_copy(base)
self.__phdr_l.append(phdr)
base = base[self.__ElfHeader.e_phentsize:]
def getEntryPoint(self):
return self.__e_entry
def getExecSections(self):
ret = []
for segment in self.__phdr_l:
if segment.p_flags & 0x1:
ret += [{
"offset" : segment.p_offset,
"size" : segment.p_memsz,
"vaddr" : segment.p_vaddr,
"opcodes" : bytes(self.__binary[segment.p_offset:segment.p_offset+segment.p_memsz])
}]
return ret
def getDataSections(self):
ret = []
for section in self.__shdr_l:
if not (section.sh_flags & 0x4) and (section.sh_flags & 0x2):
ret += [{
"name" : section.str_name,
"offset" : section.sh_offset,
"size" : section.sh_size,
"vaddr" : section.sh_addr,
"opcodes" : bytes(self.__binary[section.sh_offset:section.sh_offset+section.sh_size])
}]
return ret
def getArch(self):
if self.__ElfHeader.e_machine == ELFFlags.EM_386 or self.__ElfHeader.e_machine == ELFFlags.EM_X86_64:
return CS_ARCH_X86
elif self.__ElfHeader.e_machine == ELFFlags.EM_ARM:
return CS_ARCH_ARM
elif self.__ElfHeader.e_machine == ELFFlags.EM_ARM64:
return CS_ARCH_ARM64
elif self.__ElfHeader.e_machine == ELFFlags.EM_MIPS:
return CS_ARCH_MIPS
elif self.__ElfHeader.e_machine == ELFFlags.EM_PowerPC:
return CS_ARCH_PPC
elif self.__ElfHeader.e_machine == ELFFlags.EM_SPARCv8p:
return CS_ARCH_SPARC
else:
print("[Error] ELF.getArch() - Architecture not supported")
return None
def getArchMode(self):
if self.__ElfHeader.e_ident[ELFFlags.EI_CLASS] == ELFFlags.ELFCLASS32:
return CS_MODE_32
elif self.__ElfHeader.e_ident[ELFFlags.EI_CLASS] == ELFFlags.ELFCLASS64:
return CS_MODE_64
else:
print("[Error] ELF.getArchMode() - Bad Arch size")
return None
def getEndian(self):
if self.__ElfHeader.e_ident[ELFFlags.EI_DATA] == ELFFlags.ELFDATA2LSB:
return 0
if self.__ElfHeader.e_ident[ELFFlags.EI_DATA] == ELFFlags.ELFDATA2MSB:
return CS_MODE_BIG_ENDIAN
print("[Error] ELF.getEndian() - Bad Endianness")
return None
def getFormat(self):
return "ELF"