【问题标题】:Handling signals in x86_64 assembly [duplicate]在 x86_64 程序集中处理信号 [重复]
【发布时间】:2017-10-08 11:34:37
【问题描述】:

我想设置一个基本的信号陷阱。

global _start
%define stdout 1
%define sys_signal 48
%define SIGINT 2
%define SIGSEGV 11

section .text
exit:
    mov eax, 60
    mov rdi, 0
    syscall
catch:
    mov eax, 1
    mov rdi, stdout
    lea rsi, [message]
    mov rdx, 15
    syscall
    jmp exit

_start:
    ; jmp catch
    mov eax, sys_signal
    mov ebx, SIGINT
    mov ecx, catch
    int 80h
loop:
    jmp loop

section .data
    message: db "Signal caught!", 10

这会导致按下 Control-C 来中断程序而不是打印“信号被捕获!”的段错误。消息。

以上是this example的简化版。 (我也不知道要传递哪些选项来运行该示例。)

这是在 linux x86_64 上使用 nasm。但是我的系统似乎支持int 80h,但理想情况下我想用syscall 来做到这一点。

我的问题是:谁能给我一个在 x86_64 上使用 nasm 而不使用 C 的 SIGINT 或 SIGSEGV 信号处理的最小示例?

谢谢。

【问题讨论】:

  • This 是内联汇编,但我相信您可以自己将其变成 nasm。另外,不要这样做:)
  • 感谢您的回答。不幸的是,不,我不知道如何将它从 C 转换为 nasm(没有 C)。 (我可以将 at&t 语法 asm 转换为 intel 语法 asm,但 C 部分我不知道如何。)
  • 几乎没有任何 C,是什么导致你的问题?
  • 好吧,全部。假装我只能阅读汇编而不是 C(这几乎是真的:我几乎无法阅读任何汇编)。我无法阅读的一些示例包括“struct kernel_sigaction”以及最后的整个内容:“::”i”(7),”p”(&act),”p”(0):“rax” , ...
  • @asrp: re: using int 0x80 from 64-bit code: 它受支持,但没有优势(除非你正在搞乱你想在 32 或 64 上构建的东西-位代码,不使用%if 来选择最后如何制作sys_exit。)请参阅stackoverflow.com/questions/46087730/…

标签: assembly signals x86-64


【解决方案1】:

这是一个在 x86 assembler 代码中在 linux 上使用 sigaction 的示例,其抽象自:@987654321 @

  my $end   = Label;
  Jmp $end;                                                                     # Jump over subroutine definition
  my $start = SetLabel;
  Enter 0, 0;                                                                   # Inline code of signal handler
  Mov r15, rbp;                                                                 # Preserve the new stack frame
  Mov rbp, "[rbp]";                                                             # Restore our last stack frame
  PrintOutTraceBack;                                                            # Print our trace back
  Mov rbp, r15;                                                                 # Restore supplied stack frame
  Exit(0);                                                                      # Exit so we do not trampoline. Exit with code zero to show that the program is functioning correctly, else L<Assemble> will report an error.
  Leave;
  Ret;
  SetLabel $end;

  Mov r15, 0;                                                                   # Push sufficient zeros onto the stack to make a struct sigaction as described in: https://www.man7.org/linux/man-pages/man2/sigaction.2.html
  Push r15 for 1..16;

  Mov r15, $start;                                                              # Actual signal handler
  Mov "[rsp]", r15;                                                             # Show as signal handler
  Mov "[rsp+0x10]", r15;                                                        # Add as trampoline as well - which is fine because we exit in the handler so this will never be called
  Mov r15, 0x4000000;                                                           # Mask to show we have a trampoline which is, apparently, required on x86
  Mov "[rsp+0x8]", r15;                                                         # Confirm we have a trampoline

  Mov rax, 13;                                                                  # Sigaction from "kill -l"
  Mov rdi, 11;                                                                  # Confirmed SIGSEGV = 11 from kill -l and tracing with sde64
  Mov rsi, rsp;                                                                 # Sigaction structure on stack
  Mov rdx, 0;                                                                   # Confirmed by trace
  Mov r10, 8;                                                                   # Found by tracing "signal.c" with sde64 it is the width of the signal set and mask. "signal.c" is reproduced below.
  Syscall;
  Add rsp, 128;

  my $s = Subroutine                                                            # Subrotuine that will cause an error to occur to force a trace back to be printed
   {Mov r15, 0;
    Mov r15, "[r15]";                                                           # Try to read an unmapped memory location
   } [qw(in)], name => 'sub that causes a segv';                                # The name that will appear in the trace back

  $s->call(K(in, 42));

  ok Assemble(debug => 0, keep2 => 'signal', emulator=>0, eq => <<END);         # Cannot use the emulator because it does not understand signals

Subroutine trace back, depth: 0000 0000 0000 0001
0000 0000 0000 002A    sub that causes a segv

END

# /var/isde/sde64 -mix -ptr-check -debugtrace -- ./signal
##include <stdlib.h>
##include <stdio.h>
##include <signal.h>
##include <string.h>
##include <unistd.h>
#
#void handle_sigint(int sig)
# {exit(sig);
# }
#
#int main(void)
# {struct sigaction s;
#  memset(&s, 0, sizeof(s));
#  s.sa_sigaction = (void *)handle_sigint;
#
#  long a = 0xabcdef;
#  sigaction(SIGSEGV, &s, 0);
#  long *c = 0; *c = a;
# }
#
# gcc -finput-charset=UTF-8 -fmax-errors=7 -rdynamic -Wall -Wextra -Wno-unused-function -o signal signal.c  && /var/isde/sde64 -mix -ptr-check -debugtrace  -- ./signal; echo $?;
 

【讨论】:

  • 这是 perl 吗?它肯定不是 NASM 或 GAS 语法,在寻址模式周围加上引号,以及像 my $s = Subroutine { ... } 这样的恶作剧。还不清楚您是否/如何从该 C 和 perl 源构建一个或多个可执行文件。也许为不同的事情使用多个单独的代码块,并用文字解释它应该做什么。
  • 哦,最右边有 cmets 路。而不是# Jump over subroutine definition,首先不要将您的子例程定义放在首位。将它放在_start 或任何入口点执行开始的位置之后或之前。
  • @PeterCordes 我也很难说出这是什么语法,即使你暗示向右看。我知道底部是signal.c 的相关部分,但我仍然不能完全理解顶部的所有部分。无论如何,我认为我在询问后 2-3 天找到了解决问题的方法,而这个答案在将近 4 年后才出现。尽管如此,它仍然对通过搜索引擎而来的人们有用。
  • 看起来更像是一天后,我发布了我的答案here
  • @asrp:似乎这个答案 (github.com/philiprbrenan/NasmX86) 中链接的 NasmX86 实际上是一个 perl 模块,它允许您使用类似于 NASM 语法的部分编写 perl。我假设这些部分最终会发出机器代码,但这是一个非常模糊的汇编器选择,用于回答。但是,是的,可能比在使用信号或其他东西的静态链接 C 程序中反汇编 glibc 函数更有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-05
  • 2017-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-23
  • 2017-11-13
相关资源
最近更新 更多