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

时间:2017-01-27 23:18:04

标签: c gcc segmentation-fault stack-overflow disassembly

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

当程序执行段错误时,gdb不适合调试,但是当我执行info frame时,我看到,在段错误之后,存在"帧级别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;
} 

我增加8的原因是因为main()中的phail指令是8个字节:

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>

我需要稍微增加偏移量吗?在处理段故障情况时,我的访问堆栈的方法(我认为对应于EBP + 4)是否需要更改?

1 个答案:

答案 0 :(得分:0)

使用sigaction而非signal注册信号处理程序,并使用SA_SIGINFO标志获取描述信号原因的siginfo_t。这样,您就可以处理因错误导致的SIGSEGVraisekillsigqueue等发送的ucontext_t不同。这也为您提供了{{1}必须检查故障时的状态,并在返回之前选择更改它。

BT顺便说一句signal一般来说使用SA_RESTART是一个坏主意,因为它未指定是否设置了SA_RESTART标志 - 并且您几乎总是想要sigaction。习惯使用signal并将{{input}}视为已弃用。