I would like to grant full permissions (read, write, and execute) to all memory pages in an ELF binary. Ideally, I'd like to be able to do this as a transformation on a binary or object file, in the same way that symbols can be changed with objcopy
. I have not yet found a good way to do this. I would also be okay with a solution that involves running code at startup that calls mprotect
on every page with the flags PROT_READ | PROT_WRITE | PROT_EXEC
. I've tried this briefly, but I haven't found a good way to know which pages are mapped, and therefore which pages need to be mprotect
ed.
It isn't required that dynamically allocated pages have all permissions, only the pages mapped at program startup.
The following script implements Employed Russian's answer in code:
p_type
of the RELRO
segment to PT_NULL
Flags
on LOAD
segments to PF_X|PF_W|PF_R
.It depends on pyelftools
for python3
, which can be installed with pip3 install pyelftools
.
#!/usr/bin/env python3
import sys
from elftools.elf.elffile import ELFFile
from elftools.elf.descriptions import describe_p_type
if len(sys.argv) != 2:
print("Usage: elf_rwe <elf>")
name = sys.argv[1]
with open(name, "rb") as f:
elf = ELFFile(f)
rwe_offsets = []
relro_offsets = []
for i in range(elf['e_phnum']):
program_offset = elf['e_phoff'] + i * elf['e_phentsize']
f.seek(program_offset)
program_header = elf.structs.Elf_Phdr.parse_stream(f)
if program_header['p_type'] == "PT_LOAD":
rwe_offsets.append(program_offset)
if program_header['p_type'] == "PT_GNU_RELRO":
relro_offsets.append(program_offset)
f.seek(0)
b = list(f.read())
# Zap RELRO
pt_null = 0
for off in relro_offsets:
b[off] = pt_null
# Fix permissions
p_flags_offset = 4
for off in rwe_offsets:
b[off + p_flags_offset] = 0x7 # PF_X|PF_W|PF_R
with open(name, "wb") as f:
f.write(bytes(b))