Blog. Just Blog

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

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Как-то задумался о том, можно ли защититься от программ, которые показывают пароли за "звездочками"? Ведь это могут быть не только безобидные программы для восстановления забытых паролей, но и "троянские кони", похищающие вашу приватную информацию. Немного поэкспериментировал, оказалось, что защититься можно. Сперва немного теоретической информации о том, каким образом открываются пароли. Первый способ: сначала нужному полю EDIT посылается сообщение EM_SETPASSWORDCHAR с нулевыми параметрами, в результате чего с него снимается атрибут ES_PASSWORD. После этого текст пароля можно прочитать как визуально, так и через GetWindowText, WM_GETTEXT и т.п. Второй способ, более "пробивной", это внедрение в исследуемый процесс своей DLL, после чего с ее помощью текст пароля читается через сообщение WM_GETTEXT. Это делается потому, что в целях безопасности информацию из поля, закрытого "звездочками", через GetWindowText или WM_GETTEXT можно получить только из контекста процесса, который владеет окном.

Чтобы защититься от программ первого типа, надо самостоятельно обрабатывать сообщение EM_SETPASSWORDCHAR и в обработчике подавлять его. Защититься от второго варианта сложнее, ведь если мы будем подавлять сообщение WM_GETTEXT, то мы и сами не сможем прочитать текст пароля. Значит надо каким-то образом различать "свои" сообщения WM_GETTEXT и "чужие". Признак "свой" можно сделать, например, указав в качестве длины буфера какое-нибудь заранее определенное уникальное значение, а затем в обработчике пропускать сообщения только с этим параметром. Установить собственный обработчик можно через субклассирование окна ввода, это мы уже разбирали в предыдущих статьях. Теперь от теории перейдем к практике.

Субклассируем поле ввода на этапе инициализации окна. Тут ничего принципиально нового нет, все делается стандартными методами:
  1.         ...
  2.         ; Субклассирование на этапе инициализации окна
  3.         invoke  GetDlgItem,[hwnddlg],ID_PASS
  4.         ; Установить наш собственный обработчик
  5.         invoke  SetWindowLong,eax,GWL_WNDPROC,EditWindowProc
  6.         ; Сохранить адрес предыдущего обработчика
  7.         mov     [OldProc],eax
  8.         ...
В нашей процедуре обработчика проверяются два сообщения: EM_SETPASSWORDCHAR и WM_GETTEXT, остальные беспрепятственно передаются оригинальному обработчику:
  1. proc EditWindowProc hEdit:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
  2.         ; Установить или сбросить символ пароля?
  3.         cmp     [uMsg],EM_SETPASSWORDCHAR
  4.         ; Подавить сообщение
  5.         je      .exit_proc
  6.         ; Получить текст из окна?
  7.         cmp     [uMsg],WM_GETTEXT
  8.         je      .get_text
  9. .msg_ok:
  10.         ; Передать управление предыдущему обработчику или пропустить
  11.         ; разрешенное сообщение
  12.         invoke  CallWindowProc,[OldProc],[hEdit],[uMsg],[wParam],[lParam]
  13.         ret
  14. .get_text:
  15.         ; Проверить длину буфера, пропускать только "своих"
  16.         cmp     [wParam],103h
  17.         je      .msg_ok
  18.  
  19. .exit_proc:
  20.         ; Подавить сообщение и вернуть из обработчика FALSE
  21.         xor     eax,eax
  22.         ret
  23. endp
Теперь, чтобы прочитать текст пароля из нашего приложения, будем передавать с сообщением WM_GETTEXT особый маркер-идентификатор. В нашем случае это уникальная длина буфера для приема текста.
  1.         ; Прочитать текст из защищенного окна
  2.         ; В качестве идентификатора "свой" используется размер буфера 103h
  3.         invoke  GetDlgItem,[hwnddlg],ID_PASS
  4.         invoke  SendMessage,eax,WM_GETTEXT,103h,buff
  5.         ...
Программа готова. Переходим к полевым испытаниям. По первому способу открытия "звездочек" работает целый легион утилит от разных разработчиков. Возьмем для тестов Atomic Asterisk Unhider, Flying Windows, UnPass и Asterisk Logger, любой поисковик подкинет еще десятки аналогов, но ни одна из них не может открыть или получить пароль. По второму способу с внедрением в процесс работает программа Asterisk Key. Она успешно обнаруживает поле ввода с паролем, но его содержимое получить не может, показывая пустую строку.

