linux ELF phdr:将可执行文件的多个范围的内存页拼接在一起

fquxozlt  于 2023-05-16  发布在  Linux
关注(0)|答案(1)|浏览(142)

我正在修补(静态链接)ELF可执行文件。我想从二进制文件的多个不同部分在虚拟地址空间中创建页面。
下面是一个简单的可视化案例,说明我正在努力实现的目标。
|标记内存页边界):

file: |aabb|ccdd|
mem:  |aadd|

页面的前半部分来自文件的第一页面大小范围的前半部分,并且后半部分来自第二页面大小范围的后半部分,因此每个片段的对齐在其范围内是正确的。
有可能以任何方式实现这一点吗?
我修改了一个二进制文件,使其具有以下程序头表(打印为readelf -l

Elf file type is EXEC (Executable file)
Entry point 0x401520
There are 12 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000560000 0x0000000000400000 0x0000000000400000
                 0x0000000000000040 0x0000000000000040  R      0x1000
  LOAD           0x0000000000001270 0x0000000000400270 0x0000000000400270
                 0x00000000000002c8 0x00000000000002c8  R      0x1000
  LOAD           0x0000000000002000 0x0000000000401000 0x0000000000401000
                 0x0000000000075ac1 0x0000000000075ac1  R E    0x1000
  LOAD           0x0000000000078000 0x0000000000477000 0x0000000000477000
                 0x0000000000027053 0x0000000000027053  R      0x1000
  LOAD           0x000000000009f7d8 0x000000000049f7d8 0x000000000049f7d8
                 0x0000000000005ab8 0x000000000000b288  RW     0x1000
  LOAD           0x0000000000000000 0x00000000004ab000 0x00000000004ab000
                 0x00000000000002e0 0x00000000000002e0  R      0x1000
  NOTE           0x0000000000001270 0x0000000000400270 0x0000000000400270
                 0x0000000000000040 0x0000000000000040  R      0x8
  NOTE           0x00000000000012b0 0x00000000004002b0 0x00000000004002b0
                 0x0000000000000044 0x0000000000000044  R      0x4
  TLS            0x000000000009f7d8 0x000000000049f7d8 0x000000000049f7d8
                 0x0000000000000018 0x0000000000000060  R      0x8
  GNU_PROPERTY   0x0000000000001270 0x0000000000400270 0x0000000000400270
                 0x0000000000000040 0x0000000000000040  R      0x8
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x10
  GNU_RELRO      0x000000000009f7d8 0x000000000049f7d8 0x000000000049f7d8
                 0x0000000000003828 0x0000000000003828  R      0x1

正如你所看到的,我正在尝试从文件的两个单独的“页面”中拼凑出0x400000处的内存页面:第一个0x40字节来自偏移量为0x560000的“页”,其余的来自偏移量为0x1000的“页”。
当我在GDB中运行可执行文件时,info proc mappings有以下输出:

Start Addr           End Addr       Size     Offset  Perms  objfile
            0x400000           0x401000     0x1000     0x1000  r--p   <the executable>
            0x401000           0x477000    0x76000     0x2000  r-xp   <the executable>
            0x477000           0x49f000    0x28000    0x78000  r--p   <the executable>
            0x49f000           0x4a6000     0x7000    0x9f000  rw-p   <the executable>
            0x4a6000           0x4ab000     0x5000        0x0  rw-p   
            0x4ab000           0x4ac000     0x1000        0x0  r--p   <the executable>
      0x7ffff7ff9000     0x7ffff7ffd000     0x4000        0x0  r--p   [vvar]
      0x7ffff7ffd000     0x7ffff7fff000     0x2000        0x0  r-xp   [vdso]
      0x7ffffffde000     0x7ffffffff000    0x21000        0x0  rw-p   [stack]
  0xffffffffff600000 0xffffffffff601000     0x1000        0x0  --xp   [vsyscall]

好像我的第一个phdr条目没有效果。

jhkqcmku

jhkqcmku1#

我正试图从文件的两个单独的“页”中拼凑出位于0x400000的内存页
这是行不通的:内核将一次一个地“解释”和执行LOAD“指令”。给出:

LOAD           0x0000000000560000 0x0000000000400000 0x0000000000400000
                 0x0000000000000040 0x0000000000000040  R      0x1000
  LOAD           0x0000000000001270 0x0000000000400270 0x0000000000400270
                 0x00000000000002c8 0x00000000000002c8  R      0x1000

内核将做(等效于)

mmap(0x400000, 0x400, PROT_READ, MAP_FIXED, fd, 0x560000);
mmap(0x400000, 0x400, PROT_READ, MAP_FIXED, fd,   0x1000);

然后第二个mmap将替换第一个,这正是您在GDB中观察到的。

相关问题