Как-то задумался о том, можно ли защититься от программ, которые показывают пароли за "звездочками"? Ведь это могут быть не только безобидные программы для восстановления забытых паролей, но и "троянские кони", похищающие вашу приватную информацию. Немного поэкспериментировал, оказалось, что защититься можно. Сперва немного теоретической информации о том, каким образом открываются пароли. Первый способ: сначала нужному полю EDIT посылается сообщение
EM_SETPASSWORDCHAR с нулевыми параметрами, в результате чего с него снимается атрибут ES_PASSWORD. После этого текст пароля можно прочитать как визуально, так и через GetWindowText, WM_GETTEXT и т.п. Второй способ, более "пробивной", это внедрение в исследуемый процесс своей DLL, после чего с ее помощью текст пароля читается через сообщение WM_GETTEXT. Это делается потому, что в целях безопасности информацию из поля, закрытого "звездочками", через GetWindowText или WM_GETTEXT можно получить только из контекста процесса, который владеет окном.
Чтобы защититься от программ первого типа, надо самостоятельно обрабатывать сообщение EM_SETPASSWORDCHAR и в обработчике подавлять его. Защититься от второго варианта сложнее, ведь если мы будем подавлять сообщение WM_GETTEXT, то мы и сами не сможем прочитать текст пароля. Значит надо каким-то образом различать "свои" сообщения WM_GETTEXT и "чужие". Признак "свой" можно сделать, например, указав в качестве длины буфера какое-нибудь заранее определенное уникальное значение, а затем в обработчике пропускать сообщения только с этим параметром. Установить собственный обработчик можно через субклассирование окна ввода, это мы уже разбирали в предыдущих статьях. Теперь от теории перейдем к практике.
Субклассируем поле ввода на этапе инициализации окна. Тут ничего принципиально нового нет, все делается стандартными методами:
...
; Субклассирование на этапе инициализации окна
invoke GetDlgItem,[hwnddlg],ID_PASS
; Установить наш собственный обработчик
invoke SetWindowLong,eax,GWL_WNDPROC,EditWindowProc
; Сохранить адрес предыдущего обработчика
mov [OldProc],eax
...
В нашей процедуре обработчика проверяются два сообщения: EM_SETPASSWORDCHAR и WM_GETTEXT, остальные беспрепятственно передаются оригинальному обработчику:
proc EditWindowProc hEdit:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
; Установить или сбросить символ пароля?
cmp [uMsg],EM_SETPASSWORDCHAR
; Подавить сообщение
je .exit_proc
; Получить текст из окна?
cmp [uMsg],WM_GETTEXT
je .get_text
.msg_ok:
; Передать управление предыдущему обработчику или пропустить
; разрешенное сообщение
invoke CallWindowProc,[OldProc],[hEdit],[uMsg],[wParam],[lParam]
ret
.get_text:
; Проверить длину буфера, пропускать только "своих"
cmp [wParam],103h
je .msg_ok
.exit_proc:
; Подавить сообщение и вернуть из обработчика FALSE
xor eax,eax
ret
endp
Теперь, чтобы прочитать текст пароля из нашего приложения, будем передавать с сообщением WM_GETTEXT особый маркер-идентификатор. В нашем случае это уникальная длина буфера для приема текста.
; Прочитать текст из защищенного окна
; В качестве идентификатора "свой" используется размер буфера 103h
invoke GetDlgItem,[hwnddlg],ID_PASS
invoke SendMessage,eax,WM_GETTEXT,103h,buff
...
Программа готова. Переходим к полевым испытаниям. По первому способу открытия "звездочек" работает целый легион утилит от разных разработчиков. Возьмем для тестов
Atomic Asterisk Unhider,
Flying Windows,
UnPass и
Asterisk Logger, любой поисковик подкинет еще десятки аналогов, но ни одна из них не может открыть или получить пароль. По второму способу с внедрением в процесс работает программа
Asterisk Key. Она успешно обнаруживает поле ввода с паролем, но его содержимое получить не может, показывая пустую строку.
Похоже, что по второму способу работает еще одна программа
Password Viewer, но и она показывает пустое значение. Итак, ни одна из протестированных программ не в состоянии прочитать введенный пароль из окна нашего приложения, в то время как мы имеем к нему полный доступ. Троянов и прочее говно не тестировал за неимением таковых под рукой. Из множества виденных мной программ я встречал пару-тройку, которые пытаются защищать поле ввода пароля, но и то лишь от сообщения EM_SETPASSWORDCHAR, так что Asterisk Key легко пробивает их защиты и показывает пароли.
В приложении готовый пример программы с исходным текстом, создающей окно с защищенным полем ввода пароля, на котором и проводились все описанные испытания.