x86 程序集,如何在不显示在控制台中的情况下获取用户输入?

x86 Assembly, How to get a user input wihout it being displayed in console?

我对汇编语言很陌生,正在尝试编写一个简单的程序。它获取不应在控制台中显示的用户输入(密码)。

对于正常输入,我是这样使用Irvine32库的。但是这个方法显示用户输入的输入,对于密码之类的输入,这应该是隐藏的,我不知道该怎么做。


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 您需要使用 GetConsoleMode and SetConsoleMode.

从控制台模式清除 ENABLE_ECHO_INPUT

ReadString 在内部使用 ReadConsoleA,使用 Windows 为控制台子系统的可执行文件自动创建的控制台(即它使用 GetStdHandle 检索控制台输入和输出句柄)。

每当 ReadConsoleA 是否回显读取的字符取决于 控制台模式
具体来说,标志 ENABLE_ECHO_INPUT(值 0x4)清除后将阻止回显字符。

要获得当前的控制台模式,请使用 GetConsoleMode,清除 ENABLE_ECHO_INPUT 位和模式与 ENABLE_ECHO_INPUT 的取反(即 [=69 中的 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 的 [=51] 一起 link 编辑=]link。使其适应您的工具。

DisableEcho returns 您必须传递给 EnableEcho 的原始控制台模式(根据 Irvine 的调用约定,在 edx 中)。
喜欢:

call DisableEcho

;Here echo is disabled when calling ReadXXX

mov edx, eax              ;Assuming eax has been preserved
call EnableEcho

根据您的需要调整代码,我没有使用全局变量,因为与 Irvine 相反,我更喜欢尽可能使用纯函数。
有些人发现缺少全局变量更难理解。

这是一个完整的程序,它将读取用户名、密码和 OTP 代码(只是为了表明 echo 已启用 beforeafter 密码提示)然后将打印所有这些。

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