MALWARE Александр Эккерт ([email protected])

Технология Kernel Patch Protection, более известная широкой публике под названием ЛЕЗЕМ В НЕДРА PatchGuard, предназначена для защиты ОС ТАИНСТВЕННОЙ Windows. Создание и реализацию этой техно- логии можно смело приписывать к несомнен- ТЕХНОЛОГИИ MS — ным заслугам в области обеспече- ния защиты ОС от руткитов. Но если набрать KERNEL PATCH в Гугле «PatchGuard», то всемогущий поис- PROTECTION ковик выдаст нам мало чего вразумительного. Не знает Гугл ничего об этой таинственной технологии Microsoft. Яндекс тоже, кстати, в поиске по PatchGuard находится в пролете, ЧТО ИМЕЕМ? аки фанера над Парижем. Но не будем судить Суть технологии PatchGuard проста — система защищает адрес- ное пространство ядра от попыток модификации, тем самым не строго. Вины поисковиков в этом нет: практи- допуская попыток захвата жизненно важных системных позиций. чески вся информация об особенностях этой Защите подлежат объекты, наиболее критические с точки зрения безопасности системы, — это SSDT, GDT, IDT, специфические ре- технологии — результат трудов независимых гистры процессора MSR (через которые проходят так называемые исследователей-кодокопателей. Сегодня мы syscalls), а также само ядро — ntos.exe, библиотека абстракции от оборудования hal.dll и драйвер сетевых операций ndis.sys. не только в деталях рассмотрим, что такое После успешного старта PatchGuard в случайные промежутки PatchGuard и с чем ее едят, но и поговорим времени проверяет целостность виртуальных адресов ядерного пространства и, если обнаруживает подозрительные модифи- о способах ее обхода — тематика журнала того кации, тут же поднимает тревогу с вызовом полиции, скорой, требует ;). пожарных и МЧС в придачу. А если серьезно, то эта технология

092 ХАКЕР 10 /165/ 2012 Малварщики против PatchGuard

