我尝试修改名为 g 的函数的第一条指令,但在以下代码段的第二条语句中出现了段错误
int a = *(int*)g;
*(int*)g=0; // segment fault!
*(int*)g=a;
由于我想要修改的指令所在页面的页面表条目中的无写入权限,该段是否有错误?
我之所以这样做是因为我想看看是否可以使用一些错误修补一个函数,同时保持进程运行,如下所示:
1)正在运行功能 g 的流程,并且发现 g 存在一些错误。所以编写一个名为 patch_g 的新函数,该函数没有错误。
2)将新功能编译为 patch.so
3) dlopen & dlsym .so文件。获取 patch_g 的地址。
4)暂停正在运行的过程
5)使用一些代码(有点类似于上面代码段的第二个陈述)将 g 的第一条指令更改为jump patch_g
。
答案 0 :(得分:1)
好的,让我们做一个实验。 这是代码:
#include <stdio.h>
int (*functionPtr)(int,int);
int addInt(int n, int m) {
return n+m;
}
int main()
{
functionPtr = &addInt;
printf("%p\n", functionPtr);
while(1){};
*(int *) functionPtr = 0x0;
return 0;
}
编译
$ gcc -o ./main.c main
在第一个控制台中启动此应用程序。
$ ./main
0x40052d
在第二个控制台
$ cat /proc/`pidof main`/maps
00400000-00401000 r-xp 00000000 08:01 6345711 /tmp/main
00600000-00601000 r--p 00000000 08:01 6345711 /tmp/main
00601000-00602000 rw-p 00001000 08:01 6345711 /tmp/main
...
此 r-xp 表示当内核加载此二进制文件时,它已将文本部分映射到具有读取和执行权限的私有虚拟映射,但没有写入权限。我认为这样做是出于安全原因。
内核中标记为不可写的vma_area是合适的,导致未处理的用户空间页面错误,即发生了段错误。
现在让我们将mprotect调用添加到适当的地方
17 if (mprotect((void *)0x00400000, 4096, PROT_READ | PROT_WRITE | PROT_EXEC)) {
18 printf("error\n");
19 return -1;
20 }
您会注意到这将有助于您获得运行时修补的想法。
00400000-00401000 rwxp 00000000 08:01 6345711 /tmp/main
00600000-00601000 r--p 00000000 08:01 6345711 /tmp/main
00601000-00602000 rw-p 00001000 08:01 6345711 /tmp/main