Защищенное поле для ввода пароля

Как-то задумался о том, можно ли защититься от программ, которые показывают пароли за "звездочками"? Ведь это могут быть не только безобидные программы для восстановления забытых паролей, но и "троянские кони", похищающие вашу приватную информацию. Немного поэкспериментировал, оказалось, что защититься можно. Сперва немного теоретической информации о том, каким образом открываются пароли. Первый способ: сначала нужному полю 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 легко пробивает их защиты и показывает пароли.

В приложении готовый пример программы с исходным текстом, создающей окно с защищенным полем ввода пароля, на котором и проводились все описанные испытания.
Теги:
Защищенное поле, пароль
Добавлено: 10 Апреля 2018 20:37:09 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...