Created
October 10, 2023 17:35
-
-
Save fzakaria/62d776353b54d6175f4e35e40404d4b9 to your computer and use it in GitHub Desktop.
ELF Loader in python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ctypes | |
import mmap | |
import struct | |
# Simplified ELF Header Structure | |
class Elf32_Ehdr(ctypes.Structure): | |
_fields_ = [ | |
("e_ident", ctypes.c_char * 16), | |
("e_type", ctypes.c_uint16), | |
("e_machine", ctypes.c_uint16), | |
("e_version", ctypes.c_uint32), | |
("e_entry", ctypes.c_uint32), | |
("e_phoff", ctypes.c_uint32), | |
("e_shoff", ctypes.c_uint32), | |
("e_flags", ctypes.c_uint32), | |
("e_ehsize", ctypes.c_uint16), | |
("e_phentsize", ctypes.c_uint16), | |
("e_phnum", ctypes.c_uint16), | |
("e_shentsize", ctypes.c_uint16), | |
("e_shnum", ctypes.c_uint16), | |
("e_shstrndx", ctypes.c_uint16), | |
] | |
# Simplified Program Header Structure | |
class Elf32_Phdr(ctypes.Structure): | |
_fields_ = [ | |
("p_type", ctypes.c_uint32), | |
("p_offset", ctypes.c_uint32), | |
("p_vaddr", ctypes.c_uint32), | |
("p_paddr", ctypes.c_uint32), | |
("p_filesz", ctypes.c_uint32), | |
("p_memsz", ctypes.c_uint32), | |
("p_flags", ctypes.c_uint32), | |
("p_align", ctypes.c_uint32), | |
] | |
# Load ELF binary into memory and execute its main function | |
def load_and_execute_elf(file_path): | |
with open(file_path, "rb") as f: | |
# Map the file into memory | |
mmapped_file = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) | |
# Read the ELF header | |
elf_header = Elf32_Ehdr.from_buffer(mmapped_file) | |
# Validate the ELF magic number | |
if elf_header.e_ident[:4] != b'\x7fELF': | |
raise ValueError("Not a valid ELF file") | |
# Find the program header table | |
phoff = elf_header.e_phoff | |
phentsize = elf_header.e_phentsize | |
phnum = elf_header.e_phnum | |
# Iterate through program header entries | |
for i in range(phnum): | |
# Read the program header entry | |
phdr_data = mmapped_file[phoff + i * phentsize : phoff + (i + 1) * phentsize] | |
phdr = Elf32_Phdr.from_buffer_copy(phdr_data) | |
# Check if the segment is loadable | |
if phdr.p_type == 1: # PT_LOAD | |
# Map the segment into memory | |
segment = mmap.mmap(-1, phdr.p_memsz, prot=mmap.PROT_READ | mmap.PROT_WRITE | mmap.PROT_EXEC) | |
segment.write(mmapped_file[phdr.p_offset : phdr.p_offset + phdr.p_filesz]) | |
# Assume the entry point is in this segment | |
if elf_header.e_entry >= phdr.p_vaddr and elf_header.e_entry < phdr.p_vaddr + phdr.p_memsz: | |
entry_offset = elf_header.e_entry - phdr.p_vaddr | |
# Define a ctypes function type for the entry point | |
FUNCTYPE = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_char_p)) | |
# Create a ctypes function pointer | |
entry_func = FUNCTYPE(segment[entry_offset:].tobytes()) | |
# Call the entry function | |
args = (ctypes.c_int(1), ctypes.POINTER(ctypes.c_char_p)(ctypes.c_char_p(b'example'))) | |
result = entry_func(*args) | |
print("Program returned:", result) | |
break | |
# Example usage | |
# load_and_execute_elf("path_to_your_elf_file") |
Author
fzakaria
commented
Oct 10, 2023
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment