Простой контроль целостности процесса под Windows

Намедни решил попробовать написать драйвер под Windows. Варианты с "Hello world" показались унылыми, поэтому в качестве тренировки поставил перед собой следющую цель: написать драйвер, который будет контролировать целостность кода процесса по запросу. В общем, драйвер будет считывать данные о загруженных в память секциях, проверять атрибуты и считать простенькую контрольную сумму, а при повторном обращении - сверять её. Совсем детально описывать процесс я не буду, так как в интернете есть куча мануалов по самым основам, да и желающие могут просто посмотреть примеры из WDK, которые достаточно хорошо документированы.

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

Функции работы с двусвязным списком я подробно разбирать не буду, так как логика работы довольно тривиальная и подробно описана в MSDN. Опишу лишь формат, в котором я храню данные о секциях модулей.

Теперь рассмотрим основные функции, реализующие заявленный контроль целостности:

И, наконец, здоровенная функция, которая обрабатывает секции модулей:

Вот мы и рассмотрели основной код, позволяющий осуществить простой контроль целостности секций юзермодного процесса из ядра. Дополнительные процедуры и заголовоные файлы: для работы с двусвязными списками, структуры, описывающие заголовки PE-файла и простой табличный метод расчета CRC приведены в архиве ниже.

Теперь возьмем этот код и добавим к какому-нибудь базовому прототипу драйвера. Результат будет выглядеть, например, следующим образом:

Скомпилируем и установим наш драйвер в систему (для этой цели я воспользовался удобной утилитой OSR Driver Loader). Теперь нам необходимо отослать драйверу IOCTL-запрос. Что ж, сделаем небольшую утилиту, которая нам в этом поможет:

Компилируем и запускаем нашу утилиту, а также запускаем DebugView, чтобы видеть отладочный вывод драйвера.

init

Как мы видим, драйвер посчитал контрольные суммы интересующих нас секций и добавил в свой внутренний список. Теперь возьмем OllyDbg и изменим произвольный байт в секции кода. Драйвер незамедлительно сообщает о нарушении целостности секции и пишет об этом в логе:

validation_failed

Надеюсь, пример окажется кому-нибудь полезен.

Исходный код полностью: скачать

Простой контроль целостности процесса под Windows: 34 комментария

  1. Спасибо за пример.
    Тоже хочу попробовать написать драйвер, который бы перехватывал обращение к определенным папкам и блокировал доступ. Но все руки никак не доходят.

    1. И что же с ними, если это "простой контроль" и цель - контролировать только секции с кодом в обычных исполняемых файлах?

  2. То, что они в секциях кода и значения эти изменяются. Из за них кодосекции модуля на диске и в памяти различаются.

    1. Так, продолжайте, и что дальше? Если мы читаем и проверяем исключительно исходя из того, что уже загружено в память.

  3. Тогда как узнать что модуль в памяти изменён/пропатчен, сравнить ведь несчем ?

    Например mov r,offset proc -- имеется релок для смещенья. Он может как угодно быть переписан.

    IAT по отношенью к модулю на диске вообще содержит произвольные данные.

    1. Сравнить с тем, что было при первом запросе на проверку. Это не способ защиты от хитрого хекера или чего-то подобного.

  4. Каком есчо запросе ?

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

    1. IOCTL-запросе. Софт делает запрос к драйверу, считается изначальная контрольная сумма, далее, при повторных запросах, контрольная сумма сверяется с изначальной.
      А я в этом особо не разбираюсь.

  5. Вы наверно не понимаете мою речь. Я спрашиваю КАК ОПРЕДЕЛЯЕТСЯ ЦЕЛОСТНОСТЬ ОБРАЗА ?

    Причём тут ваши запросы в дров. Мой вредоносный код изменит образ как сказано выше, пофиксит IAT и как вы узнаете что он целый ?

    1. Если IAT будет изменена до запуска процесса - никак, если IAT будет изменена до первого обращения к драйверу - никак.

  6. IAT заполняется системным лодером при стартапе. Ежели вся суть чеканья в отправке запроса после запуска приложенья, то это не защита :)

  7. Indy вы больной на всю голову человек, ищите себе без повода задачу или конфликт, но когда вам предлагают что-то решить, в личной обстановке, вы не беретёсь. Человек ясно написал, что решил попробовать написать драйвер, вместо Hello world, он не начал с того, что предлагает хитрую технику проверки кода на целостность.

    Kaimi не слушайте этого идиота, нормальный у вас блог, интересно читать и пользы больше и большему кругу людей, чем от экскрементов Indy.

    1. Вы друг мой явно не понимаете. Ежели человек начинает разрабатывать защиту, то он неизбежно становится авером, причём его не интересует дальнейшая проработка защиты. Именно здесь мы сие и наблюдаем. Дальнейшее сами обмозгуете, или быть может тоже помощь нужна ?

      1. Шутить изволите? У меня даже образования в области IT нет, не говоря уже о полном отсутствии желания работать в ней.

        1. У инде тоже его нет и желанья. Это не мешает обходить защиту, пилить морфы и дроверы :)
          А аверы все с такого начинали. Далее будет защита на уровне сервисных таблиц етц, после чего рассмотрена возможность поработать в одной из ав контор(спермский обычно).

  8. Indy вам мерещатся аверы по всюду. У человека хобби, он выкладывает для новичков информацию. Поэтому помощь тут нужна вам, сходите к психологу, он вам поможет разобраться в себе.

  9. Спасибо за код, но тут есть 2 недочёта
    1. Если исполняемый файл содержит релоки, то при проецировании в память засчёт рандомизации адресного пространства секция кода должна будет отличатся от той что в файле (адреса релоков ведь загрузчик перепишет под текущее смещение)
    2. Если исполняемый файл накрыт протектором или пакером, то его секции могут все иметь атрибуты RWE или RWEC. Т.е. алгоритм выборки секций работает только на стандартных скомпилиных файлах.

    Если 2 этих недочёта поправить, то выйдет вполне рабочий вариант.

    1. 1. Так код ведь не оперирует с образом файла на диске, а исключительно с тем, что было уже загружено в память.
      2. Есть такое дело.

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *