Blog. Just Blog

Ассемблер: получаем имя файла оболочки

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
В этой статье я расскажу, как можно программно получить имя файла оболочки Windows. Зачем это нужно? Например, есть программа, которая инжектит свою библиотеку в работающую копию explorer.exe и при этом подразумевает, что такой процесс в системе гарантированно должен присутствовать. В подавляющем большинстве случаев действительно все работает, никаких нареканий нет. Но стоит запустить программу под альтернативным шеллом, например, Aston Desktop, и она неизбежно падает с ошибкой, потому что explorer.exe в системе вообще не запущен. Проверки на соответствие оболочки в программе нет, и вместо корректного информирования пользователя о причинах невозможности запуска мы получаем фатальное падение. И хорошо, если не вместе с системой.

Чтобы найти процесс оболочки, сперва надо определить ее главное окно. В MSDN для этого рекомендуют воспользоваться следующим кодом:
  1.         ; Найти окно с классом "Progman"
  2.         invoke  FindWindow, szClass, NULL
  3.         ...
  4. szClass db 'Progman',0
Недостатки такого способа, надеюсь, очевидны. Ничто не мешает любому приложению создать окно с классом "Progman", а при отсутствии запущенного штатного шелла это гарантированно приведет к неверным результатам.

Более правильный путь - использование функции WinAPI GetShellWindow. Долгое время она относилась к недокументированным, но сейчас ситуация улучшилась. Как гласит официальная документация, с ее помощью можно получить хэндл главного окна, принадлежащего процессу оболочки. В случае успеха нам останется только запросить идентификатор процесса, который относится к этому окну при помощи функции GetWindowThreadProcessId, после чего можно будет получить любую информацию о процессе. Но в рамках этой статьи я не буду в это углубляться, ограничусь только простым перебором списка процессов, чтобы узнать имя исполняемого файла оболочки.
  1.         ; Получить хэндл главного окна оболочки
  2.         invoke  GetShellWindow
  3.         or      eax,eax
  4.         jnz     @f
  5. shell_not_found:
  6.         ; Скорее всего используется альтернативная оболочка
  7.         invoke  MessageBox,0,szNo,szShell,0
  8.         jmp     loc_exit
  9. @@:
  10.         ; Получить ID процесса, связанного с этим окном
  11.         invoke  GetWindowThreadProcessId,eax,pID
  12.  
  13.         ; Перебрать все активные процессы
  14.         invoke  CreateToolhelp32Snapshot,TH32CS_SNAPPROCESS,NULL
  15.         mov     esi,eax
  16.  
  17.         mov     eax,sizeof.PROCESSENTRY32
  18.         mov     [ProcEntry.dwSize],eax
  19.         invoke  Process32First,esi,ProcEntry
  20. @@:
  21.         cmp     eax,FALSE
  22.         je      shell_not_found
  23.         ; ID процессов равны, оболочка найдена
  24.         mov     eax,[ProcEntry.th32ProcessID]
  25.         cmp     eax,[pID]
  26.         je      @f
  27.         invoke  Process32Next,esi,ProcEntry
  28.         or      eax,eax
  29.         ; Невероятно, но ничего не найдено
  30.         jz      shell_not_found
  31.         jmp     @b
  32. @@:
  33.         ; EAX -> имя файла оболочки
  34.         lea     eax,[ProcEntry.szExeFile]
А вот если функция GetShellWindow вернула ошибку, то скорее всего в системе используется альтернативный шелл. Значит придется заглянуть в реестр и посмотреть, что прописано в параметре Shell в ключе \SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon. Сперва поиск выполняется в ветке HKEY_CURRENT_USER, затем в HKEY_LOCAL_MACHINE.
  1. ;-------------------------------------------------
  2. ; Прочитать ключ из HKEY_CURRENT_USER
  3. ;-------------------------------------------------
  4. read_registry_user:
  5.         ; Открыть ключ реестра
  6.         invoke  RegOpenKey,HKEY_CURRENT_USER,szReg,phkResult
  7.         or      eax,eax
  8.         jnz     read_registry_machine
  9.         ; Получить информацию из реестра
  10.         mov     [buffSize],MAX_PATH
  11.         invoke  RegQueryValueEx,[phkResult],szKey,0,lpdwDisp,buff,buffSize
  12.         or      eax,eax
  13.         jz      @f
  14.         mov     [buffSize],0
  15. @@:
  16.         ; Закрыть
  17.         invoke  RegCloseKey,[phkResult]
  18.  
  19.         cmp     [buffSize],0
  20.         je      read_registry_machine
  21.  
  22.         ; buff -> имя файла оболочки
  23.         ...
  24.  
  25. ;-------------------------------------------------
  26. ; Прочитать ключ из HKEY_LOCAL_MACHINE
  27. ;-------------------------------------------------
  28. read_registry_machine:
  29.         ; Открыть ключ реестра
  30.         invoke  RegOpenKey,HKEY_LOCAL_MACHINE,szReg,phkResult
  31.         or      eax,eax
  32.         jnz     shell_not_found
  33.         ; Получить информацию из реестра
  34.         mov     [buffSize],MAX_PATH
  35.         invoke  RegQueryValueEx,[phkResult],szKey,0,lpdwDisp,buff,buffSize
  36.         or      eax,eax
  37.         jz      @f
  38.         mov     [buffSize],0
  39. @@:
  40.         ; Закрыть
  41.         invoke  RegCloseKey,[phkResult]
  42.  
  43.         cmp     [buffSize],0
  44.         je      shell_not_found
  45.  
  46.         ; buff -> имя файла оболочки
  47.         ...
  48. ; Ключ реестра
  49. szReg   db 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon',0
  50. szKey   db 'Shell',0
Если и из реестра ничего не удалось получить, значит все совсем плохо. Но на практике я с такой ситуацией не сталкивался.

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

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

Get.Shell.Demo.zip (2,389 bytes)


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

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

Комментарии

Отзывы посетителей сайта о статье
АндрейК (28.09.2017 в 22:49):
>и вот только после этого что-то в него инжектить или выполнять какие-то другие действия.
Так вот в чём цель проверки. Или я опять неправильно понял ?

Просто как-то с сабжем немного не сходится.
ManHunter (28.09.2017 в 10:50):
Про просчет не соглашусь. Первая же проверка через GetShellWindow вернет ошибку и, соответственно, никаких действий с шеллом программа предпринимать не должна. Ровно тот же эффект будет, если при нормальной загрузке системы нахлобучить explorer.exe. Факт: запущенный ШТАТНЫЙ шелл отсутствует. А причина его отсутствия - безопасный режим, альтернативный шелл или тупо убитый шелл - это уже дело десятое.

При нормальном результате проверяем что да, в роли шелла действительно выступает процесс explorer.exe. Если вообще все по уму делать, то после этого надо проверить, действительно ли он запущен из папки Windows, действительно ли у него есть валидная цифровая подпись и всякое такое, и вот только после этого что-то в него инжектить или выполнять какие-то другие действия.

А данные из реестра - это всего лишь приятный бонус, но ни в коем случае не руководство к действию.
АндрейК (27.09.2017 в 23:45):
Просто напомню: в "safe mode with command prompt" дефолтная альтернативная оболочка - cmd.exe

Главное совсем забыл, к чему это я: прога пишет explorer.exe
Просчёт/баг.

И да, cmd.exe в качестве оболочки куда более распространённая/доступная ситуация, в отличии от астона.

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

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

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