Nasm x86-64's Hello World program prints Hello World continuously

advertisements

Could you please help me on this code. On execution, the program prints Hello World continuously and does not exit. I want to use this code as shellcode in C program too, hence I have not defined Hello String in data section. Please let me know where is the issue.

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


Explanation

  • You're using the wrong syscall numbers for x86-64 Linux. Thus your exit() call fails and instead dowork and callback end up in a mutual recursion, causing a loop.
  • For the correct syscall numbers, see arch/x86/syscalls/syscall_64.tbl in the Linux source code:

1 common write sys_write 231 common exit_group sys_exit_group

  • If you're willing to embrace AT&T x86 assembler syntax and the C preprocessor, you can #include <sys/syscall.h> and use e.g. SYS_write as the syscall number for write. See hello-att.S below. This way you can stop worrying about looking up the syscall numbers.

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

hello-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 $1, %rdi
    mov $12, %rdx
    syscall

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

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

Knowing AT&T x86 assembler syntax makes reading Linux kernel and glibc source a lot easier ;)