1
votes

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
2

2 Answers

2
votes

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 ;)

1
votes

Obviously after the last syscall you must exit, return or jump somewhere else, otherwise you have an endless loop and it will crash the stack after some time.

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

Either that, or you must use a different syscall because here you do a sys_write operation. Maybe you wanted #60?