Nasm x86-64 中的 Hello World 程序连续打印 Hello World

Hello World program in Nasm x86-64 prints Hello World continuously

你能帮我看看这段代码吗?执行时,程序会连续打印 Hello World 并且不会退出。我也想在 C 程序中使用这段代码作为 shellcode,因此我没有在数据部分定义 Hello String。请告诉我问题出在哪里。

SECTION .text       ; Code section
    global _start       ; Make label available to linker 

_start:             ; Standard ld entry point

jmp callback    ; Jump to the end to get our current address

dowork:

    pop     rsi     ;
    mov rax,4       ; System call number for write
    mov     rdi,1   ; 1 for stdout
    mov     rdx,12  ; length of Hello World
    syscall         ; Switch to the kernel mode

    mov     rax,1   ;
    xor rdi,rdi     ;
    syscall         ;

callback:
   call dowork        ; Pushes the address of "Hello World" onto the stack
   db 'Hello World',0xA  ; The string we want to print

显然在最后一个 syscall 之后你必须退出,return 或跳到其他地方,否则你有一个死循环,一段时间后它会崩溃堆栈。

mov     rax,1   ;   sys_write
xor rdi,rdi     ;
syscall         ;

要么,要么你必须使用不同的系统调用,因为你在这里做了一个 sys_write 操作。也许你想要 #60?

说明

  • 您为 x86-64 使用了错误的系统调用编号 Linux。因此,您的 exit() 调用失败,取而代之的是 doworkcallback 最终进入相互递归,导致循环。
  • 有关正确的系统调用编号,请参阅 Linux 源代码中的 arch/x86/syscalls/syscall_64.tbl

1 common write sys_write 231 common exit_group sys_exit_group

  • 如果您愿意接受 AT&T x86 汇编器语法和 C 预处理器,您可以 #include <sys/syscall.h> 并使用例如SYS_write 作为 write 的系统调用号。请参阅下面的 hello-att.S。这样你就可以不用担心查找系统调用号了。

hello.asm

    SECTION .text   ; Code section
    global _start   ; Make label available to linker 

_start:             ; Standard ld entry point    
    jmp callback    ; Jump to the end to get our current address

dowork: 
    pop     rsi     ;
    mov rax,1       ; System call number for write
    mov     rdi,1   ; 1 for stdout
    mov     rdx,12  ; length of Hello World
    syscall         ; Switch to the kernel mode

    mov   rax,231   ; exit_group(0)
    xor rdi,rdi     ;
    syscall         ;

callback:
    call dowork     ; Pushes the address of "Hello World" onto the stack
    db 'Hello World',0xA  ; The string we want to print

你好-att.S

#include <sys/syscall.h>

    .global _start
_start:
    jmp callback
dowork:
    /* write(1, "Hello World\n", 12) */
    pop %rsi /* "Hello World\n" */
    mov $SYS_write, %rax
    mov , %rdi
    mov , %rdx
    syscall

    /* exit_group(0) */
    mov $SYS_exit_group, %rax
    xor %rdi, %rdi
    syscall

callback:
    call dowork
    .ascii "Hello World\n"

了解 AT&T x86 汇编器语法使阅读 Linux 内核和 glibc 源代码变得容易得多;)