2

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

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

4

2 回答 2

4

以下脚本在代码中实现了 Employed Russian 的答案:

  • p_type段的设置RELROPT_NULL
  • 将分段设置Flags为。LOADPF_X|PF_W|PF_R

它取决于pyelftoolsfor python3,它可以与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)) 
于 2017-08-09T04:03:36.153 回答
3

我想授予 ELF 二进制文件中所有内存页的完全权限(读取、写入和执行)。

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

理想情况下,我希望能够将其作为二进制文件或目标文件的转换

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

你想要做的就是改变FlagsLOADPF_X|PF_W|PF_R。标志是表的一部分,Elf{32,64}_Phdr表的偏移量存储在e_phoff其中Elf{32,64}_Ehdr(存储在每个 ELF 文件的开头)。

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

您不太可能找到可以为您执行此操作的任何标准工具(鉴于这是一件不寻常且不安全的事情),但是更改标志的程序很容易写入C,PythonPerl.

PS您可能还需要“删除”该RELRO段,这可以通过将其更改p_typePT_NULL.

我还没有找到一个很好的方法来知道哪些页面被映射,因此哪些页面需要被映射 mprotected

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

于 2016-12-31T01:37:51.457 回答