Скриншот программы Asterisk Key
Скриншот программы Asterisk Key

Похоже, что по второму способу работает еще одна программа Password Viewer, но и она показывает пустое значение. Итак, ни одна из протестированных программ не в состоянии прочитать введенный пароль из окна нашего приложения, в то время как мы имеем к нему полный доступ. Троянов и прочее говно не тестировал за неимением таковых под рукой. Из множества виденных мной программ я встречал пару-тройку, которые пытаются защищать поле ввода пароля, но и то лишь от сообщения EM_SETPASSWORDCHAR, так что Asterisk Key легко пробивает их защиты и показывает пароли.

В приложении готовый пример программы с исходным текстом, создающей окно с защищенным полем ввода пароля, на котором и проводились все описанные испытания.

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

Protected.EDIT.Demo.zip (2,665 bytes)


Поделиться ссылкой ВКонтакте
Просмотров: 6011 | Комментариев: 10

Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
ManHunter (19.09.2020 в 00:27):
Нет, мне просто пофиг. Не испытываю ни малейшего интереса к этой проблеме, и уж тем более не считаю нужным тратить свое время на ее решение.
FFFF (18.09.2020 в 22:52):
Вы целенаправленно не отвечаете, думаете или забыли?
FFFF (13.09.2020 в 23:18):
Или я плохо ищу, или одно из двух. Снятие пароля просто посылкой сообщения:
(Извините за многабукаф)
PasswordDialog.cpp:

bool CPasswordDialog::OnButtonClicked(int buttonID, HWND buttonHWND)
{
  if (buttonID == IDX_PASSWORD_SHOW)
  {
    ReadControls();
    SetTextSpec();
    return true;
  }
  return CDialog::OnButtonClicked(buttonID, buttonHWND);
}
void CPasswordDialog::SetTextSpec()
{
  _passwordEdit.SetPasswordChar(ShowPassword ? 0: TEXT('*'));
  _passwordEdit.SetText(Password);
}

Edit.h:

void SetPasswordChar(WPARAM c) { SendMsg(EM_SETPASSWORDCHAR, c); }

Window.h:

LRESULT SendMsg(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
    { return ::SendMessage(_window, message, wParam, lParam); }

И ни намёка на защиту. Но не пробиться же!
ManHunter (13.09.2020 в 22:12):
7zip же в исходниках. Почему бы не посмотреть там?
FFFF (12.09.2020 в 08:01):
По данным на сейчас, 7zip походу научился выдерживать оба способа. Причём там есть ещё и способ снять звёздочки, хотя в вашем примере сообщение перехвачено и подавлено совсем. Выяснять не пробовал, но, как вы думаете, как это там? Тоже отличение свой-чужой по лишнему полю?
ManHunter (16.03.2012 в 13:40):
Решил нахаляву получить решение своей лабораторной работы? Ты ошибся сайтом.
Alexey (16.03.2012 в 13:38):
хотелось бы увидеть  пример чтоб  веденную строку edit сохранялся в текстовый файл
invoke CreateFile,addr file,GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0
то есть мы для начала создаем файл  а потом туда и записываем с веденного нашего поля
chak_xakep (22.12.2010 в 09:25):
ManHunter,
"Если затачивать прогу именно под эту защиту, зная ее реализацию, то написать можно. Например, с внедрением dll и циклическим перебором разных размеров буфера, пока не будет получен результат."

я тоже об этом задумался))) а если будет перебор буфера, то защита не устоит, хотя если сделать размер буфера*на ID железа )))))))))) ну это изврат конечно же, но я думаю проще будет подменять каждый чар шифруя на ходу каким нибудь ключем а в этот едит виндоу подставлять звездочку)) ну и потом когда астериск попробует глянуть на пасс, то увидит облом! У него будут просто звёздочки...
ManHunter (23.08.2010 в 08:37):
Если затачивать прогу именно под эту защиту, зная ее реализацию, то написать можно. Например, с внедрением dll и циклическим перебором разных размеров буфера, пока не будет получен результат.
Isaev (23.08.2010 в 04:58):
cool

А теперь прогу, которая сможет его считать :)

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.06 сек. / MySQL: 2 (0.0062 сек.) / Память: 4.5 Mb
Наверх