C 直接调用的信号处理程序与raise()调用的信号处理程序之间的堆栈差异?

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

我试图在段错误处理程序中修改堆栈上的返回地址,以便它跳过错误指令。但是,每当我试图修改返回地址时,如果我不直接调用信号处理程序,就会出现段错误

当程序执行segfault时,gdb不适合调试,但当我执行
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>