以编程方式访问核心文件内存映像
Access core file memory image programmatically
从相应的 ELF 核心转储文件访问进程内存映像的(正确)方法是什么?在某种程度上,我将能够检查特定地址,比如 0x12345678。
请记住,不能使用 gdb
,只能使用纯 C 方法。不鼓励使用库,libelf
除外。
What is the (correct) way to access the memory image of a process from the corresponding ELF core dump file?
这并不完全是微不足道的。此外,具体地址可能甚至不在 core
开头。
让我们考虑一个例子:
// t.c
#include <stdio.h>
#include <stdlib.h>
int main() {
int i = 42;
printf("&i = %p\n", &i);
abort();
}
编译它:
gcc -g t.c && ulimit -c unlimited && ./a.out
&i = 0x7fffdfb20e1c
Aborted (core dumped)
我们来看核心:
readelf -l core.19477
Elf file type is CORE (Core file)
Entry point 0x0
There are 18 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
NOTE 0x0000000000000430 0x0000000000000000 0x0000000000000000
0x000000000000084c 0x0000000000000000 0
LOAD 0x0000000000001000 0x0000000000400000 0x0000000000000000
0x0000000000001000 0x0000000000001000 R E 1000
LOAD 0x0000000000002000 0x0000000000600000 0x0000000000000000
0x0000000000001000 0x0000000000001000 R 1000
LOAD 0x0000000000003000 0x0000000000601000 0x0000000000000000
0x0000000000001000 0x0000000000001000 RW 1000
LOAD 0x0000000000004000 0x00007f85c6abf000 0x0000000000000000
0x0000000000001000 0x00000000001bb000 R E 1000
LOAD 0x0000000000005000 0x00007f85c6c7a000 0x0000000000000000
0x0000000000000000 0x00000000001ff000 1000
LOAD 0x0000000000005000 0x00007f85c6e79000 0x0000000000000000
0x0000000000004000 0x0000000000004000 R 1000
LOAD 0x0000000000009000 0x00007f85c6e7d000 0x0000000000000000
0x0000000000002000 0x0000000000002000 RW 1000
LOAD 0x000000000000b000 0x00007f85c6e7f000 0x0000000000000000
0x0000000000005000 0x0000000000005000 RW 1000
LOAD 0x0000000000010000 0x00007f85c6e84000 0x0000000000000000
0x0000000000001000 0x0000000000023000 R E 1000
LOAD 0x0000000000011000 0x00007f85c7084000 0x0000000000000000
0x0000000000003000 0x0000000000003000 RW 1000
LOAD 0x0000000000014000 0x00007f85c70a3000 0x0000000000000000
0x0000000000003000 0x0000000000003000 RW 1000
LOAD 0x0000000000017000 0x00007f85c70a6000 0x0000000000000000
0x0000000000001000 0x0000000000001000 R 1000
LOAD 0x0000000000018000 0x00007f85c70a7000 0x0000000000000000
0x0000000000001000 0x0000000000001000 RW 1000
LOAD 0x0000000000019000 0x00007f85c70a8000 0x0000000000000000
0x0000000000001000 0x0000000000001000 RW 1000
LOAD 0x000000000001a000 0x00007fffdfb00000 0x0000000000000000
0x0000000000022000 0x0000000000022000 RW 1000
LOAD 0x000000000003c000 0x00007fffdfbfc000 0x0000000000000000
0x0000000000002000 0x0000000000002000 R E 1000
LOAD 0x000000000003e000 0xffffffffff600000 0x0000000000000000
0x0000000000001000 0x0000000000001000 R E 1000
如您所见,核心包含一个 NOTE
段,然后是几个 LOAD
段。
NOTE
段包含几个 Elf64_Note
s,描述崩溃时的寄存器,以及其他内容。它本身很有趣(使用 readelf -n
来检查它),但与您在此处的具体问题无关。
其中一个LOAD
段"covers"我们感兴趣的地址:0x7fffdfb20e1c
,这个:
LOAD 0x000000000001a000 0x00007fffdfb00000 0x0000000000000000
0x0000000000022000 0x0000000000022000 RW 1000
请注意它是可写的(正如人们所期望的那样),并且
0x7fffdfb00000 < 0x7fffdfb20e1c < 0x7fffdfb22000 (0x7fffdfb00000+0x22000)
所以 &i
位于 LOAD
段的内部,偏移量
0x7fffdfb20e1c - 0x7fffdfb00000 == 0x20e1c
段本身位于文件偏移量 0x1a000
,这告诉我们我们寻找的值在文件偏移量0x1a000 + 0x20e1c == 0x3ae1c
.
确实,我们在核心的那个偏移处找到了值 42:
hexdump -s 0x3ae1c -n 4 -e '4/1 "%02X "' core.19477
2A 00 00 00
那么如何以编程方式做到这一点?
非常简单:从 core
的开头阅读 Elf64_Ehdr
。这将告诉您 Elf64_Phdr
的偏移量和数量。遍历它们,直到找到 "covers" 您的地址。现在计算文件偏移量(正如我上面所做的),lseek(2)
和 read(2)
你的数据。
从相应的 ELF 核心转储文件访问进程内存映像的(正确)方法是什么?在某种程度上,我将能够检查特定地址,比如 0x12345678。
请记住,不能使用 gdb
,只能使用纯 C 方法。不鼓励使用库,libelf
除外。
What is the (correct) way to access the memory image of a process from the corresponding ELF core dump file?
这并不完全是微不足道的。此外,具体地址可能甚至不在 core
开头。
让我们考虑一个例子:
// t.c
#include <stdio.h>
#include <stdlib.h>
int main() {
int i = 42;
printf("&i = %p\n", &i);
abort();
}
编译它:
gcc -g t.c && ulimit -c unlimited && ./a.out
&i = 0x7fffdfb20e1c
Aborted (core dumped)
我们来看核心:
readelf -l core.19477
Elf file type is CORE (Core file)
Entry point 0x0
There are 18 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
NOTE 0x0000000000000430 0x0000000000000000 0x0000000000000000
0x000000000000084c 0x0000000000000000 0
LOAD 0x0000000000001000 0x0000000000400000 0x0000000000000000
0x0000000000001000 0x0000000000001000 R E 1000
LOAD 0x0000000000002000 0x0000000000600000 0x0000000000000000
0x0000000000001000 0x0000000000001000 R 1000
LOAD 0x0000000000003000 0x0000000000601000 0x0000000000000000
0x0000000000001000 0x0000000000001000 RW 1000
LOAD 0x0000000000004000 0x00007f85c6abf000 0x0000000000000000
0x0000000000001000 0x00000000001bb000 R E 1000
LOAD 0x0000000000005000 0x00007f85c6c7a000 0x0000000000000000
0x0000000000000000 0x00000000001ff000 1000
LOAD 0x0000000000005000 0x00007f85c6e79000 0x0000000000000000
0x0000000000004000 0x0000000000004000 R 1000
LOAD 0x0000000000009000 0x00007f85c6e7d000 0x0000000000000000
0x0000000000002000 0x0000000000002000 RW 1000
LOAD 0x000000000000b000 0x00007f85c6e7f000 0x0000000000000000
0x0000000000005000 0x0000000000005000 RW 1000
LOAD 0x0000000000010000 0x00007f85c6e84000 0x0000000000000000
0x0000000000001000 0x0000000000023000 R E 1000
LOAD 0x0000000000011000 0x00007f85c7084000 0x0000000000000000
0x0000000000003000 0x0000000000003000 RW 1000
LOAD 0x0000000000014000 0x00007f85c70a3000 0x0000000000000000
0x0000000000003000 0x0000000000003000 RW 1000
LOAD 0x0000000000017000 0x00007f85c70a6000 0x0000000000000000
0x0000000000001000 0x0000000000001000 R 1000
LOAD 0x0000000000018000 0x00007f85c70a7000 0x0000000000000000
0x0000000000001000 0x0000000000001000 RW 1000
LOAD 0x0000000000019000 0x00007f85c70a8000 0x0000000000000000
0x0000000000001000 0x0000000000001000 RW 1000
LOAD 0x000000000001a000 0x00007fffdfb00000 0x0000000000000000
0x0000000000022000 0x0000000000022000 RW 1000
LOAD 0x000000000003c000 0x00007fffdfbfc000 0x0000000000000000
0x0000000000002000 0x0000000000002000 R E 1000
LOAD 0x000000000003e000 0xffffffffff600000 0x0000000000000000
0x0000000000001000 0x0000000000001000 R E 1000
如您所见,核心包含一个 NOTE
段,然后是几个 LOAD
段。
NOTE
段包含几个 Elf64_Note
s,描述崩溃时的寄存器,以及其他内容。它本身很有趣(使用 readelf -n
来检查它),但与您在此处的具体问题无关。
其中一个LOAD
段"covers"我们感兴趣的地址:0x7fffdfb20e1c
,这个:
LOAD 0x000000000001a000 0x00007fffdfb00000 0x0000000000000000
0x0000000000022000 0x0000000000022000 RW 1000
请注意它是可写的(正如人们所期望的那样),并且
0x7fffdfb00000 < 0x7fffdfb20e1c < 0x7fffdfb22000 (0x7fffdfb00000+0x22000)
所以 &i
位于 LOAD
段的内部,偏移量
0x7fffdfb20e1c - 0x7fffdfb00000 == 0x20e1c
段本身位于文件偏移量 0x1a000
,这告诉我们我们寻找的值在文件偏移量0x1a000 + 0x20e1c == 0x3ae1c
.
确实,我们在核心的那个偏移处找到了值 42:
hexdump -s 0x3ae1c -n 4 -e '4/1 "%02X "' core.19477
2A 00 00 00
那么如何以编程方式做到这一点?
非常简单:从 core
的开头阅读 Elf64_Ehdr
。这将告诉您 Elf64_Phdr
的偏移量和数量。遍历它们,直到找到 "covers" 您的地址。现在计算文件偏移量(正如我上面所做的),lseek(2)
和 read(2)
你的数据。