Why does this NASM assembly program print nothing - linux

I have the following assembly, which I assemble with NASM and then link with gcc:
section .text
extern printf
global main
main:
sub rsp, 8 ;align stack pointer
mov rax, 0 ;no vector arguments
mov rdi, intro_message ;First argument
call printf
mov rax, 60 ;exit
syscall
section .data
intro_message:
db 'Hello world',0
When I run ./a.out, nothing is printed, and the instruction pointer seems to have moved to an invalid location. What have I done wrong?

Related

x86_64 Warning : character constant too long [-w+other] (nasm)

I am writing a compiler in attempt to switch my programming language from interpreted to compiled
this is the code my script generated:
section .bss
digitSpace resb 100
digitSpacePos resb 8
string_at_index_0 resb 12
string_at_index_0_len resb 4
section .data
section .text
global _start
_start:
mov rax, "Hello world"
mov [string_at_index_0], rax
mov byte [string_at_index_0_len], 13
mov rax, 1
mov rdi, 1
mov rsi, string_at_index_0
mov rdx, string_at_index_0_len
syscall
mov rax, 60
mov rdi, 0
syscall
when i run this code with nasm -f elf64 -o test.o test.asm i get this warning:
warning:character constant too long [-w+other]
can anyone help me with this , and also if anyone could suggest a better way to output a Hello world that would be helpful too!
mov rax, "Hello world"
RAX is an 64-bit (8 byte) register, you are trying to put 11 bytes into it.
Here is a simple hello world:
As can be seen you don't want to put the message inside the register, you want to put a pointer to the message into rsi.
section .data
msg: db "Hello World"
section .text
global _start
_start:
mov rax, 1 ; write function
mov rdi, 1 ; to stdout
mov rsi, msg ; pointer to message
mov rdx, 11 ; length of the message
syscall ; write
Ideally, your compiler should declare string literals in .data section and pass pointers to them when using them in functions.

Why does my shellcode segfault when executed from C, but not as a stand-alone executable?

I'm trying to execute a shell with shellcode. I've made this code in a 64-bits machine:
section .text
global _start
_start:
xor rax, rax
push rax
mov rbx, "/bin//sh"
push rbx
mov rdi, rsp
mov al, 59
syscall
mov al, 60
xor rdi, rdi
syscall
After using nasm and linking with ld if i execute the file this works fine. The problem is if i get the shellcode from this and tried to execute it with this program:
int main(){
char *shellcode = "\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\xb0\x3b\x0f\x05\xb0\x3c\x48\x31\xff\x0f\x05";
(*(void(*)()) shellcode)();
}
It gives me a segmentation fault error. I can't see what's wrong here. Any help would be appreciated.
EDIT: Already tried the gcc -z execstack to make the stack executable, still gives a segmentation fault error
It is normal, because your shellcode is not setting the registers rsi and rdx, and when your C program executes the shellcode will have garbage in the registers rdi and rdx. It is because the syscall execve needs more arguments.
int execve (const char *filename, const char *argv [], const char *envp[]);
As extra information, the segmentation fault is because after your execve syscall you will get an error in rax and you will move 60 to the last 8 bits of rax and call to this syscall that doesn't exist.

NASM basic input-output program crashes

