x86平台下只允许访问起始的1MB内存
# dd if=/dev/mem of=/dev/null
dd: error reading '/dev/mem': Operation not permitted
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.187975 s, 5.6 MB/s
workaround it by follows:
(1) Rebuild your kernel without the CONFIG_STRICT_DEVMEM restriction.
(2) Port the Fedora /dev/crash driver (./drivers/char/crash.c) to your kernel.
(3) Write a kretprobe module that tinkers with the return value of the
kernel's devmem_is_allowed() function such that it always returns 1.
http://gleeda.blogspot.com/2009/08/devcrash-driver.html
程序test1.c
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
int main(int argc, char **argv)
{
unsigned char *addr;
addr = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED, -1, 0);
strcpy(addr, "AAAAA");
printf("address at: %p content is: %s\n", addr, addr);
getchar();
printf("address at: %p content is: %s\n", addr, addr);
munmap(addr, 4096);
return 1;
}
下面做个实验通过/dev/mem来修改进程A的某个地址,
1) 编译后执行 ./test1
address at: 0x7f252e412000 content is: AAAA
2) 通过crash工具查看0x7f252e412000 对应的物理地址
3) 通过另外一个程序来修改这段物理地址
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <fcntl.h>
int main(int argc, char **argv)
{
int fd;
unsigned char *addr;
unsigned long off;
off = strtol(argv[1], NULL, 16);
fd = open("/dev/mem", O_RDWR);
addr = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, off);
strcpy(addr, "changed by wlm");
close(fd);
munmap(addr, 4096);
return 1;
}
编译后运行:./hack 0x898652000
可以看到入职直接运行会出现“Segmentation fault (core dumped)”的错误。
通过stap 跟踪可以看到 返回的是“0 pagenr=0x965447”,说明这段内存是不允许访问的。
# stap -e 'probe kernel.function("devmem_is_allowed").return { printf("%d %s", $return, $$parms)}'
4)于是我们可以通过stap来篡改devmem_is_allowed 的返回值。从而绕过这个问题。
运行这个命令后,需要退出crash后重进crash
# stap -g -e 'probe kernel.function("devmem_is_allowed").return { $return = 1 }'
5)test1程序键入回车,可以看到hack的输出。