mmap
映射的内存通过 fork
保留,但会被 exec
系列系统调用擦除。因此,经典的顺序 fork
,设置一些东西然后 exec
是无法实现这个功能的。
一个简单的解决方案是使用 LD_PRELOAD
钩子。让我们把这段代码放在 add_mmap.c
中。
#include <sys/mman.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void add_mmap(void) __attribute__((constructor));
void add_mmap(void)
{
int fd;
void *addr;
printf("calling mmap() before main...\n");
fd = open("/etc/passwd", O_RDONLY);
printf("fd=%d\n", fd);
addr = mmap(0, 100, PROT_READ, MAP_SHARED, fd, 0);
printf("addr=%llx\n", (long long unsigned)addr);
}
然后,将其构建为动态库:
gcc -Wall -g -fPIC -shared -o add_mmap.so add_mmap.c
最后,使用它来运行一些现有的程序:
$ LD_PRELOAD=./add_mmap.so /bin/cat
calling mmap() before main...
fd=3
addr=7fe4916f8000
我们可以检查在运行cat
之前是否设置和保留了映射:
$ cat /proc/27967/maps
...
7f2f7f2d0000-7f2f7f2d1000 r--s 00000000 09:00 1056387 /etc/passwd
...
编辑
我这里只展示了如何在程序启动前添加内存映射,但是我的示例可以轻松扩展到在程序内部透明地注入一个“内存管理器”线程。该线程将通过 IPC 机制(如套接字)接收命令并相应地操作映射。
ptrace
暂停目标程序,修改接下来的几条指令以包含所需的mmap
调用,然后恢复它。完成mmap
处理后,您会取消修补目标并还原指令指针。这很邪恶,但它能够奏效(此页面介绍了类似技术的详细信息)。 - nneonneogdb
吗? - glglgl