为了检查我是否可以在运行时更改代码,我在linux中编写了一小段代码(下面)。
int add(int a, int b)
{
printf("reached inside the function");
return a+b;
}
int main()
{
int x=10;
int y = 20;
int * p;
int z;
int (*fp) (int , int);
fp = add;
p = (int *)fp;
*(p+0) = 0;
z = add(x,y);
}
从c编码的角度来看,没有问题,编译器编译完美,链接也会发生。但是在运行时它失败并出现以下错误:
分段错误(核心转储)
上面的错误是完美的,因为代码段不应该在运行时被更改,但我想知道它是如何在运行时被控制的。
要了解有关代码区域限制的更多信息,我在输出文件上运行了readelf,结果显示在以下部分标题中:
[13] .text PROGBITS 08048330 000330 0001cc 00 AX 0 0 16
其中节标题标记显示为" AX" ,表示此部分只是可分配和可执行的。它不支持写作(" W")。
并且对elf文件进行了一些小改动,我能够将此部分的标志修改为" WAX" ,如下所示:
[13] .text PROGBITS 08048330 000330 0001cc 00 WAX 0 0 16
但我仍然得到相同的#34;分段错误"错误。
我想知道 - 系统是如何实现的?
答案 0 :(得分:2)
分段错误是否发生在同一个地方?
可能是操作系统忽略了W
标志,但我不认为这是这种情况。假设操作系统尊重该标志,则以下内容是相关的。
你用add
覆盖0
函数的第一条指令,在x86汇编中是(假设这里有4个字节int
)
00000000 0000 add [bx+si],al
00000002 0000 add [bx+si],al
最有可能最终访问bx+si
的无效内存。
答案 1 :(得分:2)
系统忽略了W
标志:
$ gcc -Wall file.c
$ readelf -S a.out | grep .text
[14] .text PROGBITS 08048330 000330 0001cc 00 AX 0 0 16
$ objcopy a.out --set-section-flags .text=alloc,code,data a.out
$ readelf -S a.out | grep .text
[14] .text PROGBITS 08048330 000330 0001cc 00 WAX 0 0 16
$ gdb -q a.out
Reading symbols from a.out...(no debugging symbols found)...done.
(gdb) r
Starting program: a.out
Program received signal SIGSEGV, Segmentation fault.
0x0804842f in main ()
(gdb) x/i 0x0804842f
0x804842f <main+45>: movl $0x0,(%eax)
(gdb)
您仍然无法写信至p
。您可以使用mprotect
:
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/mman.h>
int add(int a, int b)
{
printf("reached inside the function");
return a+b;
}
int main()
{
int x=10;
int y = 20;
int * p;
int z;
int (*fp) (int , int);
long pagesize;
fp = add;
p = (int *)fp;
pagesize = sysconf(_SC_PAGESIZE);
if(mprotect((void *)((uintptr_t)p & ~((uintptr_t)pagesize - 1)), pagesize, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
perror("Error mprotect()");
*(p+0) = 0;
z = add(x,y);
return 0;
}
这会让你得到错误的解决方法:
$ gcc -Wall file.c
$ ./a.out
Segmentation fault
$ gdb -q a.out
Reading symbols from a.out...(no debugging symbols found)...done.
(gdb) r
Starting program: a.out
Program received signal SIGSEGV, Segmentation fault.
0x08048484 in add ()
(gdb) x/i 0x08048484
0x8048484 <add>: add %al,(%eax)
(gdb)