Following this thread, How do i read single character input from keyboard using nasm (assembly) under ubuntu? ,I'm trying to compile a program that echoes the input in NASM.
I've made following files:
my_load2.asm:
%include "testio.inc"
global _start
section .text
_start: mov eax, 0
call canonical_off
call canonical_on
testio.inc:
termios: times 36 db 0
stdin: equ 0
ICANON: equ 1<<1
ECHO: equ 1<<3
canonical_off:
call read_stdin_termios
; clear canonical bit in local mode flags
push rax
mov eax, ICANON
not eax
and [termios+12], eax
pop rax
call write_stdin_termios
ret
echo_off:
call read_stdin_termios
; clear echo bit in local mode flags
push rax
mov eax, ECHO
not eax
and [termios+12], eax
pop rax
call write_stdin_termios
ret
canonical_on:
call read_stdin_termios
; set canonical bit in local mode flags
or dword [termios+12], ICANON
call write_stdin_termios
ret
echo_on:
call read_stdin_termios
; set echo bit in local mode flags
or dword [termios+12], ECHO
call write_stdin_termios
ret
read_stdin_termios:
push rax
push rbx
push rcx
push rdx
mov eax, 36h
mov ebx, stdin
mov ecx, 5401h
mov edx, termios
int 80h
pop rdx
pop rcx
pop rbx
pop rax
ret
write_stdin_termios:
push rax
push rbx
push rcx
push rdx
mov eax, 36h
mov ebx, stdin
mov ecx, 5402h
mov edx, termios
int 80h
pop rdx
pop rcx
pop rbx
pop rax
ret
Then I run:
[root#localhost asm]# nasm -f elf64 my_load2.asm
[root#localhost asm]# ld -m elfx86_64 my_load2.o -o my_load2
When I try to run it i get:
[root#localhost asm]# ./my_load2
Segmentation fault
Debugger says:
(gdb) run
Starting program: /root/asm/my_load2
Program received signal SIGSEGV, Segmentation fault.
0x00000000004000b1 in canonical_off ()
Can someone explain why is it crashing without on "import" step?
Also, I am running RHEL in Virtualbox under Win7 64 bit. Can this cause problems with compilation?
Firstly, let's address the issue of not exiting, as mentioned by Daniel. Let's comment out the two call instructions, so the program essentially does nothing:
%include "testio.inc"
global _start
section .text
_start: mov eax, 0
;call canonical_off
;call canonical_on
When we run this:
$ ./my_load2
Segmentation fault (core dumped)
It still dies! Daniel is right - you need to exit:
%include "testio.inc"
global _start
section .text
_start: mov eax, 0
;call canonical_off
;call canonical_on
mov eax, 1
mov ebx, 0
int 0x80
This time:
$ ./my_load2
$
No segfault. So let's uncomment the calls:
%include "testio.inc"
global _start
section .text
_start: mov eax, 0
call canonical_off
call canonical_on
mov eax, 1
mov ebx, 0
int 0x80
And run it again:
$ ./my_load2
Segmentation fault (core dumped)
We get a segfault again. But at least we can be (fairly) sure that's coming from inside one of the called routines.
Running the executable with strace is also quite informative:
$ strace ./my_load2
execve("./my_load2", ["./my_load2"], [/* 57 vars */]) = 0
setsockopt(0, SOL_IP, 0x400080 /* IP_??? */, NULL, 0) = -1 EFAULT (Bad address)
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_ACCERR, si_addr=0x40008c} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)
The setsockopt line is due to the ioctl request that happens in read_stdin_termios. strace tells us the return value was EFAULT. The setsockopt(2) man page tells us this happens when:
The address pointed to by optval is not in a valid part of the process address space.
Actually this is telling us that the block of memory into which the termios structure is written is read-only. Frank is correct; everything in the program - including the termios space, and all the code - is in the read-only .text section. You can see this with:
$ objdump -h my_load2.o
my_load2.o: file format elf64-x86-64
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 000000cd 0000000000000000 0000000000000000 000001c0 2**4
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
i.e. there's only one section, .text, and it's READONLY.
The line that actually causes the segfault, however, is this one:
and [termios+12], eax
because it also tries to write to the (read-only) termios memory.
The quickest way to fix this is to put the termios memory in the .data section, and everything else in the .text section:
section .data
termios: times 36 db 0
section .text
stdin: equ 0
ICANON: equ 1<<1
ECHO: equ 1<<3
canonical_off:
call read_stdin_termios
[...]
(stdin, ICANON, and ECHO can be in the read-only .text section, because they're just used as constants - i.e. we don't write to those bits of memory.)
Having made these changes:
$ ./my_load2
$
The program runs and exits normally.

nasm calling subroutine from another file

I'm doing a project that attaches a subroutine that I wrote to a main file included by the teacher. He gave us the instructions for making our subroutine global but apparently I'm an idiot. The two asm files are in the same folder, I'm using nasm -f elf -g prt_dec.asm and ld prt_dec and then doing the same for main.asm. Here's the relevant code in the main.asm:
SECTION .text ; Code section.
global _start ; let loader see entry point
extern prt_dec
_start:
mov ebx, 17
mov edx, 214123
mov edi, 2223187809
mov ebp, 1555544444
mov eax, dword 0x0
call prt_dec
call prt_lf
The line call prt_dec throws "undefined reference to prt_dec" when i use ld main.o
Here's the a code segment from my prt_dec.asm:
Section .text
global prt_dec
global _start
start:
prt_dec:
(pushing some stuff)
L1_top:
(code continues)
You want to call a routine in another asm file or object file?
if you are Assembling prt_dec.asm and are linking multiple asm files to use in your main program, here is a sample, 2 asm files Assembled and linked together... * NOTE * hello.asm *DOES NOT * have a start label!
Main asm file: hellothere.asm
sys_exit equ 1
extern Hello
global _start
section .text
_start:
call Hello
mov eax, sys_exit
xor ebx, ebx
int 80H
Second asm file: hello.asm
sys_write equ 4
stdout equ 1
global Hello
section .data
szHello db "Hello", 10
Hello_Len equ ($ - szHello)
section .text
Hello:
mov edx, Hello_Len
mov ecx, szHello
mov eax, sys_write
mov ebx, stdout
int 80H
ret
makefile:
APP = hellothere
$(APP): $(APP).o hello.o
ld -o $(APP) $(APP).o hello.o
$(APP).o: $(APP).asm
nasm -f elf $(APP).asm
hello.o: hello.asm
nasm -f elf hello.asm
Now, if you just want to separate your code into multiple asm files, you can include them into your main source: with %include "asmfile.asm" at the beginning of your main source file and just assemble and link your main file.

How to open a file in assembler and modify it?

I'm starting to learn Assembler and I'm working in Unix. I want to open a file and write 'Hello world' on it.
section .data
textoutput db 'Hello world!', 10
lentext equ $ - textoutput
filetoopen db 'hi.txt'
section .text
global _start
_start:
mov eax, 5 ;open
mov ebx, filetoopen
mov ecx, 2 ;read and write mode
int 80h
mov eax, 4
mov ebx, filetoopen ;I'm not sure what do i have to put here, what is the "file descriptor"?
mov ecx, textoutput
mov edx, lentext
mov eax, 1
mov ebx, 0
int 80h ; finish without errors
But when I compile it, it doesn't do anything. What am I doing wrong?
When I open a file where does the file descriptor value return to?
This is x86 Linux (x86 is not the only assembly language, and Linux is not the only Unix!)...
section .data
textoutput db 'Hello world!', 10
lentext equ $ - textoutput
filetoopen db 'hi.txt'
The filename string requires a 0-byte terminator: filetoopen db 'hi.txt', 0
section .text
global _start
_start:
mov eax, 5 ;open
mov ebx, filetoopen
mov ecx, 2 ;read and write mode
2 is the O_RDWR flag for the open syscall. If you want the file to be created if it doesn't already exist, you will need the O_CREAT flag as well; and if you specify O_CREAT, you need a third argument which is the permissions mode for the file. If you poke around in the C headers, you'll find that O_CREAT is defined as 0100 - beware of the leading zero: this is an octal constant! You can write octal constants in nasm using the o suffix.
So you need something like mov ecx, 0102o to get the right flags and mov edx, 0666o to set the permssions.
int 80h
The return code from a syscall is passed in eax. Here, this will be the file descriptor (if the open succeeded) or a small negative number, which is a negative errno code (e.g. -1 for EPERM). Note that the convention for returning error codes from a raw syscall is not quite the same as the C syscall wrappers (which generally return -1 and set errno in the case of an error)...
mov eax, 4
mov ebx, filetoopen ;I'm not sure what do i have to put here, what is the "file descriptor"?
...so here you need to mov ebx, eax first (to save the open result before eax is overwritten) then mov eax, 4. (You might want to think about checking that the result was positive first, and handling the failure to open in some way if it isn't.)
mov ecx, textoutput
mov edx, lentext
Missing int 80h here.
mov eax, 1
mov ebx, 0
int 80h ; finish without errors
Did you read the Linux Assembly HOWTO? It covers your question.
You can also compile some C code with gcc -S -fverbose-asm -O1 and look at the generated assembly. For example, with foo.c, run gcc -S -Wall -fverbose-asm -O1 foo.c (as a command in some terminal) then look (using some editor -perhaps GNU emacs) into the generated foo.s assembler file.
At last, I don't think it is worth bothering a lot about assembler. In 2020, a recent GCC compiler will surely generate better code than what you could write (if you invoke it with optimizations, at least -O2). See this draft report for more.
This is a x64 Linux sample
; Program to open and write to file
; Compile with:
; nasm -f elf64 -o writeToFile64.o writeToFile64.asm
; Link with:
; ld -m elf_x86_64 -o writeToFile64 writeToFile64.o
; Run with:
; ./writeToFile64
;==============================================================================
; Author : Rommel Samanez
;==============================================================================
global _start
%include 'basicFunctions.asm'
section .data
fileName: db "testFile.txt",0
fileFlags: dq 0102o ; create file + read and write mode
fileMode: dq 00600o ; user has read write permission
fileDescriptor: dq 0
section .rodata ; read only data section
msg1: db "Write this message to the test File.",0ah,0
msglen equ $ - msg1
msg2: db "File Descriptor=",0
section .text
_start:
mov rax,2 ; sys_open
mov rdi,fileName ; const char *filename
mov rsi,[fileFlags] ; int flags
mov rdx,[fileMode] ; int mode
syscall
mov [fileDescriptor],rax
mov rsi,msg2
call print
mov rax,[fileDescriptor]
call printnumber
call printnewline
; write a message to the created file
mov rax,1 ; sys_write
mov rdi,[fileDescriptor]
mov rsi,msg1
mov rdx,msglen
syscall
; close file Descriptor
mov rax,3 ; sys_close
mov rdi,[fileDescriptor]
syscall
call exit
It depends what assembler you are using and if you expect to be using the C runtime or not. In this case which appears to be the Hello World text example from rosettacode they are using nasm. Given you have a _start field you are not needing the C runtime so you assemble this to an elf object file and link it into a program:
nasm -felf hello.asm
ld hello.o -o hello
Now you can run the hello program.
A slightly more portable example that uses the C runtime to do the work rather than linux syscalls might look like the sample below. If you link this as described it can use printf to do the printing.
;;; helloworld.asm -
;;;
;;; NASM code for Windows using the C runtime library
;;;
;;; For windows - change printf to _printf and then:
;;; nasm -fwin32 helloworld.asm
;;; link -subsystem:console -out:helloworld.exe -nodefaultlib -entry:main
;;; helloworld.obj msvcrt.lib
;;; For gcc (linux, unix etc):
;;; nasm -felf helloworld.asm
;;; gcc -o helloworld helloworld.o
extern printf
section .data
message:
db 'Hello, World', 10, 0
section .text
global main
main:
push dword message ; push function parameters
call printf ; call C library function
add esp, 4 ; clean up the stack
mov eax, 0 ; exit code 0
ret
For information about file descriptors - read the open(2) manual page or look at wikipedia. It is how posix refers to an open i/o stream. In your case, stdout.

Resources