TL;DR您需要从控制台模式中清除ENABLE_ECHO_INPUT 位,使用GetConsoleMode 和SetConsoleMode。
ReadString 在内部使用 ReadConsoleA,使用 Windows 自动为控制台子系统的可执行文件创建的控制台(即,它使用 GetStdHandle 检索控制台输入和输出句柄)。
ReadConsoleA 是否会回显读取的字符取决于控制台模式。
具体来说,标志 ENABLE_ECHO_INPUT(值 0x4)在清除后将阻止回显字符。
要获得当前的控制台模式,请使用GetConsoleMode,清除ENABLE_ECHO_INPUT 位和取反的ENABLE_ECHO_INPUT 模式(即NASM 中的and rm32, ~ENABLE_ECHO_INPUT)。
然后使用这个新值设置控制台模式。
这是禁用和重新启用回声的功能:
;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
注意此代码是为 NASM 编写的,并与 Microsoft 的 link 链接。使其适应您的工具。
DisableEcho 返回必须传递给EnableEcho 的原始控制台模式(在edx 中,按照欧文的调用约定)。
喜欢:
call DisableEcho
;Here echo is disabled when calling ReadXXX
mov edx, eax ;Assuming eax has been preserved
call EnableEcho
根据您的需要调整代码,我没有使用全局变量,因为与 Irvine 相反,我更喜欢纯函数。
有些人发现缺少全局变量更难理解。
这是一个完整的程序,它将读取用户名、密码和 OTP 代码(只是为了显示在密码提示之前和启用了回显)和然后将它们全部打印出来。
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