Ввод пароля в консоли
Ввод пароля в консоли
Не знаю как вам, а мне очень не нравится метод ввода пароля в никсовой консоли. Введенные символы не показываются даже замаскированными, ввод не реагирует на вставку пароля из буфера обмена, а главное, нельзя удалять ошибочно введенный символ. Я понимаю, безопасность, все дела, но неудобно же! И решил я сделать свой вариант ввода пароля для консольных приложений. Чтобы и "звездочки" показывались, и вставка работала, и символы можно было удалять. Вот что у меня получилось.
Для меня, как и для вас, уже не будет неожиданностью, что сперва надо метнуться в MSDN и самостоятельно описать некоторые структуры и константы, потому что FASM их просто не знает. Структура CONSOLE_SCREEN_BUFFER_INFO уже была, а вот INPUT_RECORD надо описать. Хотя тут используется только клавиатура, я опишу и другие структуры для ввода, вдруг пригодится на будущее. Кстати, INPUT_RECORD в MSDN описана с ошибкой, там неправильно учитывается смещение union. Или поле EventType должно иметь размер DWORD, или надо добавить еще два байта для корректной адресации. Спасибо дизассемблеру IDA, он показывает корректную структуру.
Code (Assembler) : Убрать нумерацию
- struct COORD
- X dw ?
- Y dw ?
- ends
- struct KEY_EVENT_RECORD
- bKeyDown dd ?
- wRepeatCount dw ?
- wVirtualKeyCode dw ?
- wVirtualScanCode dw ?
- union
- UnicodeChar dw ?
- AsciiChar db ?
- ends
- dwControlKeyState dd ?
- ends
- struct WINDOW_BUFFER_SIZE_RECORD
- dwSize COORD
- ends
- struct MOUSE_EVENT_RECORD
- dwMousePosition COORD
- dwButtonState dd ?
- dwControlKeyState dd ?
- dwEventFlags dd ?
- ends
- struct MENU_EVENT_RECORD
- dwCommandId dd ?
- ends
- struct INPUT_RECORD
- EventType dw ?
- Reserved dw ?
- union
- KeyEvent KEY_EVENT_RECORD
- MouseEvent MOUSE_EVENT_RECORD
- WindowBufferSizeEvent WINDOW_BUFFER_SIZE_RECORD
- MenuEvent MENU_EVENT_RECORD
- ends
- ends
- KEY_EVENT = 0x0001
- MOUSE_EVENT = 0x0002
- WINDOW_BUFFER_SIZE_EVENT = 0x0004
- MENU_EVENT = 0x0008
- SHIFT_PRESSED = 0x0010
- RIGHT_CTRL_PRESSED = 0x0004
- LEFT_CTRL_PRESSED = 0x0008
Code (Assembler) : Убрать нумерацию
- ; Получить дескриптор stdout
- invoke GetStdHandle,STD_OUTPUT_HANDLE
- ; Сохранить дескриптор stdout
- mov [stdout],eax
- ; Получить дескриптор stdin
- invoke GetStdHandle,STD_INPUT_HANDLE
- ; Сохранить дескриптор stdin
- mov [stdin],eax
- ; Сбросить буфер ввода консоли
- invoke FlushConsoleInputBuffer,[stdin]
- ; Строка для получения пароля
- mov edi,passw
- ; Длина пароля
- xor ebx,ebx
- loc_loop:
- ; Прочитать ввод с консоли
- invoke ReadConsoleInput,[stdin],ir,1,tmp
- ; Это ввод с клавиатуры?
- cmp [ir.EventType],KEY_EVENT
- jne loc_loop
- ; Нажатие клавиши?
- cmp [ir.KeyEvent.bKeyDown],0
- je loc_loop
- ; BackSpace?
- cmp [ir.KeyEvent.wVirtualKeyCode],8
- je loc_del
- ; Del?
- cmp [ir.KeyEvent.wVirtualKeyCode],46
- je loc_del
- ; Enter?
- cmp [ir.KeyEvent.wVirtualKeyCode],13
- je loc_done
- ; Shift+Ins?
- cmp [ir.KeyEvent.wVirtualKeyCode],45
- jne @f
- test [ir.KeyEvent.dwControlKeyState],SHIFT_PRESSED
- jnz loc_paste
- @@:
- ; Ctrl+V?
- cmp [ir.KeyEvent.wVirtualKeyCode],'V'
- jne @f
- test [ir.KeyEvent.dwControlKeyState],\
- LEFT_CTRL_PRESSED+RIGHT_CTRL_PRESSED
- jnz loc_paste
- @@:
- ; Введенный символ
- mov al,[ir.KeyEvent.AsciiChar]
- ; Буквенно-цифровая кнопка?
- cmp al,20h
- jb loc_loop
- ; Достигнута максимальная длина пароля?
- cmp ebx,MAX_PASSWORD_LENGTH
- jae loc_loop
- ; Записать символ в строку пароля
- stosb
- ; Увеличить длину пароля
- inc ebx
- ; Вывести на экран символ-заменитель
- invoke WriteConsole,[stdout],szPassw,1,tmp,NULL
- jmp loc_loop
- ; Удалить последний введенный символ
- loc_del:
- ; Пароль пустой?
- or ebx,ebx
- jz loc_loop
- ; Затереть последний символ в строке
- dec edi
- mov byte [edi],0
- ; Уменьшить длину пароля
- dec ebx
- ; Получить координаты курсора
- invoke GetConsoleScreenBufferInfo,[stdout],sbi
- ; Передвинуть на символ влево
- dec [sbi.dwCursorPosition.X]
- invoke SetConsoleCursorPosition,[stdout],[sbi.dwCursorPosition]
- ; Записать символ пробела
- invoke WriteConsole,[stdout],szSpace,1,tmp,NULL
- invoke SetConsoleCursorPosition,[stdout],[sbi.dwCursorPosition]
- jmp loc_loop
- ; Вставка строки из буфера обмена
- loc_paste:
- ; Получить формат буфера обмена
- invoke IsClipboardFormatAvailable,CF_TEXT
- or eax,eax
- jz loc_loop
- ; Открыть буфер обмена
- invoke OpenClipboard,NULL
- invoke GetClipboardData,CF_TEXT
- mov edx,eax
- invoke GlobalLock,eax
- ; Поочередно передать все символы из буфера обмена
- mov esi,eax
- @@:
- ; Достигнута максимальная длина пароля?
- cmp ebx,MAX_PASSWORD_LENGTH
- jae @f
- lodsb
- or al,al
- jz @f
- ; Буквенно-цифровой символ?
- cmp al,20h
- jb @b
- ; Записать символ в строку пароля
- stosb
- inc ebx
- ; Вывести на экран символ-заменитель
- invoke WriteConsole,[stdout],szPassw,1,tmp,NULL
- jmp @b
- @@:
- ; Закрыть буфер обмена
- invoke GlobalUnlock,edx
- invoke CloseClipboard
- jmp loc_loop
- ; Окончание ввода пароля
- loc_done:
- ; Пароль пустой?
- or ebx,ebx
- jz loc_loop
- ; passw -> введенный пароль
Теперь при вводе пароля консоль по удобству использования вплотную приблизилась к оконным приложениям. Также код можно легко доработать для работы с юникодными символами. С минимальными изменениями этот код можно применять вообще для любого ввода данных с консоли, в том числе и специализированного, например, чтобы вводить только цифры, только hex-значения или типа того.
В приложении пример программы с исходным текстом, которая запрашивает у пользователя пароль, а затем отображает введенную строку.
Просмотров: 1828 | Комментариев: 4
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
hatmaster
(14.07.2020 в 14:43):
Я юзаю ConEmu, из которого либо через OpenSSH идет коннект напрямую в консоль Линукса, либо через вызов Putty.
Как прикрутить данную тулзу?
Как прикрутить данную тулзу?
ManHunter
(14.07.2020 в 11:20):
Да, тут в уме держалась центосовская консолька. Постоянно испытываю боль во время ввода пароля при логине на сервер. А внутри все нормально, к консоли никаких претензий.
Александр
(14.07.2020 в 08:40):
Возможно здесь речь идёт про какую-то конкретную консоль, но большинство виденных мной консолей и терминалов поддерживают выше описанные действия за исключением отображения символов и сочетания Ctrl+V, в *nix системах это сочетание исторически выполняет действие вставки управляющих символов и вместо него для вставки из буфера обычно работает Shift+Ctrl+V.
Добавить комментарий
Заполните форму для добавления комментария
Спасибо! Всё ок.