просто сваливает систему в BSOD с кодом CRITICAL_STRUCTURE_ CORRUPTION (bugcheck 0x109). PatchGuard присутствует лишь в системах +, крутящихся на 64-битных системах. Старушке Windows XP все System check routine прелести PatchGuard не грозят. Кстати, сами майкрософтовские товарищи категорически не приветствуют патчи kernel-space сторонними драйверами, в том числе использованием ядерных стеков, не созданных непосредственно самим ядром (bit.ly/ Exception handler KeSetTimerEx REiEtR). Вместе с тем надо отметить, что PatchGuard защища- ет лишь ядро от патчей драйверов, но не защитит патчи одних драйверов другими. Надо признать, что данная ситуация ставит в тупик разработ- DPC dispatcher чиков систем защит ОС Windows, ведь современные требования к разработке таких защит просто вынуждают контролировать пользователя на уровне ядра, например при помощи перехвата по- тенциально опасных функций в SSDT. При этом сами же разработ- чики ОС Windows вряд ли предоставят возможности для взаи- Access violation DPC routine модействия с PatchGuard (bit.ly/OT5WmN) — зачем давать в руки врагов ключи от квартиры, где деньги лежат? Однако выкручиваться из этой ситуации как-то надо, и сегодня мы попробуем рассмотреть все или почти все имеющиеся способы Important system code ужиться с PatchGuard на одной системе. PATCHGUARD — ВЗГЛЯД ИЗНУТРИ Инициализация PatchGuard до ее полного включения — очень Примерная логика действий PatchGuard замороченная операция. Ее натуральный старт происходит вы- зовом функции nt!KiInitializePatchGuard, однако, прежде чем дело дойдет до ее вызова, должна произойти масса малопонятных nt!KiDivide6432+0x570: и совсем непонятных вещей. Если приглядеться повниматель- sub rsp,0x2d8 нее, то старт PatchGuard происходит где-то на самом раннем cmp dword ptr [nt!InitSafeBootMode] этапе загрузки операционной системы — со стартом основной jne nt!KiDivide6432+0x580 «загрузочной функции» — nt!KeInitSystem. И если поковыряться ... в дизасме этой функции, то можно увидеть все суровые извра- nt!KiDivide6432+0x580: щения разработчиков Microsoft. Нет, серьезно, я понимаю, что mov al,0x1 перед ними стоит задача защитить систему и замаскировать про- add rsp,0x2d8 цесс инициализации PatchGuard, но не обязательно это делать ret настолько изощренно! Итак, смотрим. Старт PatchGuard происходит вызовом функ- Детальный разбор полета функции KiInitializePatchGuard по- ции nt!KiDivide6432, которая делает важное дело — мастерски требует не один десяток страниц журнала, поэтому остановимся делит два числа. Далее начинается магия — идет вызов функции на основных моментах. nt!KiTestDividend, которая просто тестирует полученный результат Главное, что надо знать, когда работаешь с PatchGuard, — с (внимание!) прошитым в коде (!) значением: PatchGuard высчитывает контрольные суммы защищаемых объектов вызовом функции PgCreateBlockChecksumSubContext nt!KeInitSystem+0x158: и хранит их в особой структуре PATCHGUARD_CONTEXT. Для «об- mov rcx,[nt!KiTestDividend] работки» каждого защищаемого объекта используются функ- mov edx,0xcb5fa3 ции PgCreateImageSubContext (для системных образов и SSDT), call nt!KiDivide6432 PgCreateGdtSubContext и PgCreateIdtSubContex (для GDT/IDT), cmp eax, [ _hardcoded value_ ] PgCreateMsrSubContext (для защиты MSR) и PgCreateDebugRoutine jne nt!KeInitSystem + 0x170 SubContext (для отладочных процедур). ... Память под контекст выделяется в условиях очень высокой ано- nt!KeInitSystem + 0x170: нимности, так, чтобы обломать любителей пошариться по чужим mov ecx,0x5d виртуальным адресам. Маскировка контекста проводится вызовом call nt!KeBugCheck //выход по ошибке UNSUPPORTED PROCESSOR PgEncryptContext, которая не слишком продвинуто ксорит пере- даваемый ей PATCHGUARD_CONTEXT и возвращает вызывающему Кто-то может спросить: почему именно хардкод при инициа- XOR-ключ. лизации? Не слишком умно, правда? Но это лишь на первый взгляд. Данный хардкод, как выясняется, нужен лишь для того, «А МЫ ПОЙДЕМ НА СЕВЕР...» чтобы выявить, не находится ли система под дебагом. Как имен- Обойти PatchGuard сложно, но можно. Вообще, строго говоря, но это происходит — оставлю тебе в качестве домашнего за- хорошим парням обход PatchGuard не нужен. Microsoft пре- дания ;). красно понимала, что вводом этой системы в строй отнимает Выполнение функции KiInitializePatchGuard несет в себе часть хлеба у разработчиков антивирусных защит и проактивных много рутины — она мониторит инициализацию контекстов систем. Для решения этой задачи Microsoft ввела ряд новых, SSDT, таблиц GDT/IDT, ключевых регистров процессора MSR, неизвестных доселе Native API и коллбэков, позволяющих от- а также некоторых критических дебаг-функций. Первое, что слеживать телодвижения ОС. Например, чтобы отслеживать делает KiInitializePatchGuard, — это проверяет, не загружается ли изменения в реестре, в руки системных кодеров была передана система в безопасном режиме. В этом случае, то есть при загрузке функция nt!ZwNotifyChangeKey или коллбэк CmRegisterCallbackEx, в SafeMode, PatchGuard инициализирован не будет: которые были призваны информировать обо всех изменениях

ХАКЕР 10 /165/ 2012 093

WWW INFO

На великом Информации в Сети и могучем инфы о PatchGuard очень в Сети о PatchGuard мало. Оно и по- почти нет. Для нятно — Microsoft общего развития совсем не заинтере- можно почитать сована в раскрытии статью К. Касперски особенностей этой «Взлом Patch- технологии. Guard» — is.gd/ xPB2tl. Из англицких WARNING статей можно почитать FAQ про Вся информация PatchGuard — is.gd/ предоставлена xDkpMJ. исключительно в ознакомительных целях. Ни редакция, Коллстек вызовов ни автор не несут при старте системы: ответственности хорошо видна за любой возможный инициализация вред, причиненный PatchGuard материалами данной статьи.

