nasm, read syscall reads over buffer size - linux

I have the following code. It works ok except one thing which limits its usage in other programs. When I run it in the debugger, Linux read system call returns value always bigger than the specified buffer size. Why is it and how to fix it, because it doesn't let the program to loop through the buffer array without a segmentation fault?
SECTION .data
address dd "log.txt", 0
badf dd "Bad file!",0
buffsize dd 1024
size dd 1024
filedesc dd 0
section .bss
buf resb 1024
SECTION .text
global main
main:
mov ebx, address
mov eax, 5 ; open(
mov ecx, 0 ; read-only mode
int 80h ; );
mov [filedesc], eax
read_loop:
mov ebx, [filedesc] ; file_descriptor,
mov eax, 3 ; read(
mov ecx, buf ; *buf,
mov edx, buffsize ; *bufsize
int 80h ; );
test eax, eax
jz done
js badfile
mov eax, 4 ; write(
mov ebx, 1 ; STDOUT,
mov edx, buffsize
mov ecx, buf ; *buf
int 80h
jmp read_loop
badfile:
mov eax, 4 ; write(
mov ebx, 1 ; STDOUT,
mov edx, 10
mov ecx, badf ; *buf
int 80h
done:
mov eax, 6
mov ebx, [filedesc]
int 0x80
mov ebx,0
mov eax,1
int 0x80

mov edx, buffsize ; *bufsize
Is wrong since buffsize is declared as follows:
buffsize dd 1024
the above code will move the address of buffsize to edx. What you want is:
mov edx, [buffsize]
which will move the value stored at buffsize to edx.
You have a few of those type of errors in there.

Could it be a negative error return code?
I don't see any test in your code for negative values.

Related

How do I use a BSS var to move string into register NASM

I'm trying to move a string into a BSS var, I've tried various methods but I have a feeling that unless I hardcode the string or use a read to grab the string I'm fighting a futile battle, the problem I'm having is although I can get the text data into the right register more data accompanies it which trashes the output and some how trashes the value of vdlen (if I directly assign a value to ecx in WriteFile the proper length is put however attempting to use vdlen causes it to way off radar)
How do I get the right results (ie "Hello!" in "text.txt") ?
section .bss
vdata resw 10
vdlen resb 3
vfd resb 1
vfn resb 15
err resb 2
section .text
mov eax,vfn
mov dword [eax],'test'
mov dword [eax+3], '.txt'
mov ebx,vdata
mov dword [ebx], 'Hell'
mov dword [ebx+3],'o!'
mov ecx,vdlen
mov [ecx], 0x03h
jmp WriteFile
ProgramEnd:
mov eax,1
mov ebx,[err]
int 80h
WriteFile:
mov eax,5 ;Syscall for open()
mov ebx,vfn
mov ecx, 65 ; mode Write-only Create
mov edx, 420 ; permissions rw-r-r
int 80h ; Linux Kernel Interrupt
mov [vfd],eax ; get file descriptor
mov eax,4 ;Syscall for write()
mov ebx,[vfd] ; FD argument
mov ecx,[vdata] ; this is where my issue is
mov edx,[vdlen] ; length of vdata
int 80h
mov [err],eax
jmp ProgramEnd
After the extremely helpful advice provided by rkbh and MikeCat to the OP, the OP got it working:
section .bss
vfd resb 5
vfn resb 15
vdlen resb 5
vdata resw 10
section .text
global _start
_start:
mov eax,vfn
mov dword [eax],'test'
mov dword [eax+4],'.txt'
mov ebx,vdata
mov dword [vdata], 'Hell'
mov dword [vdata+4],0 ;nullbyte ?
mov word [vdlen],4
jmp WriteFile
ProgramEnd:
mov eax,1
mov ebx,[err]
int 80h
WriteFile:
mov eax,5 ; open syscall
mov ebx,vfn
mov ecx, 65 ; Write Only, Create Only File Mode
mov edx, 420 ; ugo: RW-R-R
int 80h
mov [vfd],eax
mov eax,4
mov ebx,[vfd]
mov ecx,vdata
mov edx,[vdlen]
int 80h
mov byte [err],0 ;this essentially does nothing since write()
;returns the number of bytes written so I can't actually get an
;error code unless I want to check for err == 0 or
;err >= expectedWriteSize
jmp ProgramEnd
TL;DR: OP was trying to cram 6 bytes into 4 bytes using DWORD MOV's and had mis-specified the size for vdlen.

File permissions in Linux assembly

I'm trying to get information about file permissions. I am using the sys_access system call. Here is my code snippet:
mov eax, 33
mov ebx, fileName
mov ecx, 1
int 80h
cmp eax, 0
jl .error
If eax is -1 there is an error, and I am not getting one, but I need to check all the permissions of the file (owner, group, others). How do I do that?
You can use the kernel function sys_newstat (No. 106 - look at this table) to get the file permissions. The structure stat is a never ending horror, but the following example works at least on my Debian Wheezy 64 bit (NASM, 32-bit and 64-bit modes):
SECTION .data
filename db '/root' ; Just an example, can be replaced with any name
filename_len equ $ - filename ; Length of filename
db 0 ; Terminator for `Int 80h / EAX = 106`
perm_out db 'Permissions: '
perm db 'drwxrwxrwx'
perm_len equ $ - perm ; Index of last character in `perm`
lf db 10
perm_out_len equ $ - perm_out ; Length of `Permissions: ...\n`
SECTION .bss
stat resb 256 ; Way too much, but size is variable depending on OS
SECTION .text
global _start
_start:
mov eax,4 ; sys-out
mov edx,filename_len ; length of string to print
mov ecx,filename ; Pointer to string
mov ebx,1 ; StdOut
int 0x80 ; Call kernel
mov eax,4 ; sys-out
mov edx,1 ; Length of string to print
mov ecx, lf ; Pointer to string
mov ebx,1 ; StdOut
int 0x80 ; Call kernel
mov eax, 106 ; sys_newstat
mov ebx, filename ; Pointer to ASCIIZ file-name
mov ecx, stat ; Pointer to structure stat
int 80h
test eax, eax
jz .noerr
mov eax,1 ; sys_exit
mov ebx,1 ; Exit code, 1=not normal
int 0x80 ; Call kernel
.noerr:
movzx eax, word [stat + 8] ; st_mode (/usr/include/asm/stat.h)
mov ebx, perm_len
; rwx bits
mov ecx, 9
.L1:
sub ebx, 1
shr eax, 1
jc .J1
mov byte [perm + ebx], '-'
.J1:
loop .L1
; directory bit
sub ebx, 1
shr eax, 6
jc .J2
mov byte [perm + ebx], '-'
.J2:
mov eax,4 ; sys-out
mov edx,perm_out_len ; Length of string to print
mov ecx,perm_out ; Pointer to string
mov ebx,1 ; StdOut
int 0x80 ; Call kernel
mov eax,1 ; sys_exit
mov ebx,0 ; Exit code, 0=normal
int 0x80 ; Call kernel

NASM, read a file and print the content

I have this piece of code in NASM (for linux) that supposed to open an existing file, read it and print the content on the screen, but does not work, can someone tell me what am I doing wrong?(hello.txt is the name of the file)
section .data
file db "./hello.txt", 0
len equ 1024
section .bss
buffer: resb 1024
section .text
global _start
_start:
mov ebx, [file] ; name of the file
mov eax, 5
mov ecx, 0
int 80h
mov eax, 3
mov ebx, eax
mov ecx, buffer
mov edx, len
int 80h
mov eax, 4
mov ebx, 1
mov ecx, buffer
mov edx, len
int 80h
mov eax, 6
int 80h
mov eax, 1
mov ebx, 0
int 80h
mov ebx, [file] ; name of the file
mov eax, 5
mov ecx, 0
int 80h
Is wrong. Loose the square brackets around file. You are passing the file name instead of a pointer to the filename.
mov ebx, file ; const char *filename
mov eax, 5
mov ecx, 0
int 80h
I see here a lot of mistakes, in order:
mov ebx, [file] ; name of the file
mov eax, 5
mov ecx, 0
int 80h
Here, as said, u must lose square brackets (because the function needs a pointer, not a value)
mov eax, 3
mov ebx, eax
mov ecx, buffer
mov edx, len
int 80h
Here, u must save the file descriptor from eax, before writing there value 3, else u just loose it
mov eax, 4
mov ebx, 1
mov ecx, buffer
mov edx, len
int 80h
Well. Here u using ebx register, so better way is to save file descriptor in memory. And for display, you take 1024 bytes from buffer, which is not correct. After reading from the file, the eax register will contain the number of characters read, so after reading from the file it will be better to store the value from the eax register in edx
mov eax, 6
int 80h
Again. U close the file, but ebx contains dirt, although it must contain a file descriptor
Correct code must look like this:
section .data
file db "text.txt",0 ;filename ends with '\0' byte
section .bss
descriptor resb 4 ;memory for storing descriptor
buffer resb 1024
len equ 1024
section .start
global _start
_start:
mov eax,5 ;open
mov ebx,file ;filename
mov ecx,0 ;read only
int 80h ;open filename for read only
mov [descriptor],eax ;storing the descriptor
mov eax,3 ;read from file
mov ebx,[descriptor] ;your file descriptor
mov ecx,buffer ;read to buffer
mov edx,len ;read len bytes
int 80h ;read len bytes to buffer from file
mov edx,eax ;storing count of readed bytes to edx
mov eax,4 ;write to file
mov ebx,1 ;terminal
mov ecx,buffer ;from buffer
int 80h ;write to terminal all readed bytes from buffer
mov eax,6 ;close file
mov ebx,[descriptor] ;your file descriptor
int 80h ;close your file
mov eax,1
mov ebx,0
int 80h
This is not a perfect code, but it should work

NASM loop over bytes

Currently I'm trying to loop over every single byte in a buffer (read from a file) and compare it to see if any of them is a whitespace, and write them to STDOUT. For some reason the program compiles and runs fine, but produces zero output.
section .data
bufsize dw 1024
section .bss
buf resb 1024
section .text
global _start
_start:
; open the file provided form cli in read mode
mov edi, 0
pop ebx
pop ebx
pop ebx
mov eax, 5
mov ecx, 0
int 80h
; write the contents in to the buffer 'buf'
mov eax, 3
mov ebx, eax
mov ecx, buf
mov edx, bufsize
int 80h
; write the value at buf+edi to STDOUT
mov eax, 4
mov ebx, 1
mov ecx, [buf+edi]
mov edx, 1
int 80h
; if not equal to whitespace, jump to the loop
cmp byte [buf+edi], 0x20
jne loop
loop:
; increment the loop counter
add edi, 1
mov eax, 4
mov ebx, 1
mov ecx, [buf+edi]
int 80h
; compare the value at buf+edi with the HEX for whitespace
cmp byte [buf+edi], 0x20
jne loop
; exit the program
mov eax, 1
mov ebx, 0
int 80h
The main problem was that I didn't given the address of bufsize ([bufsize]), also the loops had some problems.
Here's the fixed version, thanks everyone for your input.
section .data
bufsize dd 1024
section .bss
buf: resb 1024
section .text
global _start
_start:
; open the file provided form cli in read mode
mov edi, 0
pop ebx
pop ebx
pop ebx
mov eax, 5
mov ecx, 0
int 80h
; write the contents in to the buffer 'buf'
mov eax, 3
mov ebx, eax
mov ecx, buf
mov edx, [bufsize]
int 80h
; write the value at buf+edi to STDOUT
; if equal to whitespace, done
loop:
cmp byte [buf+edi], 0x20
je done
mov eax, 4
mov ebx, 1
lea ecx, [buf+edi]
mov edx, 1
int 80h
; increment the loop counter
add edi, 1
jmp loop
done:
; exit the program
mov eax, 1
mov ebx, 0
int 80h

NASM Linux Assembly Printing Integers

I am trying to print a single digit integer in nasm assembly on linux. What I currently have compiles fine, but nothing is being written to the screen. Can anyone explain to me what I am doing wrong here?
section .text
global _start
_start:
mov ecx, 1 ; stores 1 in rcx
add edx, ecx ; stores ecx in edx
add edx, 30h ; gets the ascii value in edx
mov ecx, edx ; ascii value is now in ecx
jmp write ; jumps to write
write:
mov eax, ecx ; moves ecx to eax for writing
mov eax, 4 ; sys call for write
mov ebx, 1 ; stdout
int 80h ; call kernel
mov eax,1 ; system exit
mov ebx,0 ; exit 0
int 80h ; call the kernel again
This is adding, not storing:
add edx, ecx ; stores ecx in edx
This copies ecx to eax and then overwrites it with 4:
mov eax, ecx ; moves ecx to eax for writing
mov eax, 4 ; sys call for write
EDIT:
For a 'write' system call:
eax = 4
ebx = file descriptor (1 = screen)
ecx = address of string
edx = length of string
After reviewing the other two answers this is what I finally came up with.
sys_exit equ 1
sys_write equ 4
stdout equ 1
section .bss
outputBuffer resb 4
section .text
global _start
_start:
mov ecx, 1 ; Number 1
add ecx, 0x30 ; Add 30 hex for ascii
mov [outputBuffer], ecx ; Save number in buffer
mov ecx, outputBuffer ; Store address of outputBuffer in ecx
mov eax, sys_write ; sys_write
mov ebx, stdout ; to STDOUT
mov edx, 1 ; length = one byte
int 0x80 ; Call the kernel
mov eax, sys_exit ; system exit
mov ebx, 0 ; exit 0
int 0x80 ; call the kernel again
From man 2 write
ssize_t write(int fd, const void *buf, size_t count);
In addition to the other errors that have been pointed out, write() takes a pointer to the data and a length, not an actual byte itself in a register as you are trying to provide.
So you will have to store your data from a register to memory and use that address (or if it's constant as it currently is, don't load the data into a register but load its address instead).

Resources