NASM - How can I solve the input reading problem from the terminal? [duplicate] - linux

This question already has answers here:
Read STDIN using syscall READ in Linux: unconsumed input is sent to bash
(2 answers)
Closed 4 months ago.
section .data
yourinputis db "your input is =",0
len equ $ - yourinputis
section .bss
msginput resb 10
section .text
global _start
_start:
mov eax,3 ;read syscall
mov ebx,2
mov ecx,msginput
mov edx,9 ; I don't know that is correct?
int 80h
mov eax,4 ;write syscall
mov ebx,1
mov ecx,yourinputis
mov edx,len
int 80h
mov eax,4 ;write syscall
mov ebx,1
mov ecx,msginput
mov edx,10
int 80h
exit:
mov eax,1 ;exit syscall
xor ebx,ebx
int 80h
This code working very well. But It is so terrible bug(for me:(). If I enter an input longer than 10 --->
$./mycode
012345678rm mycode
your input is 012345678$rm mycode
$
This is happening. And of course "mycode" is not exist right now.
What should I do?
EDIT:The entered input is correctly printed on the screen. But if you enter a long input, it moves after the 9th character to the shell and runs it.
In the example, the "rm mycode" after "012345678" is running in the shell.

If you enter more than 9 characters, they're left in the terminal driver's input buffer. When the program exits, the shell reads from the terminal and tries to execute the rest of the line as a command.
To prevent this, your program should keep reading in a loop until it gets a newline.

You can read the characters one by one until you reach 0x0a. Something like:
_read:
mov esi, msginput
_loop:
mov eax,3 ;read syscall
mov ebx,0
mov ecx, esi
mov edx,1 ; I don't know that is correct?
int 80h
cmp byte[esi], 0x0a
je end
inc esi
jmp _loop
end:
ret
You would have to increase the size of msginput tho.
IMPORTANT: Do note that this is not the efficient way to do this (see the comments), it is only put here as an example to the answer above.

Related

Linux NASM - Drain Terminal Input Without Prompt [duplicate]

This question already has answers here:
How do I discard user input delivered during sleep function?
(3 answers)
Prevent reading of previous / prior user keyboard input from sys.stdin, that works with Click
(1 answer)
Closed 2 years ago.
I want to drain terminal input before prompting the user, or otherwise to close the terminal input until I want to prompt the user for input.
I am writing a program that uses sys_read to prompt the user for input through the terminal. If a user types characters before being prompted, those characters get included in the input. I can easily drain every unread character after the prompt using sys_read again, but it relies on a return character being at the end of the stream of input to prevent prompting the user more than once (I am assuming the user ends every prompt with the return key). I can't rely on the presence of a return character before the prompt, so I can't drain the input the same way.
I have also tried closing stdin with sys_close, but I can't figure out how to open terminal input again, so the program is left frozen when a prompt comes up. Even if I could open the terminal input again, I'm not sure whether or not characters typed while it's closed still get saved for the next time it's read, which would render this approach completely useless.
If there is some sort of obscure termios flag that could disable user input, that would also be an excellent solution.
Here's a program, for example:
global _start
_start:
mov edx,ldot
mov ecx,mdot
mov ebx,1
mov eax,4 ; sys_write
int 0x80
mov dword[sleep_sec],1
mov dword[sleep_usec],0
mov ecx,0
mov ebx,sleep
mov eax,162 ; sys_nanosleep
int 0x80
mov edx,ldesire
mov ecx,mdesire
mov ebx,1
mov eax,4 ; sys_write
int 0x80
call input ; here's the call...
mov edx,lreceive
mov ecx,mreceive
mov ebx,1
mov eax,4 ; sys_write
int 0x80
mov dword[sleep_sec],1
mov dword[sleep_usec],0
mov ecx,0
mov ebx,sleep
mov eax,162 ; sys_nanosleep
int 0x80
mov edx,99
mov ecx,inputed
mov ebx,1
mov eax,4 ; sys_write
int 0x80
mov eax,1 ; sys_exit
int 0x80 ; the end!
input: ; here is all that I am concerned about
mov edx,99
mov ecx,inputed
mov ebx,0 ; stdin
mov eax,3 ; sys_read
int 0x80
cmp eax,99 ; check for valid input
jl inputdone
cmp byte[inputed+98],0xa
je inputdone
inputclear: ; drain
mov eax,3
int 0x80
cmp eax,99
jl inputerror
cmp byte[inputed+98],0xa
je inputerror
jmp inputclear
inputerror:
mov eax,-1
ret
inputdone:
mov eax,1
ret
section .bss
inputed resb 99
section .data
sleep:
sleep_sec dd 0
sleep_usec dd 0
mdot db '...',0xA
ldot equ $ - mdot
mdesire db 'tell me your truest desire:'
ldesire equ $ - mdesire
mreceive db 'you shall receive... '
lreceive equ $ - mreceive
A user who does things when they are told will find no trouble:
...
tell me your truest desire:money
you shall receive... money
But a user who likes to press buttons as they please will struggle:
...
a gtell me your truest desire:love
you shall receive... a glove
And the program won't wait for anyone who makes a mess with the return key:
...
who
tell me your truest desire:you shall receive... who

Linux NASM - Hiding Terminal Input [duplicate]

This question already has answers here:
How do i read single character input from keyboard using nasm (assembly) under ubuntu?
(3 answers)
Reading input from keyboard with x64 linux syscalls (assembly)
(1 answer)
How to stop echo in terminal using c?
(1 answer)
Closed 2 years ago.
Is there a way to disable and enable the display of terminal input within an assembly program?
I am writing a command line program in nasm where user input it periodically read from the terminal (which I want to be displayed) and the program sleeps for certain lengths of time. During that time (unlike what I've found in the Windows command line) the user is still able to type in the terminal. I want to hide that text.
Here's a program that asks for a prompt and waits between certain message:
section .text
global _start
_start:
mov edx,lhello
mov ecx,mhello
mov ebx,1
mov eax,4 ; sys_write
int 0x80
mov dword[sleep_sec],1
mov dword[sleep_usec],0
mov ecx,0
mov ebx,sleep
mov eax,162 ; sys_nanosleep
int 0x80
mov edx,lwrite
mov ecx,mwrite
mov ebx,1
mov eax,4 ; sys_write
int 0x80
mov edx,99
mov ecx,usergift
mov ebx,0
mov eax,3 ; sys_read
int 0x80
mov edx,lsleep
mov ecx,msleep
mov ebx,1
mov eax,4 ; sys_write
int 0x80
mov dword[sleep_sec],2
mov dword[sleep_usec],0
mov ecx,0
mov ebx,sleep
mov eax,162 ; sys_nanosleep
int 0x80
mov edx,ldone
mov ecx,mdone
mov ebx,1
mov eax,4 ; sys_write
int 0x80
mov eax,1 ; sys_exit
int 0x80 ; the end!
section .bss
usergift resb 99
section .data
sleep:
sleep_sec dd 0
sleep_usec dd 0
mhello db 'hello-',0xA
lhello equ $ - mhello
mwrite db 'give me something:'
lwrite equ $ - mwrite
msleep db 'wait for 2 seconds...',0xA
lsleep equ $ - msleep
mdone db 'thank you.',0xA
ldone equ $ - mdone
gives the following output when love is inputted by the user when prompted-
hello-
give me something:love
wait for 2 seconds...
thank you.
but the user is also able to write outside of the prompt-
hello-
ha!give me something:love
wait for 2 seconds...
lies!thank you.

How to take a string as a input in Assembly x64

I am writing a program to check if a string is Palindrome or not. I want to take a string as input from user. The string can contain any character ranging from digits to special characters. How can I take input from user. I have tried the following code.
global _start
section .bss
string resb 9
section .text
_start:
mov rax,0 ;Am I doing this correct ?
mov rdi,0
mov rsi,string
mov rdx,8
syscall
xor rax,rax
mov rdx,[string]
mov rax,1
mov rdi,1
mov rsi,rdx
mov rdx,8
syscall
mov rax,0
mov rdi,0
syscall
Is the above code correct because when I output the string it shows segmentation fault. The error is
Segmentation fault (core dumped)
I am coding in nasm in Linux(Ubuntu 14.04)
For printing you also need to pass the address so mov rdx, [string] is wrong, you need mov rdx, string or lea rdx, [string]. Also, your final syscall is wrong, because that's a read again. You probably want mov rax, 60 to make it exit.
See, that's why you should post a Minimal, Complete, and Verifiable example.
Usually Linux requires you to use the exit
mov rax, 60
xor rdi, rdi
syscall

A loop in assembly doesn't work why?

i have problem. I tried build a loop in assembly (nasm,linux). The loop should "cout" number 0 - 10, but it not work and i don't know why. Here is a code :
section .text
global _start
_start:
xor esi,esi
_ccout:
cmp esi,10
jnl _end
inc esi
mov eax,4
mov ebx,1
mov ecx,esi
mov edx,2
int 80h
jmp _ccout
_end:
mov eax,1
int 80h
section .data
Well, the loop is working, but you aren't using the syscall correctly. There are some magic numbers involved here, so let's get that out of the way first:
4 is the syscall number for write
1 is the file descriptor for the standard output
So far, so good. write requires a file descriptor, the address of a buffer and the length of that buffer or the part of it that it's supposed to write to the file descriptor. So, the way this is supposed to look is similar to
mov eax,4 ; write syscall
mov ebx,1 ; stdout
mov ecx,somewhere_in_memory ; buffer
mov edx,1 ; one byte at a time
compare that to your code:
mov eax,4
mov ebx,1
mov ecx,esi ; <-- particularly here
mov edx,2
int 80h
What you are doing there (apart from passing the wrong length) is passing the contents of esi to write as a memory address from which to read the stuff it's supposed to write to stdout. By pure happenstance this doesn't crash, but there's no useful data at that position in memory.
In order to solve this, you will need a location in memory to put it. Moreover, since write works on characters, not numbers, you'll have to to the formatting yourself by adding '0' (which is 48 in ASCII). All in all, it could look something like this:
section .data
text db 0 ; text is a byte in memory
section .text
global _start
_start:
xor esi,esi
_ccout:
cmp esi,10
jnl _end
inc esi
lea eax,['0'+esi] ; print '0' + esi. lea == load effective address
mov [text],al ; is useful here even though we're not really working on addresses
mov eax,4 ; write
mov ebx,1 ; to fd 1 (stdout)
mov ecx,text ; from address text
mov edx,1 ; 1 byte
int 80h
jmp _ccout
_end:
mov [text],byte 10 ; 10 == newline
mov eax,4 ; write that
mov ebx,1 ; like before.
mov ecx,text
mov edx,1
int 80h
mov eax,1
mov ebx,0
int 80h
The output 123456789: is probably not exactly what you want, but you should be able to take it from here. Exercise for the reader and all that.

unable to read from file when user provides filename (x86 assembly program using nasm)

I'm having a problem trying to open a file and read from it. The user is prompted for the file name.
The program compiles without error but doesn't show anything. When I hardcode the filename in the .data section it runs fine, but when I get the filename from the user it fails to read the file. Where am I doing wrong? I can't find any error.
Output using hardcoded name: welcome
Output when user enters the name: ���
Here is my code:
section .data
promptUsr db 'enter a file name:',0xA,0xD
lenPrompt equ $-promptUsr
info db 1
;file_name db 'data.txt' (NOTE:harcoded name works when used)
section .bss
fd_in resb 1
buffer resb 7
file_name resb 20
section .text
global _start
_start:
;prompt user to enter a file name
mov eax,4 ;sys_write
mov ebx,1 ;stdout
mov ecx,promptUsr
mov edx,lenPrompt
int 0x80
;read filename (NOTE:when user enters the same name 'data.txt',this is the output:���)
mov eax,3
mov ebx,2
mov ecx,file_name ;(NOTE:tried using 'dword[file_name]',doesnt work)
mov edx,20
int 0x80
;open file
mov eax,5
mov ebx,file_name ;(NOTE:also tried using 'dword[file_name]',doesnt work too)
mov ecx,2 ;read n write
mov edx,7777h ;all file permissions
int 0x80
mov [fd_in],eax
;read 7 bytes of the file
mov eax,3
mov ebx,[fd_in]
mov ecx,buffer
mov edx,7
int 0x80
;close the file
mov eax,6
int 0x80
;print out what was read
mov eax,4
mov ebx,1
mov ecx,buffer
mov edx,7
int 0x80
;end program
mov eax,1
int 0x80
To add to what Michael says... 1) fd_in is too small - make it resd 1. 2) sys_read doesn't return a zero-terminated string, and sys_open wants one.
mov byte [ecx + eax - 1], 0
after the sys_read of the filename should zero-terminate it.
Looks like you're trying to read from STDERR:
mov eax,3
mov ebx,2
mov ecx,file_name ;(NOTE:tried using 'dword[file_name]',doesnt work)
mov edx,20
That mov ebx,2 ought to be mov ebx,0 if you want to read from STDIN.
would also love to know how to check first if the file exists before opening it
If you use sys_open without the O_CREAT flag set, it should fail and return -1 if the file doesn't already exist. You could also use access (syscall 33) or stat (syscall 18) if you want to.

Resources