2016-12-30 83 views
1

我想授予对ELF二进制文件中所有内存页的完全权限(读,写,执行)。理想情况下,我希望能够对二进制文件或目标文件进行转换,就像可以用objcopy更改符号一样。我还没有找到一个好办法来做到这一点。我也可以使用一个解决方案,它涉及在启动时运行代码,在每个页面上调用mprotect,标记为PROT_READ | PROT_WRITE | PROT_EXEC。我简单地尝试了这一点,但是我还没有找到一个很好的方法来知道哪些页面被映射,因此哪些页面需要被编辑为mprotect使所有页面可读/可写/可执行

动态分配的页面不需要具有所有权限,只需要在程序启动时映射的页面。

+0

既然'ELF'文件格式与语言无关,为什么C++标签呢? –

+0

因为如果我最终不得不在每一页上调用'mprotect',我都会用C++来完成。 – IanPudney

回答

3

下面的脚本实现受聘于俄罗斯代码的回答:

  • 设置RELRO段的p_typePT_NULL
  • FlagsLOADPF_X|PF_W|PF_R

这取决于pyelftoolspython3,可与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)) 
1

我想授予一个ELF二进制完全权限(读,写和执行)所有的内存页。

请注意,某些安全策略(如selinux中的W^X)会阻止您的二进制文件运行。

理想情况下,我希望能够做到这一点的转变上的二进制文件,二进制文件或目标文件

运行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 

你想要做的又是什么改变FlagsLOAD段有PF_X|PF_W|PF_R。这些标志是Elf{32,64}_Phdr表的一部分,表的偏移量存储在Elf{32,64}_Ehdr(存储在每个ELF文件的开始处)的e_phoff中。

查看/usr/include/elf.h。解析这里涉及的固定大小的ELF结构并不复杂。

你是不可能找到任何标准的工具,它会为你做这个(因为这是这样做的一个不寻常的和不安全的事情),但一个程序更改标志是琐碎CPythonPerl写。

P.S.您可能还需要“删除”RELRO细分受众群,您可以将其p_type更改为PT_NULL

我还没有发现知道哪些页面被映射,因此该页面必须mprotected的好方法。

在Linux上,您可以解析/proc/self/maps以获取该信息。其他操作系统可能会提供不同的方式来实现相同的目标。