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

标签 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)是否需要更改?

最佳答案

使用sigaction而不是signal注册信号处理程序,并使用SA_SIGINFO标志来获取siginfo_t描述信号产生的原因。这将允许您处理由错误引起的 SIGSEGV,该错误不同于显式 raised 或由 killsigqueue 发送的错误> 等。这还为您提供了检查故障时的状态并可选择在返回之前更改状态所需的 ucontext_t

顺便说一句,一般来说,无论如何使用 signal 都是一个坏主意,因为未指定是否设置了 SA_RESTART 标志 - 并且您几乎总是想要 SA_RESTART.养成使用 sigaction 并将 signal 视为已弃用的习惯。

关于c - 直接调用信号处理程序和通过 raise() 调用的信号处理程序之间的堆栈差异?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41904590/

相关文章:

c++ - 简单的 getter/accessor 防止矢量化 - gcc 错误?

c++ - 无法理解为什么会发生段错误

c++ - 调用第三方可执行文件时调试段错误

c - 使用命令行参数的结构链接列表

c - 在 main.c 或 source.c 中进行 Rng 初始化?

c - banana pi 和设备树的 Linux 设备驱动程序

c - 结构和位域的奇怪行为

c - 使用 4.2 OpenGL 时,"glGenTextures"返回 1282 错误

c - 避免 float 的不准确性

linux - 使用 arg 时出现 nasm 段错误