Абсолютный ноль Николай «GorluM» Андреев Хакер, номер #072, стр. 072-068-2 Спускаемся на нулевой уровень Любое приложение, запущенное в user mode, само по себе значение cpl (current privilege level) с трех на ноль не сменит, тут хитрое программистское решение нужно. И оно есть, и даже не одно. Существуют, как минимум, два способа выполнения необходимого кода на нулевом уровне привилегий. Первый – официальный, которым пользуются все производители аппаратных наворотов для ПК и хитрых системных инструментов типа SoftIce, заключается он в написании собственного драйвера уровня ядра. Просто пишешь драйвер, запихиваешь куда-нибудь в него свой код, а далее все, как в MSDN написано, – с помощью Service Manager API подгружаешь получившуюся фигню к системе, и твой код выполняется. Способ, как я уже говорил, официальный, неприкольный. В вирусах и червяках его использовать нереально, т.к. таскать с собой бинарник драйвера – большой геморрой. В троян, в принципе, можно впихнуть, но отдельно писать драйвер, а отдельно - пользовательскую часть приложения - тоже некрасиво, не говоря уже об удобстве. Есть, конечно, и плюсы в использовании этого способа. К примеру, устройства-фильтры для перехвата сообщений ввода/вывода (о них позже) реализовать будет попроще, чем во втором способе. Да и не надо будет искать адреса ядерного API – все само найдется при загрузке. Второй способ – хакерский, а точнее, вирмейкерский, так как именно эти повелители заразы его и придумали. Он позволяет перевести твое приложение в привилегированный режим процессора, не используя никаких дров, а просто с помощью небольшого и несложного кода, о реализации которого я сейчас постараюсь рассказать. Ring0 без дров Если открыть третий том IA-32 Intel® Architecture Software Developer’s Manual, единственного достойного учебника по низкоуровневому программированию на интеловских процессорах, на 120-ой странице можно прочесть, что в cpu есть специальные механизмы, позволяющие перелезать с одного уровня привилегий на другой с помощью шлюзов. Шлюзы бывают четырех типов: interrupt gate – шлюз прерывания, task gate – шлюз задачи, trap gate – шлюз ловушки и call gate – шлюз вызова. Достаточно грамотно оформить любой из них, и пользовательское приложение сможет переползать в нулевое кольцо. Другое дело – как их оформить? Каждый шлюз – это специфическая запись в одной из системных таблиц. К примеру, шлюз ловушки, шлюз прерывания и задачи – это специальные записи в IDT, дескрипторной таблице прерываний. А шлюз вызова (калгейт) – это элемент глобальной или локальной дескрипторной таблицы, GDT или LDT. Обычно во всех этих таблицах со страшными названиями хранятся жизненно важные для работы процессора в защищенном режиме данные, такие как векторы прерываний, описания сегментов памяти и прочая фигня, которая нам совершенно не нужна, – нам важно только одно - заставить приложение перелезть в ring0. |