Blog. Just Blog

Контроль запуска процессов на Ассемблере

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Контроль запуска процессов на Ассемблере
Контроль запуска процессов на Ассемблере

Сегодня разберем интересную задачу: надо отслеживать запуск приложений в системе и, в случае необходимости, выборочно блокировать их запуск. Решения могут быть различные, я предлагаю вот такой способ. Он заключается в том, что в цепочку AppCertDlls встраивается наша собственная библиотека-обработчик. При первом и любом последующем вызове функции CreateProcess обработчику будет передан полный путь до запускаемого файла.

Такой способ перехвата используется еще со времен Windows 2000, но подробно не документирован до сих пор. Ничего удивительного, что "коробочный" FASM совершенно не в курсе используемых в нем данных. Сперва немного констант:
  1. ; Флаги запроса
  2. APPCERT_IMAGE_OK_TO_RUN  = 1
  3. APPCERT_CREATION_ALLOWED = 2
  4. APPCERT_CREATION_DENIED  = 3
  5.  
  6. ; Флаги результата
  7. STATUS_SUCCESS      = 0x00000000
  8. STATUS_UNSUCCESSFUL = 0xC0000001
Переходим к созданию основного модуля. В экспорте вашей dll обязательно должна быть функция CreateProcessNotify которая и отвечает за обработку запуска процесса. У нее два параметра: lpApplicationName - указатель на строку имени файла запускаемого процесса и Reason - флаг запроса. Если с именем файла все более-менее понятно, то по флагу запроса надо внести ясность. Этот флаг может принимать одно из трех возможных значений. APPCERT_IMAGE_OK_TO_RUN - система опрашивает вашу библиотеку на предмет того, доверяете вы указанному процессу или нет. Такое бывает, если ваш обработчик первый или единственный. Если запускаемая программа вас устраивает, то верните STATUS_SUCCESS, в противном случае установите флаг результата в STATUS_UNSUCCESSFUL. Варианты запроса APPCERT_CREATION_ALLOWED или APPCERT_CREATION_DENIED поступают в том случае, если в системе уже установлены обработчики запуска приложений, какой-то из них уже проверил запускаемый файл и принял решение, можно его запускать или нет. Если передаваемый функции флаг имеет значение APPCERT_CREATION_ALLOWED, то процесс с этим именем может быть создан, а если APPCERT_CREATION_DENIED, то, соответственно, нет.

Очень важное замечание. Финальную точку в "голосовании" о судьбе запускаемого процесса принимает обработчик, который находится последним в очереди. Даже если все предыдущие обработчики приняли решение, что процесс запускать не надо, и передали по цепочке STATUS_UNSUCCESSFUL, то последний обработчик легко может отменить это решение, вернув флаг STATUS_SUCCESS, и наоборот. На мой взгляд, это очень странное поведение со стороны системы. Ведь ничто не мешает, например, вредоносной программе встроить свой обработчик последним и контролировать таким образом запуск приложений. Если вы создаете приложение просто для логирования запуска процессов, то хорошим тоном будет учитывать "мнение" предыдущих обработчиков и передавать его дальше по цепочке.

Каркас dll в общем виде выглядит следующим образом. Я оставил только значимые части.
  1. ;------------------------------------------------------------------
  2. ; Секция кода
  3. ;------------------------------------------------------------------
  4. proc CreateProcessNotify lpApplicationName:DWORD, Reason:DWORD
  5.         mov     eax,[Reason]
  6.         ; Мы первый или единственный обработчик в цепочке
  7.         cmp     eax,APPCERT_IMAGE_OK_TO_RUN
  8.         je      .check_file
  9.         ; Файл уже проверен, запуск разрешен
  10.         cmp     eax,APPCERT_CREATION_ALLOWED
  11.         je      .file_ok
  12.         ; Файл уже проверен, запуск запрещен
  13.         cmp     eax,APPCERT_CREATION_DENIED
  14.         je      .file_denied
  15.         ...
  16.         ...
  17.         ...
  18. .check_file:
  19.         ; Проверка запускаемого файла, после чего возвращаем нужный статус