Вот статья К.Касперского по ядру NT,я ковырялся для начала ни чего сложного.
Модификация ядра NT.
Прежде чем вторгаться в ядро, попробуем разобраться, зачем это вообщ
нужно и нельзя ли обойтись 'демократичнымa прикладным уровнем.
Черви, вирусы и rootkitiы стремятся в ядро затем, чтобы дотянуться до
функций, работающих с памятью, файлами, сетевыми соединениями
и процессами на самом низком уровне, перехватив которые, можно надежно
замаскировать свое присутствие в системе.
Аналогичными приемами пользуются протекторы исполняемых файлов типа Themid
(бывший eXtreme Protector) и защиты лазерных дисков от копировани
(Star-Force, SONY и т. д.). Методика та же самая, что и в Stealth-виру-
сах 10-15-летней давности, только программные реализации другие.
Кстати говоря, после громкого скандала и судебного разбирательств
SONY признала свою неправоту, отозвав свыше 30-ти наименований.
А ребята из Star-Force продолжают использовать вирусные методики, до сих пор регулярно роняя пользовательские
системы в голубой экран и отказываясь работать с новыми версиями
Windows без обновления самой Star-Force.
Методы модификации ядра
Перехват системных функций, взлом защитных механизмов-все
эти действия требуют модификации ядра, сосредоточенного в файле
ntoskrnl.exe. Модифицировать ядро можно как на диске (off-line patch),
так и в памяти (on-line patch). Каждый способ имеет свои достоинства
и недостатки, поэтому опытный хакер должен в равной мере владеть и
тем, и другим.
On-line patch возможен только из драйвера или из прикладного режима
через псевдоустройство \Device\PhysicalMemory, которое вплоть до
Windows 2003 Server SP1 было доступно администратору, а после
закрыто даже для пользователя типа 'systema (см.
www.microsoft.com/
technet/prodtechnol/windowsserver2003/library/BookofSP1/e0f862a3-
cf16-4a48-bea5-f2004d12ce35.mspx, заметка под именем Changes to
Functionality in Microsoft Windows Server 2003 Service Pack 1 Device\
PhysicalMemory Object). Драйвера (и тем более прикладные програм-
мы!) грузятся после ядра, которое их может вообще не грузить, если
отсутствует цифровая подпись, или ядру что-то 'не нравитсяa. Кроме того,
любой успешно загруженный драйвер может заблокировать
загрузку всех последующих или помешать им осуществить перехват
системных функций, равно как и любую другую намеченную ими опера-
цию. В борьбе с малварью и антивирусными сторожами очередность
загрузки становится очень актуальной, но ни у одной из сторон нет
100% гарантии того, что ее драйвер загрузитсяпервым. К тому же, если
ядро сообщает о завершении испытательного срока или отправляет
систему в reboot еще до загрузки любых драйверов (что практикова-
лось в ранних версиях NT), никакой on-line patch тут не поможет! Кстати
говоря, факт вмешательства в ядро легко обнаруживается тривиаль-
ным сравнением образа ntoskrnl.exe с дисковым файлом. Дезактивация перехвата осуществляется восстановлением '
байт, позаимствованных из оригинала. И хотя перехватчик, желающий
остаться незамеченным, может (и должен!) отслеживать все обраще-
ния к ntoskrnl.exe o многие разработчики об этом забывают...
Off-line patch правит ядро (и, при необходимости, другие файлы) еще до
его загрузки в память, что придает исправлениям этого типа наивысший
приоритет. Полномочия off-line патчера практически ничем не
ограничены, и для модификации ядра всего лишь требуется иметь права
администратора на локальной машине. Доступ к файлу системой не
блокируется (!), а изменения вступают в силу сразу же после перезаг-
рузки, которую с администраторскими правами устроить очень легко,
хоть и не всегда удобно. В тех случаях, когда перезагрузка неуместна или нежелательна,
прибегают к on-line patchу с динамической загруз-
кой драйвера. Естественно, правка ntoskrnl.exe встречает сопротивле-
ние со стороны SFC, но эту проблему можно решить, даже не отключая
SFC (и чуть позже мы покажем как). Хуже другое: если несколько
программ начинают править ядро, то образуется такая мешанина,что
система впадает в голубой экран или начинает вести себя совершенно
неадекватно. Также необходимо позаботиться о том, чтобы установка
новых пакетов обновления (то есть Service Packов) не конфликтовала
с хакнутым ядром. В общем, здесь есть, о чем поговорить!
On-line patch
Даже находясь в нулевом кольце, непосредственно модифицировать
память, принадлежащую ядру, нельзя. Дело в том, что все драйвера выпол-
няются в едином адресном пространстве, общим с ядром, и без защиты от
непредумышленной записи система постоянно страдала бы от некоррект-
но работающих драйверов, спроектированных непонятно кем.
Как и любую другую защиту от непреднамеренного доступа,запрет
на модификацию ядерной памяти можно отключить. Существует, по
меньше мере, два документированных способа сделать это: статичес-
кий и динамический.
Статическое отключение защиты сводится к созданию параметра
EnforceWriteProtection типа REG_DWORD со значением 0h в следующем
разделе системного реестра HKLM\SYSTEM\CurrentControlSet\Control\
SessionManager\MemoryManagement, после чего ядро, но не приклад-
ная программа может модифицировать любой драйвер.
Основной недостаток этого способа в том, что некоторые сторожа сле-
дят за этой веткой, и стоит только тронуть ее, как они поднимают дикий
визг, а то и просто молчаливо удаляют EnforceWriteProtection, возвра-
щая защиту назад. С другой стороны, некоторые честные программы,
например тот же SoftICE, именно так и работают, поэтому слишком
ретивые сторожа рискую отправиться в мусорную корзину, где им
самое место. Правда, подавляющее большинство нормальных людей с
SoftICE не работают, и статическое отключение защиты им ни к чему.
Динамическое отключение защиты осуществляется сбросом WP-бита
в управляющем регистре CR0, который так и расшифровывается
o Write Protection. Соответственно, повторная установка бита обратно
включает защиту.
Ниже приведен код псевдодрайвера, временно отключающего защиту
памяти ядра от записи, а затем включающего ее назад. 'Псевдоa
потому, что настоящие драйвера (в подлинном смысле этого слова)
используются для управления реальными (или виртуальными) устройс
твами, а нам драйвер понадобится только для того, чтобы дорваться
до нулевого кольца. Поэтому мы используем одну лишь процедуру
DriverEntry и тут же возвращаем STATUS_DEVICE_CONFIGURATION_
ERROR, сообщая о фиктивной ошибке, заставляющую систему выгру-
зить драйвер, чтобы он понапрасну не болтался в памяти. Загрузить
же драйвер можно либо обычным путем (через реестр), либо через
динамический загрузчик Свена Шрайбера, прилагаемый к его книге
'Недокументированные возможности Windows 2000 a (сам загрузчик
можно найти на WASM'е):
Код псевдодрайвера krnlWR.asm, временно отключающего защиту ядра от модифи-
кации, а затем включающего ее обратно
.386
.model flat, stdcall
.code
DriverEntry proc
mov eax, cr0 ; грузим управляющий регистр cr0 в регистр eax
mov ebx, eax ; сохраняем бит WP в регистре ebx
and eax, 0FFFEFFFFh ; сбрасываем бит WP, запрещающий запись
mov cr0, eax ; обновляем управляющий регистр cr0
; # теперь защита отключена!
; # делаем все, что задумали сделать
; # модифицируя память ядра по своему усмотрению,
mov cr0, ebx ; восстанавливаем бит WP
; # защита снова
включена!
mov eax, 0C0000182h ; STATUS_DEVICE_CONFIGURATION_ERROR
ret
DriverEntry endp
Для компиляции драйвера потребуется DDK. Во времена Windows
2000 он раздавался бесплатно всем желающим, но затем Microsoft
сменила политику, и теперь его могут получить только подписчики
MSDN или почетные погонщики ослов. На самом деле все не так уж и
печально. И полноценный DDK (вместе с частью SDK) входит теперь в
объединенный пакет Kernel-Mode Driver Framework, который пока еще распространяется бесплатно,
так что спешите качать:
www.microsoft.
com/whdc/driver/wdf/KMDF_pkg.mspx.
Сама компиляция осуществляется следующими ключами командной
строки:
Компиляция псевдодрайвера
ml /nologo /c /coff krnlWR.asm
link /driver /base:0x10000 /align:32 /out:krnlWR.sys /subsystem:native
krnlWR.obj
Модифицируя код или данные ядра, необходимо быть на 100%
уверенным, что в настоящий момент их не использует никакой другой
поток. Невыполнение этого условия приводит к непредсказуемому
поведению системы. В лучшем случае к голубому экрану, в худшем
к потере всего дискового тома (особенно, если мы вмешиваемся в
файловые операции).
Проблема возникает как на многопроцессорных,
так и на однопроцессорных системах без поддержки Hyper Heading,
причем универсальных путей выхода из ситуации не существует.
Каждый случай требует индивидуального подхода, описание которого
тянет на целую статью, и поэтому здесь не рассматривается.
Анализ исходных текстов (или драйверов) великих гуру далеко не всегда идет на пользу начинающим хакерам,
чтобы знать,какими трюками когда можно пользоваться, а когда o нет
Начинающие же обычно запоминают лишь сам трюк, а о границах его приме-
нения зачастую даже не догадываются. В частности, в ранних версиях
своей утилиты DbgView Марк Руссинович вставлял в начало ядерной
функции DbgPring команду перехода на свой обработчик:
Перехват отладочного вывода
mov eax, offset loc_10AD4 ; jmp:DbgPrint
mov eax, [eax+2] ; операнд jmp:[DbgPrint]
mov _pDbgPrn, eax
mov ecx, [eax] ; DbgPrint
mov _pDbgPrn, ecx
mov al, [ecx+1] ; второй байт DbgPrint
cmp al, 8Dh ; PUSH EBP/MOV EBP,ESP
jnz short loc_10666
Поскольку функция DbgPrint не относится к числу интенсивно вызывае-
мых, то вероятность, что какой-то поток вызовет ее одновременно с
установкой перехватчика, достаточно невелика, и все 'как бы рабо-
тает. Однако, если один или несколько драйверов начнут злоупотреб-
лять отладочным выводом, вероятность краха системы значительно
возрастет, поэтому в последующих версиях Руссинович отказался
от небезопасного способа перехвата и перешел на модификацию
таблицы экспорта ntoskrnl.exe. Новичкам, похитившим этот пример и
попытавшимся употребить его для перехвата функций ввода/вывода,
пришлось намного хуже, и голубые экраны выпрыгивали только так!
Off-line patch
Кромсать ядро статическим способом очень просто. Открываем фай
ntoskrnl.exe функций CreateFile, а затем действуем через ReadFile/
WriteFile. Проблема синхронизации потоков отпадает сама собой,
поскольку правка осуществляется еще до загрузки образа в память,
однако техника перехвата от этого ничуть не упрощается. Ведь, чтобы
записать jump поверх ядерной функции или подменить таблицу экспорта,
необходимо явным образом указать адрес нашего обработчик
(расположенного, как правило, в драйвере), но на момент статической
правки ядра местоположение драйвера в памяти еще неизвестно!!!
Приходится шаманить. Например, можно поступить так: найти в ядре
свободное место и внедрить туда крошечный перехватчик-диспетчер
определяющий, был ли загружен 'нашa драйвер. Если нет тo управление
возвращается оригинальным
ядерным функциям, в противном случае нашему драйверу. При перехвате нескольких функций
диспетчер должен смотреть, откуда приходит вызов и какой процедур
драйвера их следует передавать. Вот почему вместо jumpiа програм-
мисты используют call. Диспетчер стягивает с вершины стека адрес
возврата, смотрит, откуда пришел вызов, и все понимает.
При желании код перехватчика можно полностью реализовать в ядре
(если, конечно, это не очень сложный перехватчик) или загрузить сво
собственный драйвер, однако делать это можно лишь тогда, когда
исполнительная система уже функционирует, дисковые тома смонти
рованы, файловые системы опознаны и соответствующие им драйверы
готовы к работе. Другими словами, принудительная загрузка
только на поздних стадиях инициализации
драйверов из ядра возможна
операционной системы (а к этому времени вирусы, встроившиеся в
ядро, могли давным-давно захватить управление, обламывая загрузку
антивируса по полной программе).
После любой модификации системных файлов необходимо пере-
считать их контрольную сумму, иначе NT (в отличие от Windows 98)
откажется их загружать. Правда, в 'безопасном режимеa по F8 они
загружаются, но это все-таки не то.
Для этих целей можно воспользоваться утилитой EDITBIN, входящей
состав Platform SDK и Microsoft Visual Studio. Командная строка выгля
дит так:
editbin.exe /RELEASE filename.exe
Естественно, не стоит забывать о такой штуке, как SFC, норовящей
автоматически (или вручную) восстановить измененные файлы. И
хотя SFC легко усмирить (отключить или синхронизовать измененный
системный файл с его 'эталоннымa оригиналом, хранящимся в кэше),
это не решит всех проблем.
При установке очередного пакета обновления, затрагивающего ядро,
версия такая и откуда она вообще взялась.
инсталлятор просто не поймет, что это.
В результате установка прервется на середине. Пос-
ле перезагрузки система умрет, и конечному пользователю придется
заниматься ее реанимацией (подробнее об этом можно прочитать на
блоге Раймонда Чена Old New Thing:
http://blogs.msdn.com/oldnewthing/603.aspx).
Для вирусов такой прием, быть может, и подходит,
но для коммерческих программ он неприемлем в
принципе! К счастью, существует одна интересная
лазейка o возможность прописать в boot.ini-файле
альтернативное ядро, которое и будет загружаться.
Тогда оригинальный ntoskrnl.exe можно оставить в
неприкосновенности. Ни SFC, ни инсталлятор пакетов
вот то, что обновление затронет 'пассивноеa оригинальное ядро уже нехорошо.
обновления протестовать не будут,что есть гуд. А Может
возникнуть конфликт старого ядра c новым окружением (то же самое
произойдет и при удалении пакета обновления), поэтому необходимо
автоматически (или хотя бы вручную) отслеживать смену ядер, копиро-
вать ntoskrnl.exe поверх альтернативного ядра и заново его модифици-
в некоторых случаях без него не обойтись, поэтому рассмотрим его во всех подробностях.
Довольно геморройный путь, но несмотря на кажущуюся простоту операции, подводных камней
здесь предостаточно.
Первым делом скопируем файл ntoskrnl.exe (он находится в папке
System32) в... ну, например, в ntoskrnh.exe. Затем найдем в корневом
каталоге системного диска (которым, как правило, является диск C:)
boot.ini и откроем его в FARе по <F4> или любом другом подходя-
файл
в редакторе:
Типичное содержимое файла boot.ini
[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINNT
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINNT=iW2K Pro RUSi /fastdetect
Продублируем (copy-n-paste) строку, находящуюся в секции [operating
system], и добавим к ней ключ '/kernel=ntoskrh.exea, где ntoskrh.exe имя
альтернативного ядра. Также изменим текст, заключенный в кавычки,
дописав сюда 'hackeda или что-то свое. Главное, чтобы при загрузке
можно было отличить основное ядро от альтернативного.
Модифицированный boot.ini, предоставляющий возможность выбора ядер
[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINNT
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINNT=iW2K Proi /fastdetect
multi(0)disk(0)rdisk(0)partition(1)\WINNT=iW2K hackedi /fastdetect /kernel=ntoskrh.
exe
При загрузке системы возникнет меню, предлагающее нам одно из
двух ядер на выбор. Убедившись, что оба ядра исправно работают,
удовлетворенные, мы начинаем хакерстовать. Открываем ntoskrnh.exe
(альтернативное ядро) в hiewiе и вносим в него какие-нибудь несу-
щественные изменения. Например, находим последовательность 90h
90h (NOP/NOP) и меняем ее на 87h C9h (XCHG ECX,ECX), сохраняем
изменения по <F9> и перезагружаемся!
Альтернативное ядро больше не грузится! Что ж, загружаемся с
основного, ругая себя всякими словами за то, что забыли пересчитать
контрольную сумму. Даем команду 'editbin /RELEASE ntoskrnh.exea и
перезагружаемся еще раз. Теперь альтернативное ядро работает как
ни в чем не бывало, и первую строчку (с оригинальным ядром) из boot.
ini можно смело убирать, чтобы загрузочное меню не появлялось при каждом запуске системы.
Правда, при этом станет невозможна загрузка в безопасном режиме, поскольку Windows не вполне корректно
поддерживает недокументированный ключ /kernel и путается в ядрах во
всех нештатных ситуациях. В данном случае система упорно утверждает,
что файл ntoskrnl.exe не найден, хотя он исправно присутствует на
диске.
Ладно, попробуем ответить вот на какой вопрос: откуда драйвера узнают о
факте переименования ядра? Ведь в их таблице импорта явно
прописан ntoskrnl.exe, который (в случае альтернативного ядра)
может вообще отсутствовать на диске, но тем не менее функции
экспортируются/импортируются, и все работает, как кремлевские
часы после путча. Волшебство, да и только!
SoftICE по команде 'map32a показывает 'ntoskrnla (без расширения), а не 'ntoskrnHa,
как этого следовало ожидать с точки зрения
здравого смысла, тем более что в этом ntoskrnl присутствуют хакну-
тые нами байты 87h C9h. А вот PE-TOOLS с плагином Extreme Dumpe
'честно сообщает полное имя файла ядра вместе с путем .
Кому из них верить? Вопрос далеко не риторический! Если мы хотим
сравнить образ ядра с его файлом на диске (для обнаружения
on-line patchiа, например), нам необходимо точно знать, к чему обра
щаться, иначе можно совсем не в тот лес забрести.
Ответ дает команда 'moda того же SoftICE, показывающая имя моду
ля ядра (ntoskenl.exe) и соответствующий ему файл (ntoskrnH.exe).
Весь фокус в том, что имена модулей не обязаны соответствовать
ядру, но и ко всем именам файлов. И это относится не только к
динамическим библиотекам вообще! При первой загрузке статической
компоновкой или API-функцией LoadLibrary система находит файл.
Взято с xakep.ru