通过 procfs 中的 mem 文件修改进程内存

前些天打钓鱼城杯时遇到一道叫做 fsplayground 的题目,了解到了 /proc/self/mem。赛后做了个小小的测试,稍微记录一下。

关于 mem 及 maps

/proc/[pid]/mem 是当前进程所占用的内存空间,由open、read 和 lseek 等系统调用使用,不能被用户读取。但可通过 /proc/[pid]/maps 查看。

/proc/[pid]/maps 用于显示进程的内存区域映射信息(和在 gef 中使用 vmmap 命令一样)。

关于 lseek 函数

与 fseek 函数类似,不过它可以操纵 mem 的文件读写指针。

通过 /proc/self/mem 修改栈上的变量

打开 /proc/self/mem,利用 lseek 函数将读写指针的位置移至变量 a 处,再使用 write 函数修改变量 a 的值,最后输出变量 a。测试代码如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main() {
    int fd;
    int a = 0;
    char b[] = "\x9\x0\x0\x0\x0\x0\x0\x0";
    fd = open("/proc/self/mem", O_RDWR);
    printf("%p\n", &a);
    lseek(fd, (long) &a, SEEK_SET);
    write(fd, b, 8);
    printf("%d\n", a);
    return 0;
}

对应输出如下:

image-20200906180725381

可见变量 a 的值确实被更改了。另外,似乎即使在声明变量 a 时使用了 const,变量 a 的值仍可被修改。

参考资料

2019-2020 @lukbash