使所有页面 readable/writable/executable
Make all pages readable/writable/executable
我想授予对 ELF 二进制文件中所有内存页的完全权限(读取、写入和执行)。理想情况下,我希望能够将此作为对二进制文件或目标文件的转换来执行,就像可以使用 objcopy
更改符号一样。我还没有找到一个好的方法来做到这一点。我也可以接受在启动时涉及 运行 代码的解决方案,该代码在每个页面上调用 mprotect
并带有标志 PROT_READ | PROT_WRITE | PROT_EXEC
。我已经简单地尝试过这个,但我还没有找到一个好方法来知道哪些页面被映射,因此哪些页面需要 mprotect
ed。
不需要动态分配的页面拥有所有权限,只需要在程序启动时映射的页面。
I would like to grant full permissions (read, write, and execute) to all memory pages in an ELF binary.
请注意,某些安全策略,例如 selinux 中的 W^X
会阻止您的二进制文件 运行。
Ideally, I'd like to be able to do this as a transformation on a binary or object file
运行 readelf -Wl
在你的二进制文件上。您会看到类似于:
$ readelf -Wl /bin/date
Elf file type is EXEC (Executable file)
Entry point 0x4021cf
There are 9 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000040 0x0000000000400040 0x0000000000400040 0x0001f8 0x0001f8 R E 0x8
INTERP 0x000238 0x0000000000400238 0x0000000000400238 0x00001c 0x00001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x00dde4 0x00dde4 R E 0x200000
LOAD 0x00de10 0x000000000060de10 0x000000000060de10 0x0004e4 0x0006b0 RW 0x200000
DYNAMIC 0x00de28 0x000000000060de28 0x000000000060de28 0x0001d0 0x0001d0 RW 0x8
NOTE 0x000254 0x0000000000400254 0x0000000000400254 0x000044 0x000044 R 0x4
GNU_EH_FRAME 0x00cb8c 0x000000000040cb8c 0x000000000040cb8c 0x0002f4 0x0002f4 R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
GNU_RELRO 0x00de10 0x000000000060de10 0x000000000060de10 0x0001f0 0x0001f0 R 0x1
然后您要做的是将 LOAD
段上的 Flags
更改为 PF_X|PF_W|PF_R
。标志是 Elf{32,64}_Phdr
table 的一部分,table 的偏移量存储在 Elf{32,64}_Ehdr
的 e_phoff
中(存储在每个 ELF 文件)。
查看/usr/include/elf.h
。解析这里涉及的固定大小的ELF结构并不复杂。
您不太可能找到任何可以为您执行此操作的标准工具(鉴于这是一件非常不寻常且不安全的事情),但是在 C
中编写更改标志的程序是微不足道的, Python
或 Perl
.
P.S。您可能还需要 "zap" RELRO
段,这可以通过将其 p_type
更改为 PT_NULL
.
来完成
I haven't found a good way to know which pages are mapped, and therefore which pages need to be mprotected
.
在 Linux 上,您可以解析 /proc/self/maps
以获取该信息。其他操作系统可能会提供不同的方法来实现相同的目的。
以下脚本在代码中实现了 Employed Russian 的回答:
- 将
RELRO
段的 p_type
设置为 PT_NULL
- 将
LOAD
段上的 Flags
设置为 PF_X|PF_W|PF_R
。
python3
依赖pyelftools
,可以用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))
我想授予对 ELF 二进制文件中所有内存页的完全权限(读取、写入和执行)。理想情况下,我希望能够将此作为对二进制文件或目标文件的转换来执行,就像可以使用 objcopy
更改符号一样。我还没有找到一个好的方法来做到这一点。我也可以接受在启动时涉及 运行 代码的解决方案,该代码在每个页面上调用 mprotect
并带有标志 PROT_READ | PROT_WRITE | PROT_EXEC
。我已经简单地尝试过这个,但我还没有找到一个好方法来知道哪些页面被映射,因此哪些页面需要 mprotect
ed。
不需要动态分配的页面拥有所有权限,只需要在程序启动时映射的页面。
I would like to grant full permissions (read, write, and execute) to all memory pages in an ELF binary.
请注意,某些安全策略,例如 selinux 中的 W^X
会阻止您的二进制文件 运行。
Ideally, I'd like to be able to do this as a transformation on a binary or object file
运行 readelf -Wl
在你的二进制文件上。您会看到类似于:
$ readelf -Wl /bin/date
Elf file type is EXEC (Executable file)
Entry point 0x4021cf
There are 9 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000040 0x0000000000400040 0x0000000000400040 0x0001f8 0x0001f8 R E 0x8
INTERP 0x000238 0x0000000000400238 0x0000000000400238 0x00001c 0x00001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x00dde4 0x00dde4 R E 0x200000
LOAD 0x00de10 0x000000000060de10 0x000000000060de10 0x0004e4 0x0006b0 RW 0x200000
DYNAMIC 0x00de28 0x000000000060de28 0x000000000060de28 0x0001d0 0x0001d0 RW 0x8
NOTE 0x000254 0x0000000000400254 0x0000000000400254 0x000044 0x000044 R 0x4
GNU_EH_FRAME 0x00cb8c 0x000000000040cb8c 0x000000000040cb8c 0x0002f4 0x0002f4 R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
GNU_RELRO 0x00de10 0x000000000060de10 0x000000000060de10 0x0001f0 0x0001f0 R 0x1
然后您要做的是将 LOAD
段上的 Flags
更改为 PF_X|PF_W|PF_R
。标志是 Elf{32,64}_Phdr
table 的一部分,table 的偏移量存储在 Elf{32,64}_Ehdr
的 e_phoff
中(存储在每个 ELF 文件)。
查看/usr/include/elf.h
。解析这里涉及的固定大小的ELF结构并不复杂。
您不太可能找到任何可以为您执行此操作的标准工具(鉴于这是一件非常不寻常且不安全的事情),但是在 C
中编写更改标志的程序是微不足道的, Python
或 Perl
.
P.S。您可能还需要 "zap" RELRO
段,这可以通过将其 p_type
更改为 PT_NULL
.
I haven't found a good way to know which pages are mapped, and therefore which pages need to be
mprotected
.
在 Linux 上,您可以解析 /proc/self/maps
以获取该信息。其他操作系统可能会提供不同的方法来实现相同的目的。
以下脚本在代码中实现了 Employed Russian 的回答:
- 将
RELRO
段的p_type
设置为PT_NULL
- 将
LOAD
段上的Flags
设置为PF_X|PF_W|PF_R
。
python3
依赖pyelftools
,可以用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))