On line int 80h, a debugging error is raised: Program received signal SIGSEGV, Segmentation fault.
If run without debugging, the program just crashes. What could be the reason?
section .data
msg db 'Hello, World!', 0xA
length equ $ -msg
section .text
global _main
kernel:
int 80h
ret
_main:
push ebp
mov ebp, esp
mov eax, 4
mov ebx, 1
mov ecx, msg
mov edx, length
call kernel
pop ebp
ret
Related
I have the following assembly code down here. Basically I want to execute sys_write syscall twice to write something to stdout.
section .text
global _start
_start:
;write hello world
mov eax, 4
mov ebx, 1
mov edx, len_hello_world
mov ecx, hello_world
int 0x80
;write my name
mov eax, 4
mov ebx, 1
mov edx, len_my_name
mov ecx, my_name
int 0x80
;exit program
mov eax, 1 ; sys_exit
int 0x80
section .data
hello_world db "Hello, World!", 0xd
len_hello_world equ $ - hello_world
my_name db " My name is Moritz!", 0x13
len_my_name equ $ - my_name
Expected output:
Hello, World! My name is Moritz!
Actual output:
My name is Moritz!
My question is: Why is the first sys_call "skipped" (sorry for layman terms, i'm total noob)
I was experimenting and have the following assembly code, which works very well, except that I get a "Segmentation fault (core dumped)" message right before my program ends:
GLOBAL _start
%define ___STDIN 0
%define ___STDOUT 1
%define ___SYSCALL_WRITE 0x04
segment .data
segment .rodata
L1 db "hello World", 10, 0
segment .bss
segment .text
_start:
mov eax, ___SYSCALL_WRITE
mov ebx, ___STDOUT
mov ecx, L1
mov edx, 13
int 0x80
It doesn't matter whether or not I have ret at the end; I still get the message.
What's the problem?
I'm using x86 and nasm.
You can't ret from start; it isn't a function and there's no return address on the stack. The stack pointer points at argc on process entry.
As n.m. said in the comments, the issue is that you aren't exiting the program, so execution runs off into garbage code and you get a segfault.
What you need is:
;; Linux 32-bit x86
%define ___SYSCALL_EXIT 1
// ... at the end of _start:
mov eax, ___SYSCALL_EXIT
mov ebx, 0
int 0x80
(The above is 32-bit code. In 64-bit code you want mov eax, 231 (exit_group) / syscall, with the exit status in EDI. For example:
;; Linux x86-64
xor edi, edi ; or mov edi, eax if you have a ret val in EAX
mov eax, 231 ; __NR_exit_group
syscall
I am trying to create an x86_64 assembly program that displays "SIGTERM received" whenever the SIGTERM signal is sent. My application is using Linux syscalls directly:
%define sys_write 0x01
%define sys_rt_sigaction 0x0d
%define sys_pause 0x22
%define sys_exit 0x3c
%define SIGTERM 0x0f
%define STDOUT 0x01
; Definition of sigaction struct for sys_rt_sigaction
struc sigaction
.sa_handler resq 1
.sa_flags resq 1
.sa_restorer resq 1
.sa_mask resq 1
endstruc
section .data
; Message shown when a syscall fails
error_msg db 'syscall error', 0x0a
error_msg_len equ $ - error_msg
; Message shown when SIGTERM is received
sigterm_msg db 'SIGTERM received', 0x0a
sigterm_msg_len equ $ - sigterm_msg
section .bss
act resb sigaction_size
val resd 1
section .text
global _start
_start:
; Initialize act
lea rax, [handler]
mov [act + sigaction.sa_handler], rax
; Set the handler
mov rax, sys_rt_sigaction
mov rdi, SIGTERM
lea rsi, [act]
mov rdx, 0x00
mov r10, 0x08
syscall
; Ensure the syscall succeeded
cmp rax, 0
jne error
; Pause until a signal is received
mov rax, sys_pause
syscall
; Upon success, jump to exit
jmp exit
error:
; Display an error message
mov rax, sys_write
mov rdi, STDOUT
mov rsi, error_msg
mov rdx, error_msg_len
syscall
; Set the return value to one
mov dword [val], 0x01
exit:
; Terminate the application gracefully
mov rax, sys_exit
mov rdi, [val]
syscall
handler:
; Display a message
mov rax, sys_write
mov rdi, STDOUT
mov rsi, sigterm_msg
mov rdx, sigterm_msg_len
syscall
ret
When I run the application, it hangs (as expected) at the sys_pause syscall but when I send the SIGTERM signal, it crashes with a segmentation fault.
So I loaded the application into GDB to figure out what was happening:
(gdb) break _start
Breakpoint 1 at 0x4000b0
(gdb) run
Starting program: [...]
Breakpoint 1, 0x00000000004000b0 in _start ()
(gdb) info proc
process 9639
(gdb) continue
Continuing.
The GDB session hung and I then opened another terminal and ran kill SIGTERM 9639. This resulted in the following output:
Program received signal SIGTERM, Terminated.
0x00000000004000ec in _start ()
I then ran:
(gdb) disas _start
Dump of assembler code for function _start:
0x00000000004000b0 <+0>: lea 0x400123,%rax
0x00000000004000b8 <+8>: mov %rax,0x600160
0x00000000004000c0 <+16>: mov $0xd,%eax
0x00000000004000c5 <+21>: mov $0xf,%edi
0x00000000004000ca <+26>: lea 0x600160,%rsi
0x00000000004000d2 <+34>: mov $0x0,%edx
0x00000000004000d7 <+39>: mov $0x8,%r10d
0x00000000004000dd <+45>: syscall
0x00000000004000df <+47>: cmp $0x0,%rax
0x00000000004000e3 <+51>: jne 0x4000ee <error>
0x00000000004000e5 <+53>: mov $0x22,%eax
0x00000000004000ea <+58>: syscall
=> 0x00000000004000ec <+60>: jmp 0x400114 <exit>
End of assembler dump.
Then I continued the application:
(gdb) continue
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x00000000004000ec in _start ()
The signal handler is never invoked and the application has crashed.
What am I doing wrong?
There were two corrections that needed to be made before the application worked correctly.
sa_restorer
Jester pointed me to this answer which mentioned that the kernel requires the sa_restorer member of sigaction to be filled in.
Fixing this required defining SA_RESTORER:
%define SA_RESTORER 0x04000000
...and initializing the sa_restorer and sa_flags members:
mov [act + sigaction.sa_flags], dword SA_RESTORER
lea rax, [restorer]
mov [act + sigaction.sa_restorer], rax
I then added an empty stub for the restorer function:
restorer:
ret
At this point, the handler was invoked without error but the application was still crashing...
sys_rt_sigreturn
Apparently, the sa_restorer function needs to invoke the sys_rt_sigreturn syscall. This required defining sys_rt_sigreturn:
%define sys_rt_sigreturn 0x0f
The restorer function was then modified:
restorer:
; return from the signal handler
mov rax, sys_rt_sigreturn
syscall
At this point, the application ran without crashing.
Here's the entire working and corrected program by Nathan Osman. Answering here because such an example doesn't seem to exist anywhere else on the internet.
%define sys_write 0x01
%define sys_rt_sigaction 0x0d
%define sys_pause 0x22
%define sys_exit 0x3c
%define sys_rt_sigreturn 0x0f
%define SIGTERM 0x0f
%define SIGINT 0x02
%define STDOUT 0x01
%define SA_RESTORER 0x04000000
; Definition of sigaction struct for sys_rt_sigaction
struc sigaction
.sa_handler resq 1
.sa_flags resq 1
.sa_restorer resq 1
.sa_mask resq 1
endstruc
section .data
; Message shown when a syscall fails
error_msg db 'syscall error', 0x0a
error_msg_len equ $ - error_msg
; Message shown when SIGTERM is received
sigterm_msg db 'SIGTERM received', 0x0a
sigterm_msg_len equ $ - sigterm_msg
section .bss
act resb sigaction_size
val resd 1
section .text
global _start
_start:
; Initialize act
mov qword [act + sigaction.sa_handler], handler
mov [act + sigaction.sa_flags], dword SA_RESTORER
mov qword [act + sigaction.sa_restorer], restorer
; Set the handler
mov rax, sys_rt_sigaction
;mov rdi, SIGINT
mov rdi, SIGTERM
lea rsi, [act]
mov rdx, 0x00
mov r10, 0x08
syscall
; Ensure the syscall succeeded
cmp rax, 0
jne error
; Pause until a signal is received
mov rax, sys_pause
syscall
; Upon success, jump to exit
jmp exit
error:
; Display an error message
mov rax, sys_write
mov rdi, STDOUT
mov rsi, error_msg
mov rdx, error_msg_len
syscall
; Set the return value to one
mov dword [val], 0x01
exit:
; Terminate the application gracefully
mov rax, sys_exit
mov rdi, [val]
syscall
handler:
; Display a message
mov rax, sys_write
mov rdi, STDOUT
mov rsi, sigterm_msg
mov rdx, sigterm_msg_len
syscall
ret
restorer:
; return from the signal handler
mov rax, sys_rt_sigreturn
syscall
For easier testing, you can replace SIGTERM with SIGINT by uncommenting the first list here and commenting the second.
;mov rdi, SIGINT
mov rdi, SIGTERM
Save it to signal.asm and compile and run with
nasm -f elf64 signal.asm -o signal.o && ld signal.o && ./a.out
In the SIGINT version, pressing Control-C to interrupt the program should print message 'SIGTERM received' (its also possible to change that to make it more accurate). In the SIGTERM version, instead run it in gdb
$ gdb ./a.out
[GNU gdb...]
(gdb) r
Starting program: /path/a.out
And now press Control-C
^C
Program received signal SIGINT, Interrupt.
0x0000000000400107 in _start ()
(gdb) signal SIGTERM
Continuing with signal SIGTERM.
SIGTERM received
[Inferior 1 (process 22742) exited normally]
(gdb)
The 'SIGTERM received' message is printed as expected.
I was experimenting and have the following assembly code, which works very well, except that I get a "Segmentation fault (core dumped)" message right before my program ends:
GLOBAL _start
%define ___STDIN 0
%define ___STDOUT 1
%define ___SYSCALL_WRITE 0x04
segment .data
segment .rodata
L1 db "hello World", 10, 0
segment .bss
segment .text
_start:
mov eax, ___SYSCALL_WRITE
mov ebx, ___STDOUT
mov ecx, L1
mov edx, 13
int 0x80
It doesn't matter whether or not I have ret at the end; I still get the message.
What's the problem?
I'm using x86 and nasm.
You can't ret from start; it isn't a function and there's no return address on the stack. The stack pointer points at argc on process entry.
As n.m. said in the comments, the issue is that you aren't exiting the program, so execution runs off into garbage code and you get a segfault.
What you need is:
;; Linux 32-bit x86
%define ___SYSCALL_EXIT 1
// ... at the end of _start:
mov eax, ___SYSCALL_EXIT
mov ebx, 0
int 0x80
(The above is 32-bit code. In 64-bit code you want mov eax, 231 (exit_group) / syscall, with the exit status in EDI. For example:
;; Linux x86-64
xor edi, edi ; or mov edi, eax if you have a ret val in EAX
mov eax, 231 ; __NR_exit_group
syscall
I have this linux nasm code here that doesn't crash. With the ret 80 instruction at the end of printString shouldn't this program crash?
bits 32
section .data
hello: db 'Hello Linux assembly!!!!!!!!!!!!!!!!!!!',10,0
helloLen: equ $-hello
anotherString db "hello im another string!!!!",10,0
anotherStringlen equ $-anotherString
section .text
global _start
_start:
push hello
push helloLen
call printString
;;;; should i pop the two paramters I pushed?
;;;; does the ret instruction do it for me?
push anotherString
push anotherStringlen
call printString
call exit
printString:
push ebp
mov ebp, esp
mov eax, 4
mov ebx, 1
mov ecx, [ebp+12]
mov edx, [ebp+8]
int 80h
pop ebp
ret 60 ;;;;; How does this not make printString crash?
exit:
mov eax,1
mov ebx,0
int 80h
Doing things incorrectly in assembly language by no means assures that you'll get a crash.
The ret 60 instruction pops the wrong number of values off the stack after returning. However, the next things you do don't assume that there are any values of use on the stack. For instance, the exit function won't care that the stack is trashed, and will still exit your process.