C 直接调用的信号处理程序与raise()调用的信号处理程序之间的堆栈差异?
我试图在段错误处理程序中修改堆栈上的返回地址,以便它跳过错误指令。但是,每当我试图修改返回地址时,如果我不直接调用信号处理程序,就会出现段错误 当程序执行segfault时,gdb不适合调试,但当我执行C 直接调用的信号处理程序与raise()调用的信号处理程序之间的堆栈差异?,c,gcc,segmentation-fault,stack-overflow,disassembly,C,Gcc,Segmentation Fault,Stack Overflow,Disassembly,我试图在段错误处理程序中修改堆栈上的返回地址,以便它跳过错误指令。但是,每当我试图修改返回地址时,如果我不直接调用信号处理程序,就会出现段错误 当程序执行segfault时,gdb不适合调试,但当我执行info frame时,我发现在执行segfault后,会出现“帧级别2”而不是“帧级别0”?我不知道GDB从哪里得到这些信息,因为当我尝试x/12xw$ebp或者无论有多少单词,我都看不到main()的返回地址 在CentOS linux上使用-m32-z execstack-fno stack
info frame
时,我发现在执行segfault后,会出现“帧级别2”而不是“帧级别0”?我不知道GDB从哪里得到这些信息,因为当我尝试x/12xw$ebp
或者无论有多少单词,我都看不到main()
的返回地址
在CentOS linux上使用-m32-z execstack-fno stack protector编译
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
void segment_fault_handler(int signum)
{
char* ret = (char*)(&signum)-4;
*(ret) += 8;
}
int main()
{
int phail = 0;
signal(SIGSEGV, segment_fault_handler);
segment_fault_handler(7); //Only by using this can I skip the next instruction
phail = *( (int *) 0);
printf("Win!\n");
return 0;
}
我需要稍微增加偏移量吗?在处理段故障情况时,我访问堆栈的方法(我认为对应于EBP+4)是否需要更改?用
sigaction
注册信号处理程序,而不是signal
,并使用SAU SIGINFO
标志获取描述信号原因的SIGINFO
。这将允许您处理由故障引起的SIGSEGV
,与显式raise
d或由kill
、sigqueue
等发送的故障不同。这也为您提供了必要的ucontext\u t
,以检查故障时的状态,并在返回前选择性地对其进行更改
顺便说一句,一般来说,
signal
无论如何使用都不是一个好主意,因为未指定是否设置了SA_RESTART
标志,而且您几乎总是希望SA_RESTART
。养成使用sigaction
并将signal
视为弃用的习惯。您需要修改传递给处理程序的ucontext\u t
结构中保存的PC,而不是信号处理函数的即时返回地址。(不要直接调用它。)的示例程序演示了如何访问ucontext\u t
结构。
0x080484e2 <+37>: movl $0x7,(%esp)
0x080484e9 <+44>: call 0x8048480 <segment_fault_handler>
0x080484ee <+49>: mov $0x0,%eax
0x080484f3 <+54>: mov (%eax),%eax
0x080484f5 <+56>: mov %eax,0x1c(%esp)
0x080484f9 <+60>: movl $0x80485b4,(%esp)
0x08048500 <+67>: call 0x8048350 <puts@plt>