【小镇的技术天梯】mprotect: 设置内存访问权限
2016-02-24 15:56
337 查看
【小镇直接转载,如果大家看过前几篇文章的话,这篇文章是毫无难度的,但也算是个知识点吧】
mmap 的第三个参数指定对内存区域的保护,由标记读、写、执行权限的 PROT_READ、PROT_WRITE 和 PROT_EXEC 按位与操作获得,或者是限制没有访问权限的 PROT_NONE。如果程序尝试在不允许这些权限的本地内存上操作,它将被 SIGSEGV 信号(Segmentation
fault,段错误)终止。
在内存映射完成后,这些权限仍可以被 mprotect 系统调用所修改。mprotect 的参数分别为内存区间的地址,区间的大小,新的保护标志设置。所指定的内存区间必须包含整个页:区间地址必须和整个系统页大小对齐,而区间长度必须是页大小的整数倍。这些页的保护标记被这里指定的新保护模式替换。
mmap通过映射
/dev/zero 来分配内存页。内存将被初始化为可读和可写模式。
然后,您的程序可以使用 mprotect 把它变成只读:
代码使用mprotect检测内存访问
上述程序按照如下步骤执行:
程序为 SIGSEGV 建立一个信号处理句柄。
程序通过映射 /dev/zero 分配一个内存分页,然后通过写入数据的方式获得一个私有复本。
程序通过调用带 PROT_NONE 权限的 mprotect 保护了内存。
当程序在后续执行中写入内存时,Linux 向进程发送 SIGSEGV,这个信号被 segv_handler 句柄接收处理。这个句柄将解除内存保护,因而程序内存访问得以继续。
当信号句柄执行完成时,程序控制权返回 main 函数,程序将使用 munmap 来释放内存。
mmap 的第三个参数指定对内存区域的保护,由标记读、写、执行权限的 PROT_READ、PROT_WRITE 和 PROT_EXEC 按位与操作获得,或者是限制没有访问权限的 PROT_NONE。如果程序尝试在不允许这些权限的本地内存上操作,它将被 SIGSEGV 信号(Segmentation
fault,段错误)终止。
在内存映射完成后,这些权限仍可以被 mprotect 系统调用所修改。mprotect 的参数分别为内存区间的地址,区间的大小,新的保护标志设置。所指定的内存区间必须包含整个页:区间地址必须和整个系统页大小对齐,而区间长度必须是页大小的整数倍。这些页的保护标记被这里指定的新保护模式替换。
mmap通过映射
/dev/zero 来分配内存页。内存将被初始化为可读和可写模式。
int fd = open (“/dev/zero”, O_RDONLY); char* memory = mmap (NULL, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); close (fd);
然后,您的程序可以使用 mprotect 把它变成只读:
mprotect (memory, page_size, PROT_READ);有一种监控内存访问的高级技巧,可以通过利用 mmap 和 mprotect 保护目标内存区间,然后当程序访问时候接收并处理 Linux 系统发送的 SIGSEGV 信号。代码 展示了这个技巧。
代码使用mprotect检测内存访问
#include <fcntl.h> #include <signal.h> #include <stdio.h> #include <string.h> #include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> static int alloc_size; static char* memory; void segv_handler (int signal_number) { printf (“memory accessed!\n”); mprotect (memory, alloc_size, PROT_READ | PROT_WRITE); } int main () { int fd; struct sigaction sa; /* 初始化segv_handler为SIGSEGV的句柄。*/ memset (&sa, 0, sizeof (sa)); sa.sa_handler = &segv_handler; sigaction (SIGSEGV, &sa, NULL); /* 使用映射/dev/zero分配内存页。最初映射的内存为只写。*/ alloc_size = getpagesize (); fd = open (“/dev/zero”, O_RDONLY); memory = mmap (NULL, alloc_size, PROT_WRITE, MAP_PRIVATE, fd, 0); close (fd); /* 写页来获得一个私有复制。 */ memory[0] = 0; /* 使内存为不可写。 */ mprotect (memory, alloc_size, PROT_NONE); /* 写分配内存区域。 */ memory[0] = 1; /* 所有工作都结束;unmap内存映射。 */ printf (“all done\n”); munmap (memory, alloc_size); return 0; }
上述程序按照如下步骤执行:
程序为 SIGSEGV 建立一个信号处理句柄。
程序通过映射 /dev/zero 分配一个内存分页,然后通过写入数据的方式获得一个私有复本。
程序通过调用带 PROT_NONE 权限的 mprotect 保护了内存。
当程序在后续执行中写入内存时,Linux 向进程发送 SIGSEGV,这个信号被 segv_handler 句柄接收处理。这个句柄将解除内存保护,因而程序内存访问得以继续。
当信号句柄执行完成时,程序控制权返回 main 函数,程序将使用 munmap 来释放内存。
相关文章推荐
- 使用jquery的datatables总结
- HashMap和HashTable
- protobuf-lua-gen 中使用 bytes
- ubuntu使用salt部署nginx
- 任务调度Quartz初探Demo(三)
- 创建Material样式卡片风格注意事项
- APP是什么? 为什么叫APP APP全称是什么
- Vert.x 3学习笔记---09
- Android 欢迎引导页的魅力
- TCP/IP协议详解:卷一----笔记(1)概述
- Android 快速开发框架:推荐10个框架
- C#创建唯一的订单号, 考虑时间因素
- memcached的缺点
- 1143 多少个Fibonacci数
- Windows下编译最新volley jar包
- python beautifulsoup简单用法
- iOS Implicit declaration of function XXX is invalid in C99”
- matlab的parcorr函数
- 《二月英语激情飞扬》
- CREATE TABLE 表名 AS SELECT 语句