I'm really new to assembly language and trying to write a simple program. It gets a user input (password) which should not be shown in console.
For normal input, I use the Irvine32 library like so. But this method displays the input user enters, for inputs like password, this should be hidden which I'm not sure how to do.
INCLUDE Irvine32.inc
.data
idPromptStr byte "Please enter ID : ", 13, 10, 0
id DWORD ?
.code
main proc
mov edx,OFFSET idPromptStr
call WriteString
call ReadInt ;Reads the integer value from console and moves it to eax.
mov id,eax ;Input value is taken in eax.
main endp
end main
TL;DR You need to clear the ENABLE_ECHO_INPUT
bit from the console mode, using GetConsoleMode
and SetConsoleMode
.
ReadString
uses ReadConsoleA
internally, using the console that Windows automatically creates for executable with the console subsystem (i.e. it uses GetStdHandle
to retrieve the console input and output handles).
Whenever ReadConsoleA
will or will not echo the read characters depends on the console mode.
Specifically, the flag ENABLE_ECHO_INPUT
(value 0x4), when cleared, will prevent echoing the characters.
To get the current console mode use GetConsoleMode
, to clear the ENABLE_ECHO_INPUT
bit AND the mode with the negation of ENABLE_ECHO_INPUT
(i.e. and rm32, ~ENABLE_ECHO_INPUT
in NASM).
Then set the console mode with this new value.
Here's the function to disable and reenable the echo:
;No args, return the console mode to pass to EnableEcho
DisableEcho:
push esi
push edi
;-- Get console input handle ---
push STD_INPUT_HANDLE
call _GetStdHandle@4
mov esi, eax
;-- Clear the ENABLE_ECHO_INPUT bit --
sub esp, 04
push esp
push eax
call _GetConsoleMode@8
pop eax
mov edi, eax
and eax, ~ENABLE_ECHO_INPUT
push eax
push esi
call _SetConsoleMode@8
mov eax, edi
pop edi
pop esi
ret
;edx = value returned from DisableEcho
EnableEcho:
;-- Get console input handle ---
push STD_INPUT_HANDLE
call _GetStdHandle@4
;-- Set mode --
push edx
push eax
call _SetConsoleMode@8
ret
Note this code is written for NASM and to be linked with Microsoft's link. Adapt it to your tools.
DisableEcho
returns the original console mode that you must pass to EnableEcho
(in edx
as per Irvine's call convention).
Like:
call DisableEcho
;Here echo is disabled when calling ReadXXX
mov edx, eax ;Assuming eax has been preserved
call EnableEcho
Adapt the code to your needs, I didn't use global variables because, contrary to Irvine, I prefer pure functions whenever possible.
Some people find the lack of global variables harder to follow.
Here's a complete program that will read a username, a password, and an OTP code (just to show that echo is enabled before and after the password prompt) and then will print all of them.
BITS 32
GLOBAL _start
%define STD_INPUT_HANDLE -10
%define ENABLE_ECHO_INPUT 4
%define STRLEN 82
EXTERN _ReadString@0
EXTERN _ExitProcess@4
EXTERN _SetConsoleMode@8
EXTERN _GetConsoleMode@8
EXTERN _GetStdHandle@4
EXTERN _WriteString@0
SECTION .bss
myUsername resb STRLEN
myPassword resb STRLEN
myOTP resb STRLEN
SECTION .data
strUsername db "Username: ", 0
strPassword db "Password:", 0
strOTP db 13, 10, "OTP code: ", 0
strCRLF db 13, 10, 0
SECTION .text
_start:
;-- Read the username --
mov edx, strUsername
call _WriteString@0
mov edx, myUsername
mov ecx, STRLEN
call _ReadString@0
;-- Disable echo --
call DisableEcho
mov esi, eax
;-- Read the password --
mov edx, strPassword
call _WriteString@0
mov edx, myPassword
mov ecx, STRLEN
call _ReadString@0
;-- Restore the echo ---
mov edx, esi
call EnableEcho
;-- Read the otp --
mov edx, strOTP
call _WriteString@0
mov edx, myOTP
mov ecx, STRLEN
call _ReadString@0
;-- Show --
mov edx, myUsername
call _WriteString@0
mov edx, strCRLF
call _WriteString@0
mov edx, myPassword
call _WriteString@0
mov edx, strCRLF
call _WriteString@0
mov edx, myOTP
call _WriteString@0
;-- Exit --
push 0
call _ExitProcess@4
;No args, return the console mode to pass to EnableEcho
DisableEcho:
push esi
push edi
;-- Get console input handle ---
push STD_INPUT_HANDLE
call _GetStdHandle@4
mov esi, eax
;-- Clear the ENABLE_ECHO_INPUT bit --
sub esp, 04
push esp
push eax
call _GetConsoleMode@8
pop eax
mov edi, eax
and eax, ~ENABLE_ECHO_INPUT
push eax
push esi
call _SetConsoleMode@8
mov eax, edi
pop edi
pop esi
ret
;edx = value returned from DisableEcho
EnableEcho:
;-- Get console input handle ---
push STD_INPUT_HANDLE
call _GetStdHandle@4
;-- Set mode --
push edx
push eax
call _SetConsoleMode@8
ret