в реестре без перехвата в SSDT таких функций, как ZwCreateKey/ Вместе с тем надо признать — обход PatchGuard в виде под- ZwEnumerateKey. мены PDE/PTE-адресов есть малоисследованная область kernel- Таким же, например, образом, была разрешена проблема фай- кодинга, которая незаслуженно забыта разработчиками малвари. ловых фильтров, когда для контроля за файловой системой были Впрочем, может, сами разработчики поизмельчали? ;) введены в эксплуатацию мини-фильтры, для чего был реализован Другой широко распространенный в узких кругах способ рас- целый выводок Flt*-функций. Таким образом, Microsoft достигала пила PatchGuard — это перехват функций таймерного механизма, вроде бы своей цели... Но не тут-то было. регулирующих периодический запуск PatchGuard. И действи- Согласись, что здравый смысл в происходящем есть. тельно, для периодической проверки PatchGuard использует Но как оказалось на практике, не так-то просто уместить все за- стандартную kernel-API nt!KeInitializeDpc. После инициализации дачи для обеспечения безопасности ОС в рамки одних коллбэков. DPC следует вызов таймера nt!KeSetTimer, который ставит пла- Обеспечение полноценной безопасности системы — настоль- нируемую DPC в очередь. Суть обхода PatchGuard в этом случае ко трудоемкая и труднореализуемая задача, что предлагаемый в том, что нужно перечислить имеющиеся таймеры, найти нужный Microsoft инструментарий оказался явно недостаточен. А уж нам и отменить его. Несмотря на кажущуюся легкость, сделать что говорить о плохих парнях, которым Microsoft с введением это проблематично: чтобы найти необходимый таймер, нужно PatchGuard хоть и сильно осложнила жизнь, но отнюдь не отбила знать, что искать. желание заниматься своей грязной работенкой? Другой распространенный способ, наверное, не так очевиден на первый взгляд, но вполне имеет право на существование. «ОГЛАСИТЕ ВЕСЬ СПИСОК, ПОЖАЛУЙСТА...» Это — перехват функции nt!KeBugCheckEx. Если уж совсем при- Первое и самое популярное решение для обхода PatchGuard, ко- митивно — то при попытке разбить оковы PatchGuard возникнет торое имеется в арсенале малварщиков, — это создание буткита, исключение, которое, по идее, должно быть обработано функцией который бы стартовал до запуска PatchGuard. nt!KeBugCheckEx. И действительно, люди, не понаслышке знакомые с нынешними Идея, заложенная в этом способе, проста и гениальна. запросами заказчиков малвари под Win7 x32/x64, знают, что самое Смотрим код: популярное (и, пожалуй, единственное) требование — это создание MBR/VBR-руткита, с обходом PatchGuard до его инициализации. FAST_MUTEX WaitAlways; Цена вопроса, кстати говоря, не один десяток тысяч зеленых аме- риканских рублей. if (InBugCode == CRITICAL_STRUCTURE_CORRUPTION) Второй способ обхода PatchGuard малоизвестен широкой { публике. Он основан на манипуляциях с PDE/PTE-адресами. EnableInterrupts(); Я как-то уже писал в ][ об этом способе, позволяющем подменять ExInitializeFastMutex(&WaitAlways); фактические данные, не трогая виртуальных адресов, за которые ExAcquireFastMutex(&WaitAlways); цепляется PatchGuard. В его основе лежит механизм трансляции } виртуальных адресов памяти в физические, которая применяется } во всех современных операционных системах семейства Windows. Обращения к виртуальным адресам для какого-либо процесса Все, что надо сделать, — это «заморозить» поток, который вы- в Windows можно перенаправить на поддельную физическую звал исключение, и вернуть управление, позаботившись о пра- страницу, что достигается изменением значений физического вильном восстановлении стека. адреса, которые хранятся в его PDE/PTE-таблицах. Вся соль тут в том, что PatchGuard не смотрит за этими физическими адресами, ЗАКЛЮЧЕНИЕ чем можно воспользоваться. Не смотрят за этими физическими Как видишь, обойти PatchGuard можно. По крайней мере, процве- адресами и популярные антируткиты. тающие ныне руткиты прекрасно выживают и в 64-битной среде. Недостаток данного способа — его трудно реализовать. Работа И почти все они являются буткитами, то есть фактически они c PDE/PTE-адресами требует очень хороших навыков системно- не обходят PatchGuard, а стартуют до нее. го кодинга в ядре и отличных знаний kernel mode отладки. Ибо Но стремительное и неотвратимое появление в нашей жизни любые, даже самые незначительные косяки в твоем коде приведут 64-битных систем просто обяжет малварщиков искать новые пути к нехорошим последствиям, самое безобидное из которых — за- выживания. На этом закончу. Удачного компилирования и да пре- висание системы. будет с тобой Сила! z

094 ХАКЕР 10 /165/ 2012