英文:
ELF phdr: Piecing together memory pages from multiple ranges of an executable
问题
I am patching (statically linked) ELF executables.
我正在修补(静态链接的)ELF可执行文件。
I would like to create pages in virtual address space from multiple different parts of the binary.
我想从二进制文件的多个不同部分在虚拟地址空间中创建页面。
Here is a visualization of a simple case of what I am trying to achieve.
这是我试图实现的一个简单情况的可视化示例。
(|
marks memory page boundaries):
(|
表示内存页面边界):
file: |aabb|ccdd|
mem: |aadd|
The first half of the page is from the first half of the first page sized range of the file, and the second half is from the second half of the second page sized range, so the alignment of each piece is correct within its range.
页面的前半部分来自文件的第一个页面大小范围的前半部分,而后半部分来自第二个页面大小范围的后半部分,因此每个部分在其范围内的对齐都是正确的。
Is it possible to achieve this any way?
有没有可能以任何方式实现这一点?
I modified a binary to have the following program header table (printed with readelf -l
)
我修改了一个二进制文件,使其具有以下程序头表(使用 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
As you can see I am trying to piece together the memory page at 0x400000
from two separate "pages" of the file: the first 0x40
bytes from the "page" at offset 0x560000
and the rest from the one at offset 0x1000
.
正如您所看到的,我正在尝试从文件的两个单独的“页面”中组合在0x400000
处的内存页面:第一个“页面”来自偏移0x560000
处的前0x40
字节,其余来自偏移0x1000
处的页面。
When I run the executable in GDB, info proc mappings
has the following output:
当我在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 0
<details>
<summary>英文:</summary>
I am patching (statically linked) ELF executables.
I would like to create pages in virtual address space from multiple different parts of the binary.
Here is a visualization of a simple case of what I am trying to achieve.
(`|` marks memory page boundaries):
file: |aabb|ccdd|
mem: |aadd|
The first half of the page is from the first half of the first page sized range of the file, and the second half is from the second half of the second page sized range, so the alignment of each piece is correct within its range.
Is it possible to achieve this any way?
I modified a binary to have the following program header table (printed with `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
As you can see I am trying to piece together the memory page at `0x400000` from two separate "pages" of the file: the first `0x40` bytes from the "page" at offset `0x560000` and the rest from the one at offset `0x1000`.
When I run the executable in GDB, `info proc mappings` has the following output:
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]
It seems like my first phdr entry has no effect.
</details>
# 答案1
**得分**: 0
```plaintext
我正在尝试将内存页从0x400000的两个单独的“页面”拼接在一起
这样是行不通的:内核将逐个解释和执行“LOAD”指令。给定:
```plaintext
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中观察到的。
<details>
<summary>英文:</summary>
> I am trying to piece together the memory page at 0x400000 from two separate "pages" of the file
That's not going to work: the kernel will "interpret" and execute the `LOAD` "instructions" one at a time. Given:
LOAD 0x0000000000560000 0x0000000000400000 0x0000000000400000
0x0000000000000040 0x0000000000000040 R 0x1000
LOAD 0x0000000000001270 0x0000000000400270 0x0000000000400270
0x00000000000002c8 0x00000000000002c8 R 0x1000
the kernel will do (equivalent of)
mmap(0x400000, 0x400, PROT_READ, MAP_FIXED, fd, 0x560000);
mmap(0x400000, 0x400, PROT_READ, MAP_FIXED, fd, 0x1000);
The second `mmap` will then replace the first one, which is exactly what you observed in GDB.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论