Recently, I wrote a bit of assembly code that asks for the password and if the user enters the correct password as stored internally, it prints out "Correct!". Else, it prints out "Incorrect!".
Here is the code:
section .text
global _start
_start:
mov edx, len_whatis
mov ecx, whatis
mov ebx, 1
mov eax, 4
int 80h ; outputs: "What is the password?"
mov edx, 5 ; expect 5 bytes of input(so 4 numbers)
mov ecx, pass
mov ebx, 0
mov eax, 3
int 80h ; accepts intput and stores in pass
mov eax, [pass] ; move the pass variable into eax
sub eax, '0' ; change the ascii number in eax to a numerical number
mov ebx, [thepass] ; move the thepass variable into ebx
sub ebx, '0' ; change the ascii number in ebx to a numerical number
cmp eax, ebx ; compare the 2 numbers
je correct ; if they are equal, jump to correct
jmp incorrect ; if not, jump to incorrect
correct:
mov edx, len_corr
mov ecx, corr
mov ebx, 1
mov eax, 4
int 80h ; outputs: "Correct!"
mov ebx, 0
mov eax, 1
int 80h ; exits with status 0
incorrect:
mov edx, len_incor
mov ecx, incor
mov ebx, 1
mov eax, 4
int 80h ; outputs: "Incorrect!"
mov eax, 1
int 80h ; exits with status: 1
section .data
whatis db "What is the password?", 0xA
len_whatis equ $ - whatis
thepass db "12345"
corr db "Correct!", 0xA
len_corr equ $ - corr
incor db "Incorrect!", 0xA
len_incor equ $ - incor
section .bss
pass resb 5
Assemble:nasm -f elf password.s
Link:ld -m elf_i386 -s -o password password.o
(If you did try to assemble link and run this, you may notice that it checks the password incorrectly - ignore this. It is "off topic")
Then, I ran a test:
I ran the code with ./password
When I was prompted for the password, I typed in 123456, one more byte than the code expects
After I hit enter and the code exits, the terminal immediately tries to run a command 6
What is causing this behavior? Is it something to do with the assembler, or how my computer is reading the code?
EDIT:
And, when I run the code with 12345, the terminal prompts for a command twice when the program closes, as if someone just hit the enter button without entering a command.
You're only reading five bytes from standard input, so when you type 123456↵, your application ends up reading 12345 and leaving 6↵ in the buffer. That gets passed on to the shell.
If you want to read the whole line, use a larger buffer.
Related
THE PROGRAM IS USED TO ACCEPT CHARACTERS AND DISPLAY THEM IN REVERSE ORDER
The code is included here:
section .bss
num resb 1
section .text
global _start
_start:
call inputkey
call outputkey
;Output the number entered
mov eax, 1
mov ebx, 0
int 80h
inputkey:
;Read and store the user input
mov eax, 3
mov ebx, 2
mov ecx, num
mov edx, 1
int 80h
cmp ecx, 1Ch
je .sub2
push ecx
jmp inputkey
.sub2:
push ecx
ret
outputkey:
pop ecx
;Output the message
mov eax, 4
mov ebx, 1
;mov ecx, num
mov edx, 1
int 80h
cmp ecx, 1Ch
je .sub1
jmp outputkey
.sub1:
ret
The code to compile and run the program
logic.asm
is given here:
nasm -f elf logic.asm
ld -m elf_i386 -s -o logic logic.o
./logic
There are a few problems with the code. Firstly, for the sys_read syscall (eax = 3) you supplied 2 as the file descriptor, however 2 refers to stderr, but in this case you'd want stdin, which is 0 (I like to remember it as the non-zero numbers 1 and 2 being the output).
Next, an important thing to realize about the ret instruction is that it pops the value off the top of the stack and returns to it (treating it as an address). Meaning that even if you got to the .sub2 label, you'd likely get a segfault. With this in mind, the stack also tends to not be permanent storage, as in it is not preserved throughout procedures, so I'd recommend just making your buffer larger to e.g. 256 bytes and increment a value to point to an index in the buffer. (Using a fixed-size buffer will keep you from getting into the complications of memory allocation early, though if you want to go down that route you could do an external malloc call or just an mmap syscall.)
To demonstrate what I mean by an index into the reserved buffer:
section .bss
buf resb 256
; ...
inputkey:
xor esi, esi ; clear esi register, we'll use it as the index
mov eax, 3
mov ebx, 0 ; stdin file descriptor
mov edx, 1 ; read one byte
.l1: ; loop can start here instead of earlier, since the values eax, ebx and edx remain unchanged
lea ecx, [buf+esi] ; load the address of buf + esi
int 80h
cmp [buf+esi], 0x0a ; check for a \n character, meaning the user hit enter
je .e1
inc esi
jmp .l1
.e1:
ret
In this case, we also get to preserve esi up until the output, meaning that to reverse the input, we just print in descending order.
outputkey:
mov eax, 4
mov ebx, 1 ; stdout
mov edx, 1
.l2:
lea ecx, [buf+esi]
int 80h
test esi, esi ; if esi is zero it will set the ZF flag
jz .e2:
jmp .l2
.e2:
ret
Note: I haven't tested this code, so if there are any issues with it let me know.
I'm getting a segmentation fault after writing mov [gtt+4], byte '>' where my variable is defined as gtt: db "I'm ! than 10".
I feel like it might be an error when assembling the program.
I'm using the commands: nasm -f elf file.asm -o file.o, ld -m elf_i386 file.o -o file
I have tried to use elf32 rather than elf but it doesn't make a difference.
The purpose of my program is to loop 2 times, multiplying whatever is in ebx by 2 each time. Afterwards, it will compare if ecx > 10 and displaying the corresponding string. I'm trying to get it to replace the "!" with either "<" or ">".
I'm using Ubuntu, and I'm working in x86 assembly.
Here is my full code snippet:
section .data:
starti: db "Starting value: 1", 0x0a
startil equ $-starti
gtt: db "I'm > than 10!", 0x0a
gttml equ $-gtt
section .text:
_start:
mov eax, 4
mov ebx, 1
mov ecx, starti
mov edx, startil
int 0x80
mov ebx, 1 ; Start value!
mov ecx, 2 ; Number of iterations
label:
add ebx, ebx ; Add 2*ebx
dec ecx ; ecx -= 1
cmp ecx, 0 ; If ecx > 0, loop again
jg label
cmp ebx, 10 ; If cbx > 10, jump to gtt-g
jg gttg
mov [gtt+4], byte '<'
mov eax, 4 ; If cbx < 10, output <
mov ebx, 1
mov ecx, gtt
mov edx, gttml
int 0x80
mov eax, 1 ; Exit gracefully
mov ebx, 0
int 0x80
gttg:
mov [gtt+4], byte '>'
mov eax, 4 ; Display gtt
mov ebx, 1
mov ecx, gtt
mov edx, gttml
int 0x80
mov eax, 1 ; Exit gracefully
mov ebx, 0
int 0x80
Fix
Thanks to Jester for this, "you must not use colons after section names, they are not labels. As it is, the colon is included in the name and hence the assembler doesn't recognize them as standard sections and doesn't apply the expected attributes meaning your data is read only. TL;DR: use section .data and section .text without a trailing".
I am trying to teach myself how to write Assembly in X86 on NASM. I'm attempting to write a program that takes a single integer value and prints it back to standard output before exiting.
My code:
section .data
prompt: db "Enter a number: ", 0
str_length: equ $ - prompt
section .bss
the_number: resw 1
section .text
global _start
_start:
mov eax, 4 ; pass sys_write
mov ebx, 1 ; pass stdout
mov edx, str_length ; pass number of bytes for prompt
mov ecx, prompt ; pass prompt string
int 80h
mov eax, 3 ; sys_read
mov ebx, 0 ; stdin
mov edx, 1 ; number of bytes
mov ecx, [the_number] ; pass input of the_number
int 80h
mov eax, 4
mov ebx, 1
mov edx, 1
mov ecx, [the_number]
int 80h
mov eax, 1 ; exit
mov ebx, 0 ; status 0
int 80h
From there I do the assembling nasm -felf -o input.o input.asm and linking ld -m elf_i386 -o input input.o.
I run a test and input an integer and when I press enter, the program exits and Bash tries to execute the number input as a command. I even echo'd the exit status and been returned with 0.
So this is an odd behavior.
The call to read fails and doesn’t read any input. When your program exits, that input is still waiting to be read on the TTY (which was this program's stdin), at which point bash reads it.
You should check the return status of your system calls. If EAX is a negative number when the system call returns, it is the error code. For example, in this case, EAX contains -14, which is EFAULT (“Bad address”).
The reason read fails is that you are passing an invalid pointer as the buffer address. You need to load the address of the_number, not its value. Use mov ecx, the_number.
This question already has answers here:
X86 NASM Assembly converting lower to upper and upper to lowercase characters
(5 answers)
X86 Assembly Converting lower-case to uppercase
(1 answer)
Closed 3 years ago.
I want to change the string to all caps, although I am having trouble getting the length of the input. What i have tried so far is moving the address of the message into a registrar then indexing through the string and also increment a counter variable. Then comparing the char in the address to a '.' (signifying the end of the message) and if its found not to be equal it will recall this block of statements. At least this is what I want my code to do. Not sure if this is even the right logic. I know there are alot of errors and its messy but I'm learning so please just focus on my main question. thank you! EDIT: the input i use is 'this is a TEST.'
;nasm 2.11.08
SYS_Write equ 4
SYS_Read equ 3
STDIN equ 0
STDOUT equ 1
section .bss
message resb 15
counter resb 2
section .data
msg1: db 'Enter input (with a period) that I will turn into all capitals!',0xa ;msg for input
len1 equ $- msg1
section .text
global _start
_start:
mov eax, SYS_Write ; The system call for write (sys_write)
mov ebx, STDOUT ; File descriptor 1 - standard output
mov ecx, msg1 ; msg to print
mov edx, len1 ; len of message
int 0x80 ; Call the kernel
mov eax, SYS_Read ;system call to read input
mov ebx, STDIN ;file descriptor
mov ecx, message ;variable for input
mov edx, 15 ;size of message
int 0x80 ;kernel call
mov [counter], byte '0'
getLen:
mov eax, message
add eax, [counter]
inc byte [counter]
cmp eax, '.'
jne getLen
mov eax, SYS_Write ; this is to print the counter to make sure it got the right len
mov ebx, STDOUT
mov ecx, counter
mov edx, 2
int 0x80
jmp end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov eax, [message]
;add eax, counter
cmp eax, 90
jg toUpper
toUpper:
sub eax, 32
mov [message], eax
mov eax, SYS_Write ; The system call for write (sys_write)
mov ebx, STDOUT ; File descriptor 1 - standard output
mov ecx, message ; Put the offset of hello in ecx
mov edx, 10 ; helloLen is a constant, so we don't need to say
int 0x80 ; Call the kernel
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
end:
mov eax,1 ; The system call for exit (sys_exit)
mov ebx,0 ; Exit with return code of 0 (no error)
int 0x80 ;
I started learning how to write programs using the NASM assembly programming language. I wrote this simple program that prompts the user to enter two numbers and then adds the two operands together. I got it to compile with no errors or warnings, but when it prompts the user for the two numbers and it begins to add the two numbers it prints out segmentation fault and program ends. I know a segmentation fault is the equivalent to an access reading / writing violation exception in the Win32 world. But, because I don't know how to debug NASM code; I can't figure out what is wrong. I suspect it has to do with an invalid pointer; but I don't know. Here is the code below:
section .data
msg1: db 'Please Enter A Number: ', 0
length1: equ $ - msg1
msg2: db 'Please Enter A Second Number: ', 0
length2: equ $ - msg2
section .bss
operand1: resb 255
operand2: resb 255
answer: resb 255
section .text
global _start
_start:
; Print first message
mov eax, 4
mov ebx, 1
mov ecx, msg1
mov edx, length1
int 80h
; Now read value
mov eax, 3
mov ebx, 1
mov ecx, operand1
mov edx, 255
int 80h
; Print second message
mov eax, 4
mov ebx, 1
mov ecx, msg2
mov edx, length2
int 80h
; Now read second value
mov eax, 3
mov ebx, 1
mov ecx, operand2
mov edx, 255
int 80h
; Now add operand1 and operand2 and print answer
mov eax, 4
mov ebx, 1
xor ecx, ecx ; Make the ecx register 0
mov ecx, operand1
add ecx, operand2
mov edx, 510
int 80h
(Aside: you should be reading from STDIN_FILENO = 0, not STDOUT_FILENO = 1. Also, you're writing a NUL character and you shouldn't.)
The problem is that operand1 and operand2 are addresses to memory locations holding characters you've read. When you add them, you get a pointer to invalid memory.
You'll have to convert them to integers, add them, and convert back to a string, before you can write it out.
Value in ecx is an address of string that is to be printed when you call int 80h. Last part does not make sense
mov eax, 4
mov ebx, 1
xor ecx, ecx ; Make the ecx register 0
mov ecx, operand1
add ecx, operand2 ; **<<< invalid memory address now in ECX !!!**
mov edx, 510
int 80h
because you are adding address of string operand1 and address of string operand2 and trying to print whatever is located ant resulting address which is most likely points to nowhere.
To debug your program with gdb you can do:
nasm -f elf64 -g -l q1.lst q1.asm
gcc -o q1 q1.o
I replaced the "_start" with "main" so that gcc won't complain, and you can skip the 64 in "-f elf64" if you are building on 32 bit platform.
gdb q1
Here is an example f gdb session:
(gdb) br main
Breakpoint 1 at 0x4004d0: file q1.asm, line 20.
(gdb) r
Starting program: /home/anonymous/Projects/asm/q1
Breakpoint 1, main () at q1.asm:20
20 mov eax, 4
(gdb) n
21 mov ebx, 1
(gdb) n
22 mov ecx, msg1
(gdb) n
23 mov edx, length1
(gdb) p msg1
$1 = 1634036816
(gdb)