gpt4 book ai didi

c - x86, amd64 : Why SIGTRAP' ucontext instruction pointer does not point to related int3

转载 作者:行者123 更新时间:2023-12-05 04:26:43 24 4
gpt4 key购买 nike

正如标题所说 - ucontext_t 中的 rip 不指向引发 SIGTRAPint3。相反,它指向下一条指令。

这偏离了我(幼稚)的预期,即每条错误指令都将在从信号处理程序返回时重试(如果上下文未更改并且进程在处理程序中时未明确终止)。

另一方面,当获取 SIGILL 时 - 上下文指向错误指令。同样在 ARM 和 Aarch64 上 - SIGTRAP 上下文也指向相关的 bkpt #0/bpt #0

测试程序:

/* sigtest.c */ 

#define _GNU_SOURCE

#include <stdio.h>
#include <signal.h>
#include <ucontext.h>

extern void do_int3(void);
extern void do_ud2(void);

void sighandler(int signo, siginfo_t* info, void* context) {
struct ucontext_t* uctx = context;
/* Yes, printf() here is bad. I promise to never ever do this in real programs */
printf("Got signal %d:\n"
"\tsi_addr: %p\n"
"\tcontext RIP: %p\n",
signo,
info->si_addr,
(void*)uctx->uc_mcontext.gregs[REG_RIP]);
}

int main(int argc, char** argv) {
struct sigaction sa = {};
sa.sa_flags = SA_SIGINFO | SA_ONESHOT;
sa.sa_sigaction = sighandler;
sigemptyset(&sa.sa_mask);
sigaction(SIGTRAP, &sa, NULL);
sigaction(SIGILL, &sa, NULL);

void (*fn)(void) = 0;

if (argv[1][0] == 't') {
fn = do_int3;
}
if (argv[1][0] == 'u') {
fn = do_ud2;
}

printf("call function at %p\n", fn);
fn();
printf("call returned\n");
}
; do_int3.S 
.text
.globl do_int3
.type do_int3, @function
do_int3:
int3
ret
.size do_int3, .-do_int3
; do_ud2.S 
.text
.globl do_ud2
.type do_ud2, @function
do_ud2:
ud2
ret
.size do_ud2, .-do_ud2

编译运行:

$ cc sigtest.c do_int3.S do_ud2.S 
$ ./a.out t
call function at 0x5620b87c6908
Got signal 5:
si_addr: (nil)
context RIP: 0x5620b87c6909
call returned
$ ./a.out u
call function at 0x557d1bc1590a
Got signal 4:
si_addr: 0x557d1bc1590a
context RIP: 0x557d1bc1590a
Illegal instruction (core dumped)

很容易注意到,对于 SIGTRAPrip 值指向下一条指令,而不是指向 int3

为什么在SIGTRAP上下文中调整指令指针不重试相关的int3

最佳答案

Why is instruction pointer adjusted in SIGTRAP context to not retry related int3?

它不是由内核调整的;硬件推送的异常返回地址是int指令之后的地址,包括int3

请记住 int3the normal case of int n 仅略有不同例如 int 0x80int 被设计为类似于系统调用或远程调用,因此(异常)返回地址是int之后的地址。否则,除非内核在 iret 之前编辑了异常返回信息,否则 int 0x80 系统调用将永远重新运行。

那么为什么 Linux 的 int3/int 3 处理程序不将保存的 RIP 减 1?一方面,如果调试人员愿意,他们可以在软件中做到这一点,并且保持内核简单更好。 (对于确实想知道硬件推送的地址的软件来说,维护、效率和更少的分解。)

另一方面,1 字节的固定偏移量并不总是正确的:2 字节 CD 03 int 3 引发与 1 字节 CC int3 相同的异常.即使您想尝试,x86 机器代码也不会唯一地向后解码,因此混淆后的机器代码可能会给出一个地址,该地址并不是所执行指令的实际开始位置。 (尽管如果从那里解码,它将作为 int 3int3 运行)。例如如果向后看,2 字节 rep int3add al, 0xf3/int3 无法区分。

像 GDB 这样插入 int3 的软件会知道它插入了什么,并且需要知道目标机器的详细信息,因此可以处理偏移量。

关于c - x86, amd64 : Why SIGTRAP' ucontext instruction pointer does not point to related int3,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72973683/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com