- Windows Research Kernel
- Содержание
- Что такое Windows Research Kernel?
- Windows Academic Program
- Структура Windows Research Kernel
- HTML документация по WRK
- Уроки ядерной войны: Новые правила выживания в ядре Windows
- Содержание статьи
- Введение
- KeServiceDescriptorTable – ключ ко всей системе
- Position number two
- Position number три
- Еще одно ядро?
- Pro & cons
Windows Research Kernel
Содержание
Что такое Windows Research Kernel?
Windows Research Kernel (WRK) — исходный код ядра ОС Windows (Windows XP x64 и Windows Server 2003 SP1), распространяемый для некоммерческих, исследовательских целей в рамках «Windows Academic Program» под НЕ СВОБОДНОЙ лицензией (где пруфлинк?). Как следствие, этот код не может быть использован в процессе разработки ReactOS (т.е. разработчики никогда не смотрели этот код и не планируют этого делать, пока не изменятся условия лицензирования WRK)
WRK предназначен для факультетов и преподавателей, работающих в области операционных систем, для разработчиков курсов, авторов учебников и т.д., желающих включить информацию о ядре Windows, основанную на действующем исходном коде. WRK содержит среду для сборки/тестирования и бинарные файлы для исключённых компонентов исходного кода, которые могут быть использованы, чтобы собрать полнофункциональные NTOS ядра для последующей установки на Windows Server 2003 для x86/x64 и Windows XP x64.
Ниже информация из лекции «Исследовательское ядро Windows» курса «Введение во внутреннее устройство Windows» от Intuit.ru.
Windows Academic Program
В 2006 году корпорация Microsoft в рамках академической программы Windows (Windows Academic Program) сделала доступной для академических организаций исходный код исследовательского ядра Windows (Windows Research Kernel, WRK). WRK основано на коде операционных систем Windows Server 2003 SP1 и Windows XP x64.
Кроме WRK в академическую программу Microsoft входят следующие компоненты:
- учебные материалы по курсу операционных систем на основе Windows XP – Windows Internals Curriculum Resource Kit (CRK). Составлены в соответствии с рекомендациями ACM/IEEE по преподаванию курса «Операционные системы» (Operating systems, OS). Материалы включают презентации лекций, указания к лабораторным работам (в том числе лабораторные работы для Windows 7), задания, тесты, а также материалы для преподавателей (Instructor Supplement);
- среда ProjectOZ для экспериментального исследования ядра Windows;
- описание опыта университетов (Faculty Experiences) по преподаванию в рамках академической программы Microsoft.
Все компоненты Windows Academic Program, кроме WRK и материалов для преподавателей (Instructor Supplement), доступны любому желающему. WRK и Instructor Supplement можно получить, подтвердив свой статус преподавателя или по подписке Microsoft Developer Network Academic Alliance (MSDN AA).
Microsoft, предоставляя академическому сообществу исходные коды ядра Windows, преследовало следующие цели:
- облегчить студентам и преподавателям сравнение Windows с другими операционными системами;
- предоставить студентам возможность для изучения исходных кодов ядра и создания собственных проектов на их основе;
- поддержать исследования и публикации по внутреннему устройству Windows;
- содействовать разработке учебников по операционным системам на основе ядра Windows;
- упростить лицензирование.
Исследовательское ядро Windows включает более 800 000 строк исходного кода, в основном на языке программирования C, но есть файлы и на ассемблере. В процессе подготовки к опубликованию исходный код в некоторых местах был упрощен, а комментарии улучшены.
На следующем рисунке представлена схема, отражающая покрытие исходным кодом WRK компонентов ядра.
Рис.1. Покрытие исходным кодом WRK компонентов ядра (выделено серым цветом)
Как видно из рисунка, исходные коды практически всех компонентов исполнительной системы (кроме диспетчера Plug-and-Play и диспетчера электропитания) и ядра представлены в WRK.
Структура Windows Research Kernel
В состав WRK, кроме собственно исходных кодов ядра Windows, входят руководство по ядру Windows NT (NT OS/2 Design Workbook) и решение (solution) Visual Studio 2008 (WRK.sln) (которое можно преобразовать для более новых версий Visual Studio).
Руководство по ядру Windows NT было составлено в конце 1980 х – начале 1990 х гг., когда в Microsoft велась разработка новой операционной системы Windows NT с рабочим названием «NT OS/2» сначала совместно с IBM, затем самостоятельно. Руководство содержит ценную информацию по структуре и функциям ядра Windows, а также раскрывает соображения, которые привели разработчиков к тем или иным архитектурным решениям.
Главные компоненты WRK находятся в папке WRK-v1.2\base\ntos и включают, в основном описания и определения функций и структур данных. В ядре Windows при именовании функций используются определенные соглашения [5; 2]. Название функции обычно строится по следующей схеме:
где обозначает модуль, которому принадлежит функция, – действие, совершаемое над .
Например, рассмотрим функцию KeStartThread:
- Ke (префикс) – функция входит в состав ядра;
- Start (операция) – функция начинает выполнение объекта;
- Thread (объект) – объектом является поток.
Компонент WRK | Префикс функций | Название компонента на англ. языке | Название компонента на русском языке |
---|---|---|---|
cache | Cc | Cache manager | диспетчер кэша |
config | Cm | Configuration manager | диспетчер конфигурации |
dbgk | Dbgk | Debugging Framework | подсистема отладки |
ex | Ex | Executive support routines | функции поддержки исполнительной системы – синхронизация, таймеры, структуры данных исполнительной системы, системная информация |
fsrtl | FsRtl | File system driver run-time library | библиотека функций поддержки файловой системы времени выполнения |
io | Io | Input/Output manager | диспетчер ввода-вывода |
ke | Ke | Kernel | ядро |
lpc | Lpc | Local Procedure Call | механизм вызова локальных процедур |
mm | Mm | Memory manager | диспетчер памяти |
ob | Ob | Object manager | диспетчер объектов |
perf | Perf | Performance | функции для сбора информации о производительности системы |
ps | Ps | Process manager | диспетчер процессов |
raw | Raw | Raw File System | функции для Raw File System |
rtl | Rtl | Run-Time Library | библиотека функций времени выполнения |
se | Se | Security manager | диспетчер безопасности |
wmi | Wmi | Windows Management Instrumentation | поддержка WMI – инструментальные средства управления Windows |
Компоненты WRK и префиксы функций
Кроме перечисленных в таблице, в WRK есть ещё два важных компонента:
- inc – общедоступные заголовочные файлы;
- init – функции инициализации системы.
Приведем ещё один префикс часто встречающихся в WRK функций – Nt. Функции ядра с этим префиксом входят в Native API, они экспортируются Ntdll.dll, их можно вызывать из пользовательского режима. Часто функции с префиксом Nt соответствует WinAPI функция, и, например, при вызове WinAPI функции CreateProcess происходит вызов функции NtCreateProcess.
HTML документация по WRK
В Институте программной инженерии Хассо Платтнера Университета г. Потсдама (Hasso-Plattner-Institute for Software Engineering at University Potsdam) Александром Шмидтом (Alexander Schmidt) и Михаэлем Шёбелем (Michael Schobel) была создана HTML документация по WRK с использованием генератора документации Phoenix Cross Reference (PXR)2 . Данная документация доступна для преподавателей по следующей ссылке:
HTML документация по WRK включает 4 раздела: функции (functions), типы данных (types), синонимы (typedefs) и макросы (macros).
По информации, предоставляемой HTML документацией, WRK содержит 4167 функций и 1957 типов данных.
Уроки ядерной войны: Новые правила выживания в ядре Windows
Содержание статьи
Сегодня мы продолжим разговор о том, как помочь тебе выжить в суровых условиях ядра Windows, на территории, со всех сторон простреливаемой аверами и проактивными защитами. И не просто выжить, а сделать это красиво, элегантно и с наименьшими потерями.
Разработчики малвари постоянно жалуются, что их боты мрут, как мухи, аверы все сильнее закручивают гайки, и выживать в системе становится все сложнее и сложнее. Но не стоит отчаиваться – есть еще порох в пороховницах и ягоды в ягодицах. В подтверждение этому можно привести тот факт, что на широких просторах «тырнета» с определенной периодичностью отлавливаются все новые и новые зверушки типа Rustock’a или TDSS, которые формально уже должны были быть побеждены. А если поразмыслить о том, сколько еще тайных ботов будет выявлено, то можно с уверенностью утверждать, что в среднесрочной перспективе разработчики аверов и проактивных защит без работы точно не останутся.
Введение
В сегодняшней статье речь пойдет о вполне тривиальных вещах, которые знает любой мало-мальски опытный системный программист. Я не сильно согрешу против истины, если скажу, что каждый системный прогер, который не понаслышке сталкивался с вопросами безопасности в ядре, делал подобные вещи (устанавливал хуки поверх системных функций для того, чтобы проконтролировать их вызов). О борьбе хуков против хуков мы и поговорим сегодня.
Рассмотрим ситуацию: тебе всеми правдами и неправдами удалось установить драйвер в систему, и ты уже радостно потираешь свои руки, поскольку, как тебе говорили, проникновение в ядро делает тебя его повелителем. И плевать ты хотел на то, что какой-то авер что-то там контролирует.
Но не тут-то было! Проникновение в ядро, будь то установка своего драйвера или инфект уже установленного, при наличии в системе очень популярной антивирусной шушеры, не даст тебе ровным счетом ничего. Даже если ты наивно полагаешь, что исполнение твоего мегакода в ядре сделает тебя его полновластным Черным Властелином.
Такая ситуация могла быть абсолютно реальной еще несколько лет назад, когда kernel-based руткиты только-только стали появляться на публике, и аверам пришлось приспосабливаться к тому, что вирусы уже начали осваивать неизведанную ранее территорию – ядро операционной системы.
Почти каждый руткит, который можно найти в паблике, или который так или иначе попадал в мои руки, прямо или косвенно использовал системные сервисы – а куда без них? И ведь верно, уж такова архитектура ОС марки Windows, что и вирусы/руткиты, и аверы в ядре, кто для выживания, а кто – для охоты, используют один и тот же набор системных сервисов, куда входят те, которые можно найти в таблицах KeServiceDescriptorTable/KeServiceDescriptorTableShadow, экспорте ядра и важнейших драйверов.
KeServiceDescriptorTable – ключ ко всей системе
Ну, или почти ко всей системе. Первое, что сделает порядочный антивирус и файрвол, чтобы надавать по рукам мегакулхацкерам – установит свои перехватчики на KeServiceDescriptorTable – в ней содержатся адреса системных сервисов, таких как, например NtCreateFile, NtCreateProcess, NtCreateThread и т.д. Для чего это делается, я думаю, понятно – чтобы иметь возможность отслеживать вызовы потенциально опасных для стабильности ОС системных сервисов (работы с виртуальной памятью, реестром, привилегиями и тому подобными штуками). Как правило, такие функции перехватываются всеми аверами подряд, поэтому можно не сомневаться – если на машине стоит хоть что-нибудь антивирусное, будь уверен – в KeServiceDescriptorTable найдется пара-тройка, если не десяток перехватов системных сервисов. Их количество варьируется от одного (F-Secure, например, перехватывает только NtLoadDriver) до «до хрена и больше» (в случае с COMODO Internet Security или Outpost). Все это, естественно, не радует глаз начинающего системного прогера. К примеру, Kaspersky AV вообще грузит (грузил?) свою SSDT, благодаря чему все системные вызовы так или иначе проходят через его адресное пространство.
Не сильно от KeServiceDescriptorTable отличается теневая таблица KeServiceDescriptorTableShadow. Ее второй элемент содержит таблицу win32k.sys, драйвера, на котором в свою очередь держится вся графическая подсистема Windows. Win32k.sys содержит два типа сервисов: сервисы NtUser* и NtGdi*, первые отвечают за оконную подсистему, вторые за графику. Несмотря на неприглядное название и недокументированность, использование сервисов Win32k довольно популярно в андеграундной хакерской среде: посмотри на те сервисы, которые перехватывают аверы в KeServiceDescriptorTableShadow — NtUserFindWindowEx, NtUserQueryWindow, NtUserGetForegroundWindow – все они отвечают за работу с windows-окнами.
Для начала получим указатель на KeServiceDescriptorTable. Чтобы это сделать, просто добавь в свой код такую строку: extern PVOID KeServiceDescriptorTable. Получить адрес KeServiceDescriptorTableShadow немного сложнее, она не экспортируется, код для ее получения ты можешь найти на диске.
Итак, что же делать? Как убрать установленные хуки? Самый дешевый и сердитый способ – просто восстановить SSDT и выполнить свой код, а там – хоть трава не расти. Сделать это, несмотря на сложное название, довольно просто. Сначала мы через вызовы ZwOpenFile/ZwCreateSection/ZwMapViewOfSection найдем и промаппим в свою виртуальную память образ ядра ntoskernl.exe (ntkrnlpa.exe для многоядерных систем). Далее находим в полученной проекции ядра указатель на KeServiceDescriptorTable, после чего в цикле восстанавливаем адреса оригинальных обработчиков.
Находим адрес KiServiceTable
ULONG FindKiServiceTable( ULONG SdtPtr, ULONG Handle )
<
ULONG bFirst = 1, RvaPtr, i;
pointer = (char *)Handle;
pointer += 0x3c;
pointer = (char *)(*(ULONG *)pointer) + Handle + 0xA0;
reloc = (PIMAGE_BASE_RELOCATION)((char *)
(*(ULONG *)pointer) + Handle);
while ((bFirst) || (reloc->VirtualAddress))
<
bFirst = 0;
fixup = (PIMAGE_FIXUP_ENTRY)((ULONG)reloc + 8);
for (i = 0; i SizeOfBlock — 8) >>
1; i++, fixup++)
if ( fixup->type == 3)
<
RvaPtr = reloc->VirtualAddress +
fixup->offset;
if (*(PULONG)( Handle + RvaPtr) –
0x400000 == SdtPtr)
<
if (*(PUSHORT)( Handle + RvaPtr — 2)
== 0x05c7)
return (*(PULONG)
( Handle + RvaPtr + 4) — 0x400000 + Handle);
>
>
*(PULONG)&reloc += reloc->SizeOfBlock;
>
return 0;
>
Минусы такого способа, я думаю, очевидны – практически все аверы и проактивки следят за состоянием своих хуков, установленных в SSDT и, обнаружив их отсутствие, тут же их восстановят. К тому же нельзя игнорировать тот факт, что все порядочные аверы перехватывают NtCreateSection и NtMapViewOfSection, без которых при проецировании ядра не обойтись. Что делать в этом случае, ты узнаешь ближе к концу статьи.
Код, реализующий восстановление SSDT и ShadowSSDT, ты можешь найти на диске.
Position number two
Как ни крути, выжить в условиях тотального контроля за системой очень и очень сложно.
При вызове системного сервиса ядро находит указатели на KeServiceDescriptorTable и KeServiceDescriptorTableShadow, которые хранятся в структуре KTHREAD. Мы дружно маппим ядро, находим в нем указатель на старую, неизмененную KeServiceDescriptorTable. Далее подменяем в «живой» KeServiceDescriptorTable указатели на системные сервисы своими, а в KTHREAD.ServiceDescriptorTable сохраняем указатель на найденную ранее неизмененную KeServiceDescriptorTable.
Вуаля! Этим незатейливым способом можно поставить в тупик не один продвинутый авер. Как это сделать в ядре? Чтобы получить указатель на структуру ETHREAD, частью которой является структура KTHREAD (не веришь – сам посмотри), можно вызвать функцию PsLookupThreadByThreadId (как вариант – PsLookupProcessThreadByCid), в которые нужно передать хендл потока, либо выполнить такой несложный код:
__asm push esi;
__asm mov esi, fs:[0x124].
После этого в регистре esi будет находиться искомый указатель на ETHREAD. Что делать дальше, я думаю, ты поймешь.
Position number три
Есть еще один вариант: оставить не слишком расторопный авер с носом (или что там у них между ног, я не помню :)). Вспомним тезисы, изложенные мной в одной из прошлых статей, посвященных организации виртуальной памяти в Windows. В частности, там шла речь о подмене PTE для нужных виртуальных адресов, в результате чего появляется интересная возможность изменения данных в АП целевого процесса без вызова контролируемых аверами системных функций типа NtWriteVirtualMemory. Вспомнил? Так вот, что мешает нам сделать то же самое здесь? Проецируем ядро уже известными шагами, находим KeServiceDescriptorTable и адрес интересующей нас функции и вызываем ее, но только не через виртуальный адрес, а с адреса, считанного с PTE. Экстремалам и мазохистам можно предложить и такой способ: считывать нужный нам адрес напрямую из физической памяти. Он легко находится вот таким простым способом:
ULONG_PTR GetPhysicalAddress(IN ULONG_PTR VirtualAddress)
<
return (VirtualAddress & 0x1FFFFFFF);
>
Еще одно ядро?
А почему нет? Можно пойти двумя путями. Первый – пропатчить ядро Windows на диске. Делается это элементарно – CreateFile/ReadFile/WriteFile. После любой модификации системных файлов необходимо пересчитать их контрольную сумму, иначе Windows просто откажется их загружать.
Не скрою, все это сложно и палевно, поскольку делать дело придется налету, в недрах операционной системы, где за каждым углом тебя поджидает злой авер. Поэтому править ядро – способ легкий, но ненадежный. Более подробно об этом способе можно почитать в статье К.Касперски «Хак ядра NT»), которая все еще не потеряла своей актуальности.
Экстремалам я могу предложить такой способ: собираем свое ядро из сорцов WRK (Windows Research Kernel), правим его при этом, как хотим, а затем – заменяем им ядро операционной системы и начинаем властвовать. Предвижу бурю недовольства и шквал вопросов, дескать, что это невозможно, что существует и SFC, и ядро весит несколько мегабайт… Да, не спорю, способ трудоемок, но вполне реализуем. И главное – может принести массу дивидендов. Каких? Если у тебя в руках будет свое полностью контролируемое ядро, то дивиденды ты будешь придумывать сам.
Да и потом, простые эксперименты с ядром Windows в стиле «а-ля Linux» будут очень полезны для начинающего системного кодера, пусть даже эти эксперименты не будут направлены на обеспечение безопасности системы. Если ты из числа этих самых экстремалов – сорцы WRK ты сможешь найти на диске. Для начала собери их у себя на машине, а затем тщательно протести на виртуалке, перед тем, как рисковать установкой этого ядра на рабочую машину.
Pro & cons
Ну что ж, пора подводить итоги. Выжить в ядре, даже будучи в условиях тотального контроля со стороны бдительных аверов, можно. Самое главное, чего нельзя делать – это недооценивать разработчиков антивирусов, файрволов и прочих защитных системы – они грамотные люди и зря свой хлеб не едят. Однако лазейки для выживания найти всегда можно, если хорошенько покопаться. И не стоит, наверное, серьезно относиться к вышеописанному :). Просто взгляни на смысл послания как на демонстрацию «proof of concept».
Удачного компилирования, и да пребудет с тобой Сила!
На диске ты найдешь WRK – Windows Research Kernel, альтернативные сорцы для сборки ядра Windows. Крайне полезный подгон для изучения внутренностей Windows :).