![]() |
Модераторы: Snowy, bartram, MetalFan, bems, Poseidon, Riply |
![]() ![]() ![]() |
|
ama_kid |
|
||||||||||||||||||||||||||
![]() АСУТП-кодер ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1460 Регистрация: 5.3.2007 Где: Москва Репутация: 19 Всего: 95 |
1. Введение
Данная статья является, по своей сути, продолжением известной статьи Геннадия Порева "Создание драйверов режима ядра в среде Borland Delphi". Все моё дальнейшее повествование будет предполагать, что читатель по крайней мере ознакомился с представленным в ней материалом, поэтому если это еще не сделано - то сейчас самое время. К статье прилагается архив со всеми исходными текстами, описанными и разобранными здесь, при этом хотелось бы упомянуть, что некоторые вещи, которые можно найти в исходниках - здесь не описаны, например логирование действий драйвера в файл на диске, которая мало чем отличается от работы с логами в user-mode, или найденная мной в интернете ручная приближенная реализация cdecl-формата вызова функции DbgPrint, которая на языке С++ имеет переменное число параметров с возможностью вставлять управляющие символы для вывода значений переменных (Delphi этого не умеет). Не описано это просто потому, что нет желания останавливаться на этом, при необходимости - это можно самому посмотреть и понять. Также, при цитировании кода в тексте статьи я буду опускать те участки или параллельные вызовы функций (в основном, конечно, отладочный вывод), которые не нужны для понимания той части, о которой говорю в данный момент, поэтому не стоит удивляться, если обнаружите, что исходном коде наличествует еще какой-то "мусор" по сравнению со статьей. 2. Инструментарий Прежде всего, хочу немного времени уделить описанию инструментария, который я использую у себя. В принципе, в изначальной статье он был достаточно подробно описан, так что я не буду повторяться, просто на всякий случай пошагово опишу его применение. Средой разработки является любой текстовый редактор (кстати, почитателям компоненто-на-форму-кидательства дальнейшее не рекомендуется к прочтению). Лично я пользуюсь встроенным редактором Far'а, но можно использовать любой удобный и привычный инструмент. В принципе, впоследствии я нашел на просторах интернета "Delphi Driver Development Kit" (где вроде как используется компилятор от 7-й версии дельфи), но к тому моменту уже привык к изначальной среде окружения, поэтому не стал его особо изучать (кроме того на него тявкает мой антивирус, а после замены инфицированных компилятора и линкера на рабочие варианты - мне так и не удалось заставить его работать). Кому надо - может погуглить: Как правило, для разработки драйвера я копирую целиком папку, содержащую нижеописанные файлы и работаю уже в ней: а) Файл ntoskrnl.lib - самый главный файл, содержащий все импортируемые ядром Windows функции. Данный файл не только жизненно необходим для работы линковщика, но также может помочь узнать формат вызова конкретной необходимой функции, о чем я расскажу ниже. б) dcc32.exe, rlink32.dll, system.dcu и sysinit.dcu - собственно компилятор Delphi3 с сопутствующими файлами. в) link.exe, mspdb71.dll - линковщик от мелкомягких с необходимой для его работы библиотекой г) DrvInst.exe - инсталлятор\деинсталлятор драйвера. Исходник данного приложения на языке Delphi можно найти в прилагающемся архиве и в нем мной реализованы два способа установки драйвера: моментальный (по умолчанию) и с перезагрузкой (во многих случаях может потребоваться и это). Второй способ в исходнике закомментирован, но рекомендуется его проверить для того, чтобы понимать, как это делается. д) Пакетные файлы: _clear.bat (очистка папки), _copy.bat (копирование драйвера в системную папку), _Inst.bat (запуск драйвера), Make.bat и _make.bat (компилирование и сборка драйвера) и _Uninst.bat (очистка системы от следов драйвера) - собственно представляют из себя управление циклом жизни драйвера. Каждый из них вызывает соответствующие команды и исполняемые файлы для реализации своей задачи. Для корректной работы перед началом использования надо в них заменить все названия драйвера на своё собственное (заменив, естесственно, и соответствующие названия файлов). Затем, при наличии в этой же папке файла-исходника драйвера, запускать надо в следующем порядке: - _make.bat (если все прошло успешно - в папке появится sys-файл драйвера) - _copy.bat (этот файл скопируется в системную папку) - (в данном месте я обычно запускаю утилиту DbgView.exe) - _Inst.bat (драйвер запустится и начнет свою работу) - _UnInst.bat (драйвер выгрузится и удалится из системы и текущей папки) е) Ну и не могу не упомянуть скрытых игроков нашей команды - это предустановленный DDK, MSDN и интернет. 99% информации - оттуда. Естественно, этот способ организации процесса не является истиной в последней инстанции и можно его оптимизировать, но для того, чтобы дальнейшие описания были понятны и, самое главное, вопроизводимы - примем такую среду за отправную точку. 3. Первые шаги В данной главе я постараюсь показать, как можно работать в kernel-mode и что делать с доставшимся правом "делать все, что захочется". Исходный код тестового драйвера, рассмотренный здесь, а также user-mode'ного приложения для его тестирования, доступен в прилагающемся архиве в папке под именем MyDrv. 3.1 Перевод функций DDK Итак, автор первоначальной статьи оставил нас наедине с "голым" драйвером tiny, который может только загружаться и выгружаться. Куда двигаться дальше? Надо сказать, что несмотря на использовании компилятора дельфи, все его RTTL-вкусности типа функций trunc, sqrt, random, равно как классов, объектов и других полезностей в ООП, остаются за бортом. Да что там функции - даже банальное сложение двух строковых переменных недопустимо, потому что для этой несложной с точки зрения программиста операции компилятору приходится генерировать вызовы нескольких функций, которых просто нет в режиме ядра! Ну и особую грусть вызывает невозможность использования стандартных обработчиков исключений try...except...finally... по той же самой причине. Поэтому необходимо посмотреть в сторону того, что разрешено. Здесь на помощь приходят файлы ntddk.h, ntdef.h (файлы описаний из WinDDK) и ntoskrnl.lib (описанный выше). Этих файлов конечно недостаточно для того, чтобы написать какой-то навороченный драйвер файловой системы низкого уровня, но для написания более-менее полезного драйвера в учебных целях их хватит (при этом h-файлы используются только как справочный материал по объявлениям констант и необходимых нам функций). Для начала работы необходимо явно указать компилятору, какие функции режима ядра можно использовать - делается это путем статической линковки функций файла ntoskrnl.lib. Для тех, кто не очень четко представляет себе этот механизм - поясню сказанное: возьмем, к примеру, функцию IoCreateDevice, которая впоследствие нам еще пригодится. Объявление этой функции в файле ntddk.h выглядит следующим образом:
3.2. Создание объекта "устройство" Сам по себе драйвер, который умеет только загружаться и выгружаться - бесполезен. Как правило, все драйверы работают с какими-либо устройствами (но не обязательно, и впоследствии я покажу пример этого), поэтому самое первое, что необходимо сделать для того, чтобы труд не был напрасным - создать объект "устройство", к которому можно будет впоследствии обращаться из приложения. Создание устройства в принципе может происходить на любом этапе работы драйвера, но как правило это делают при начальной инициализации в функции DriverEnry:
3.3. Общение с приложением user-mode Но просто создать\удалить устройство - это еще полдела. Зачастую требуется получить некоторую информацию от процесса, исполняющегося в режиме ядра или передать туда порцию своей информации. Для начала рассмотрим самый простой способ - организацию функций-диспетчеров запросов IRP_MJ_READ ($03) и IRP_MJ_WRITE ($04), которые приходят драйверу при выполнении команд ReadFile и WriteFile соответственно. Для начала - необходимо назначить эти самые диспетчеры в функции DriverEntry:
Теперь рассмотрим методы приема\передачи буфера данных. При создании устройства можно выбрать тип метода передачи этого буфера: буферизированный (DO_BUFFERED_IO = $00000004) или прямой (DO_DIRECT_IO = $00000010) путем установки поля Flags объекта-устройств:
а) Запрос чтения (ReadFile): Сам запрос от приложения-инициатора выглядит следующим образом:
Теперь рассмотрим обработку этого запроса в нашем тестовом драйвере:
б) Запрос записи (WriteFile): Запрос от приложения-инициатора:
В драйвере:
Это сообщение отредактировал(а) ama_kid - 8.9.2008, 22:24 Присоединённый файл ( Кол-во скачиваний: 453 ) ![]() -------------------- самурай без меча подобен самураю с мечом, но только без меча |
||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||
ama_kid |
|
||||||||||||||||||||||
![]() АСУТП-кодер ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1460 Регистрация: 5.3.2007 Где: Москва Репутация: 19 Всего: 95 |
3.4 Продвинутое общение
Рассмотренный нами в предыдущей главе метод общения драйвера с внешним миром, конечно, прост и понятен, но что делать, если задача требует не просто считать\записать данные, а произвести несколько более сложные действия, например, передать управляющие команды, обеспечить диалог драйвер-приложение или выполнить что-либо ещё специфическое для данного драйвера? Можно, конечно, при желании все организовать через ReadFile\WriteFile, но есть более универсальное решение - функция DeviceIoControl. Для примера, рассмотрим следующие функции:
![]() Расшифровка полей управляющего слова следующая: 1. Поле DeviceType определяет тип объекта-устройства, которому предназначен запрос. Это тот самый тип устройства, который передается функции IoCreateDevice() при создании устройства. 2. Поле Function идентифицирует конкретные действия, которые должно предпринять устройство при получении запроса. Значения поля Function должны быть уникальны внутри устройства. 3. Поле Method указывает метод передачи буферов данных. Для задания этого поля можно использовать константы: METHOD_BUFFERED = 0; METHOD_IN_DIRECT = 1; METHOD_OUT_DIRECT = 2; METHOD_NEITHER = 3; 4. Поле Access указывает тип доступа, который должен был быть запрошен (и предоставлен) при открытии объекта-файла, для которого передается данный код Управления вводом/выводом. Возможные значения: FILE_ANY_ACCESS = $0000, FILE_READ_ACCESS = $0001 и FILE_WRITE_ACCESS = $0002. Для нас самое важное значение имеют биты 0-2 (в которых указывается метод передачи буфера) и 3-12 (в которых указывается передаваемый код управления драйвером). Остальные байты можно формировать по желанию и необходимости, в нашем случае такой необходимости нет. Теперь рассмотрим обработку этого запроса со стороны драйвера: Для начала необходимо назначить функцию-обработчик данного запроса. Это выполняется, как обычно, в DriverEntry:
4. Из жизни Предыдущая глава была посвящена решению проблем, выдуманных нами фактически на пустом месте. Это не сильно интересно, поэтому в данной главе я хотел бы разобрать пару примеров, основа которых была мной написана для реальных проектов. Надеюсь, они помогут в более быстром освоении темы. Оба примера будут рассмотрены, естественно, на языке Delphi, но если кому интересно - то в соответствующих папках в архиве можно найти и C++ - варианты этих драйверов, которые собираются из-под DDKXP. 4.1 Пример №1: Перехват клавиатуры Рассмотрим частный пример распространенной проблемы глобального перехвата клавиатуры - отлов сочетания CAD. В операционных системах семейства NT это сочетание является единственным, которое не отлавливается из user-mode (исключение составляет способ отлова через MSGINA.dll, но он обладает своими недостатками), поэтому я и взял его для примера, но в принципе данный подход применим для отлова любого требуемого сочетания клавиш. Основной идеей является установка драйвера-фильтра клавиатуры верхнего уровня. Что такое драйвер-фильтр и чем верхний уровень отличается от нижнего я объяснять не буду, об этом можно почитать в соответствующих источниках, но суть сводится к тому, что мы "посадим" наш драйвер поверх устройства основного драйвера клавиатуры, оставляя всю рутинную работу по работе с портами ввода-вывода и первичной обработке результатов ему, а сами будем только фильтровать запросы, проходящие между режимом пользователя и этим драйвером. Данный пример был написан мною по мотивам и на основе широко известного примера Ctrl2Cap, но с некоторыми изменениями, на которых я остановлюсь подробнее. Исходный код драйвера находится в прилагающемся архиве в папке под названием KbdIntcpt. Итак, рассмотрим функцию DriverEntry: первым делом мы создаем объект "устройство", как было показано ранее, с помощью функций IoCreateDevice и IoCreateSymbolicLink.
Затем идёт кусок кода по созданию объекта-евента:
а) Дело в том, что в обработке драйвера клавиатуры всегда находится как минимум один IRP-пакет, поэтому когда мы присоединяемся в цепочку фильтров - то неизбежно пропустим тот пакет, который уже сидит в обработке, потому что на него еще не была установлена наша функция возврата. Фактически это означает что первое после загрузки драйвера нажатие клавиши не будет отловлено. б) Опять же, благодаря тому, что в обработке всегда наличествует как минимум один пакет, в момент выгрузки драйвера в этом пакете сидит привязанная к нему наша callback-функция ReadCompleteCallback (если, конечно, между загрузкой и выгрузкой драйвера происходили нажатия клавиш, что должно было привести к вызову IoSetCompletionRoutine) и если мы выгрузимся до того, как драйвер клавиатуры вызовет эту функцию, мы неизбежно получим BSOD. Для того, чтобы этого избежать - я и использовал евент, сигнализирующий о получении очередного пакета и не дающий выгрузиться драйверу, если он не сработал. Этой же цели служит булевская переменная UnloadProcess, которая не дает установить процедуру завершения, если пошел процесс выгрузки драйвера. Но все это приводит к небольшому неудобству - при выгрузке драйвера необходимо нажать клавишу. Упомянутый мной пример Ctrl2Cap этот момент обходит другим способом - он для своей установки\выгрузки требует перезагрузки компьютера, кому интересно - может погуглить и посмотреть, как это реализовано. в) Ну и еще один достаточно тонкий момент, который не относится именно к данному драйверу, но который я впервые испытал на своей шкуре именно в этом месте, поэтому упомяну здесь. Дело в том, что callback-функция ReadCompleteCallback вызывается на уровне DISPATCH_LEVEL, в то время как остальной код драйвера по умолчанию работает на самом низкоприоритетном уровне PASSIVE_LEVEL. Это различие аукнулось тем, что попытка записи в лог-файл внутри этой функции приводила к BSOD, потому что работа с файлами производится тоже на уровне PASSIVE_LEVEL. Поэтому при разработке механизмов взаимодействия рекомендую не забывать о таких вещах, как приоритет выполнения. Ну а что же собственно выполняет функция ReadCompleteCallback? Её код выглядит следующим образом:
4.2 Пример №2: Перехват системных функций ядра Ну и еще один пример, который я хотел бы рассмотреть - это пример осуществления перехвата функций ядра на примере функции ZwQueryDirectoryFile для обеспечения "невидимости" требуемого файла\папки. Делается это путем модификации системной таблицы служебных дескрипторов (SSDT). Данный метод зачастую называют "грязным", но иногда приходится прибегать и к таким способам, благо из режима ядра это разрешено. Этот пример тоже был написан под большим влиянием найденного в сети драйвера, осуществляющего какую-то работу с таблицей дескрипторов, но, к сожалению, я уже не помню что это был за драйвер, поэтому авторство идеи оставляю за "неизвестным героем". Исходный код находится в прилагающемся архиве в папке под названием FileHider и полный код я приводить здесь не буду, просто поясню основные моменты. Итак, хук устанавливается в функции DriverEntry с помощью экспортируемой недокументированной глобальной переменной KeServiceDescriptorTable (со скачиваемыми примерами рекомендую проявлять осторожность - антивирус ругается на скомпилированные файлы, принимая rootkit-технологии за зверьё). Тонким моментом здесь является использование бита WP системного регистра cr0 при установке\снятии хука. Этот бит управляет защитой от записи системных страниц памяти. Если у вас на машине стоит физической памяти больше 256 Мб (WinXP) или 128 Мб (Win2k), тогда данный код никак не влияет на функциональность (т.е. если его убрать - никаких отличий не найти). Но! Если на машине стоит памяти меньше чем указано - тогда система осуществляет защиту системных страниц памяти от записи и при попытке что-то записать в область системного кода будет генерироваться исключение и это вызовет BSOD (подробнее об этом можно прочитать в журнале Хакер, глава "Типы атак на ядро"). Именно для того, чтобы это учесть, и сделан сброс бита WP перед записью в область системного кода - тогда системные страницы с любом случае будут доступны для модификации. После установки хука - остальное дело техники. Все запросы, благодаря наличию в SSDT адреса нашей функции, перенаправляются ей, затем она тут же вызывает оригинальную системную процедуру по сохраненному указателю, а возвращаемый результат анализирует на предмет соответствия требуемым условиям. В примере я сделал проверку по соответствии имени файла\папки определенному шаблону, а также закомментировал проверку по атрибутам файла. Анализ осуществляется путем перебора всего списка элементов типа FILE_BOTH_DIRECTORY_INFORMATION, который возвращается оригнальной функцией ZwQueryDirectoryFile. В случае выполнения условий проверки - проверяемый элемент удаляется из списка путем перенаправления указателя предыдущего элемента списка на следующий. При завершении работы драйвера - в функции DriverUnload адрес оригинальной процедуры возвращается на место : Конечно, для того, чтобы полностью "спрятать" требуемый файл - просто перехвата ZwQueryDirectoryFile недостаточно, даже если спрятать папку таким образом - в неё все равно можно будет зайти путем ввода команды "cd". Но это уже вопрос наращивания функциональности. 5. Заключение Данная статья не охватывает многие и многие аспекты темы разработки драйверов. Например, не были рассмотрены вопросы обмена с реальными устройствами, не приведено примеров работы с файловой системой на низком уровне, даже не рассмотрен вопрос построения inf-файлов, необходимых для полноценной установки устройства в систему, или других узкоспециализированных моментов. Но и не в этом её цель. Целью является дать дополнительный импульс для тех, кто хочет осилить эту необъятную тему, с тем, чтобы дальше можно было двигаться самостоятельно, дать начальные познания при помощи привычной "среды", а также дать своеобразные "направляющие" для правильного составления конкретных вопросов на соответствующих форумах. Если не получилось - прошу строго не судить P.S. Выражаю огромную благодарность Snowy за помощь в подготовке и оформлении статьи. Это сообщение отредактировал(а) ama_kid - 8.9.2008, 22:11 Присоединённый файл ( Кол-во скачиваний: 483 ) ![]() -------------------- самурай без меча подобен самураю с мечом, но только без меча |
||||||||||||||||||||||
|
|||||||||||||||||||||||
THandle |
|
|||
![]() Хранитель Клуба ![]() Награды: 1 Профиль Группа: Админ Сообщений: 3639 Регистрация: 31.7.2007 Где: Moscow, Dubai Репутация: 7 Всего: 372 |
||||
|
||||
MetalFan |
|
|||
![]() Аццкий Сотона ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 3815 Регистрация: 2.10.2006 Где: Moscow Репутация: 16 Всего: 128 |
ama_kid, сам написал?! ну ты
![]() -------------------- There are always someone smarter than you... |
|||
|
||||
ama_kid |
|
|||
![]() АСУТП-кодер ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1460 Регистрация: 5.3.2007 Где: Москва Репутация: 19 Всего: 95 |
THandle, MetalFan, спасибо
![]() Это сообщение отредактировал(а) ama_kid - 5.12.2008, 23:26 -------------------- самурай без меча подобен самураю с мечом, но только без меча |
|||
|
||||
Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
ama_kid,
Спасибо. Когда при решении задач мне стало довольно сильно мешать мое неумение писать драйвера, я решила обратиться к С, считая что в родной и любимой Delphi это будет "не естественно" ![]() Еще раз спасибо, за избавление от столь пагубного заблуждения ![]() |
|||
|
||||
ne0n |
|
|||
PlayBoy ![]() ![]() Профиль Группа: Участник Сообщений: 733 Регистрация: 5.8.2005 Где: Н.Новгород Репутация: 4 Всего: 11 |
Riply, ну на самом деле - это не такое пагубное заблуждение...переводить ddk на паскаль, никто не будет...а самому эту задачу не осилить, хотя может и найдуться интузиасты
![]() ничего нового не узнал, но за стотью в любом случаи респек и + |
|||
|
||||
Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
ama_kid,
Наконец-то выдалось свободное время и можно заняться всякими вкусностями ![]() Начала смотреть код (Delphi версия) и у меня сразу появилась куча вопросов: 1. STRSIZE = 115; Что это за число (115) и откуда оно взялось ? 2. NTSTATUS спецально объявлен как ULong ? Если да, то почему ? 3. Вытекает из второго Реализация ф-ии NT_Success ( Result := (NTS=STATUS_SUCCESS) ) обусловлена именно таким объявлением NTSTATUS ? 4. Почему, после вызовов BCAnsiStringAllocate не всегда вызывается BCAnsiStringFree (например в WriteDispatch) ? 5. Rtl-кие функции для работы со строками валидны в нашем случае ? (Имеется ввиду совместимость способов выделения и освобождения памяти Rtl-кими функциями и BC-функциями) ? P.S. При ответах, просьба учесть нулевой уровень вопрошающей в данной области ![]() |
|||
|
||||
ama_kid |
|
|||
![]() АСУТП-кодер ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1460 Регистрация: 5.3.2007 Где: Москва Репутация: 19 Всего: 95 |
115 - это "магическое число" и взялось оно мной практически с потолка, дабы ограничить размер статического массива
![]() Я не совсем понял вопрос. А как он должен быть объявлен? В принципе, в DDK он объявлен знаковым (long), но в изначальной статье (на которую я ссылаюсь вначале) он был объявлен как cardinal (и в принципе, я нигде не видел использования знаковых особенностей этого дефайна), поэтому перенес все один в один. ![]()
![]() ![]() Не понял, что ты имеешь ввиду под выделением\освобождением памяти Rtl-кими функциями? Память выделяется\освобождается функциями MmAllocateNonCachedMemory\MmFreeNonCachedMemory, а Rtl-кие функции как раз и предназначены для работы со строками (ну и для многого другого). BC-функции, как я говорил, это просто обертки над ними (посмотри их код в модуле BCore.inc - там они как раз и вызывают Rtl-функции) -------------------- самурай без меча подобен самураю с мечом, но только без меча |
|||
|
||||
Riply |
|
||||||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
Я только начала разбираться, но мне кажется, что можно работать с блоками размером до MAXWORD shr 1. Я пыталась исходить из размерности полей. К сожалению не знаю как обстоят дела в мире драйверов, но в обычном приложении, работающем с Nt-функциями знаковость NTSTATUS очень важна. А NT_SUCCESS должна иметь такой вид:
Дело в том, что некоторые (если не многие) функции могут в случае успеха возвращать не STATUS_SUCCESS а "некий код", содержащий STATUS_SEVERITY_INFORMATIONAL. В этом случае фунция выполнена успешно, а в ее результате дается дополнительная информация. Как правило это используется в Query функциях (например STATUS_MORE_ENTRIES говорит, что все удачно записано, но меня можно вызвать еще раз для дозаписи). Но встречается и в другин. Например я сталкивалась с STATUS_PREDEFINED_HANDLE, STATUS_EVENT_PENDING или при работе с секциями (мутантами) STATUS_OBJECT_NAME_EXISTS а вот здесь это становится довольно важно.
Ой. Прошу маленький тай-аут. Еще чуть поразбираюсь и сформулирую вопрос более точно. Но пока мне не понятно, чем обусловлен выбор MmAllocateNonCachedMemory вместо Rtl - Heap - функций ? (Они кстати "совместимы" с такими как RtlFreeUnicodeString) |
||||||
|
|||||||
ama_kid |
|
||||||||||||
![]() АСУТП-кодер ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1460 Регистрация: 5.3.2007 Где: Москва Репутация: 19 Всего: 95 |
![]() Вот как это дело расписано в DDK:
![]() Я наконец понял, что ты имеешь ввиду. ![]()
![]()
-------------------- самурай без меча подобен самураю с мечом, но только без меча |
||||||||||||
|
|||||||||||||
Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
IMHO, довольно опасный способ проверки. Например при создании секции такая проверка может показать неудачу, в то время как все успешно и мы получили на руки открытый Handle. Который еще и закрыть надо ![]() Я почему спрашиваю. Мы ведь в наших Dispatch функциях предполагаем многократное выделение/освобождение. Соответственно меня и интересует какой из способов работы с памятью лучше всего подходит для этого случая. С MmAllocateNonCachedMemory я еще не окончательно разобралась, но меня сильно смущает следующая фраза из MSDN: "A device driver that must use noncached memory should allocate only what it needs during driver initialization because nonpaged pool is likely to become fragmented as the system runs." Насчет же функций типа RtlAnsiStringToUnicodeString (а они предназначены для частого использования) , мое копательство в них показало, что они работают именно через Rtl-Heap. Поэтому я и говорила о "совместимости". Если бы BC функции тоже работали через Heap, то их можно было бы использовать "вперемежку" с Rtl-скими (проверяла в юзер-моде). P.S. Я ни в коем случае не спорю, а просто пытаюсь понять что к чему и с чем едят. Соответственно многие мои утверждения приведены не как контр-аргументы, а для того, чтобы мне показали ошибку в моих рассуждениях и пояснили "как надо на самом деле" ![]() Где еще найдешь бесплатное образование, кроме как не на таких форумах ![]() Это сообщение отредактировал(а) Riply - 9.9.2008, 17:26 |
|||
|
||||
ama_kid |
|
|||
![]() АСУТП-кодер ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1460 Регистрация: 5.3.2007 Где: Москва Репутация: 19 Всего: 95 |
Ну вот сначала закрываем, а потом отлаживаем и разбираемся, что же мы получили ![]()
![]() Но вообще, режим ядра предоставляет гораздо большие возможности для работы с памятью, чем user-mode и на эту тему есть интересные статьи на Wasm.ru (главы "Работа с памятью"). Можешь почитать, если интересно... -------------------- самурай без меча подобен самураю с мечом, но только без меча |
|||
|
||||
Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
||||
|
||||
ama_kid |
|
|||
![]() АСУТП-кодер ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1460 Регистрация: 5.3.2007 Где: Москва Репутация: 19 Всего: 95 |
-------------------- самурай без меча подобен самураю с мечом, но только без меча |
|||
|
||||
Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
ama_kid, никак не могу понять:
Вот пишем мы лог из Dispatch функций. А на чем основана наша уверенность в том, что это потоко-безопасно ? |
|||
|
||||
ama_kid |
|
|||
![]() АСУТП-кодер ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1460 Регистрация: 5.3.2007 Где: Москва Репутация: 19 Всего: 95 |
Хм... Для начала два встречных вопроса:
1) Я где-нибудь это утверждал? 2) Я где-нибудь использовал потоки? Естественно, разработка многопоточных приложений может наложить свой отпечаток, в том числе и в режиме ядра, но все-таки это не является предметом рассмотрения в даной статье... Ну а ответом на поставленный вопрос, думаю, может служить тот факт, что посылка запросов IRP_MJ_READ\WRITE\DEVICE_CONTROL осуществляется синхронно, т.е. системный менеджер запросов не пошлет драйверу следующий IRP-пакет до тех пор, пока им не будет обработан предыдущий. Поэтому, допустим, вызов ReadFile из одного потока при обработке ReadFile из другого потока вызовет просто задержку на исполнение первого вызова. Отчасти поэтому и не рекомендуется задерживать обработку IRP-пакетов (а на высоких уровнях приоритета - вообще нельзя) - т.к. это приводит к performance reducing... -------------------- самурай без меча подобен самураю с мечом, но только без меча |
|||
|
||||
Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
Это смотря что считать утверждением ![]() Я посчитала, что раз ты не побеспокоился о потоко-безопасности, значит считаешь, что это излишне. Вот я и пыталась понять на чем это заключение основано ![]() Спасибо. Именно это меня и интересовало. Т.е. сколько бы приложений одновременно не открыло наше устройство для связи с драйвером и с какой интенсивностью они бы ни читали(писали) мы будем получать только по одному запросу и пока его не обработаем, следующий нам никто не даст. Я правильно поняла ? |
|||
|
||||
ama_kid |
|
|||
![]() АСУТП-кодер ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1460 Регистрация: 5.3.2007 Где: Москва Репутация: 19 Всего: 95 |
Да на таком уровне и беспокоиться не надо - BSOD быстренько бы обо всём напомнил
![]() вполне ![]() -------------------- самурай без меча подобен самураю с мечом, но только без меча |
|||
|
||||
Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
И очень похоже, что ты оказался прав в своем выборе ![]() Вот что гласит MSDN: To allocate I/O buffer space, the best memory allocation routines to use are MmAllocateNonCachedMemory, MmAllocateContiguousMemorySpecifyCache, AllocateCommonBuffer (if the driver's device uses bus-master DMA or a system DMA controller's auto-initialize mode), or ExAllocatePoolWithTag. Nonpaged pool typically becomes fragmented as the system runs, so a driver's DriverEntry routine should call these routines to set up any long-term I/O buffers the driver needs. Each of these routines, except ExAllocatePoolWithTag, allocates memory that is aligned on a processor-specific boundary (determined by the processor's data-cache-line size) to provide best performance. Это сообщение отредактировал(а) Riply - 12.9.2008, 04:29 |
|||
|
||||
Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
ama_kid, что-то мне не удается найти в ntoskrnl.lib ничего похожего
на KeGetCurrentIrql :( Может она называется там совсем по-другому ? Подскажи, пожалуйста, как ее импортировать ? |
|||
|
||||
ama_kid |
|
|||
![]() АСУТП-кодер ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1460 Регистрация: 5.3.2007 Где: Москва Репутация: 19 Всего: 95 |
![]() Это сообщение отредактировал(а) ama_kid - 16.9.2008, 19:12 Присоединённый файл ( Кол-во скачиваний: 36 ) ![]() -------------------- самурай без меча подобен самураю с мечом, но только без меча |
|||
|
||||
Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
Спасибо. Скачала, буду смотреть. С DDK мы еще не знакомы. Пока не разобралась с какой стороны к нему подходить ![]() |
|||
|
||||
Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
ama_kid,
Хочу вернутся к вопросу потоко-безопасности. Пару раз заметила, что при записи лога KbdIntcpt (правда чуть переделанного ![]() искажение информации, причем на определенных сообщениях. Редко но бывает. Тогда решила добавить в лог ThreadID (первый столбец во второй таблице) и посмотреть в каком порядке добавляются записи. Выдержка из лога Dbgview: 00000034 11:43:50 DriverRead _ 0 0 0 00000035 11:43:50 DriverRead IoCallDriver 103 0 0 -->00000036 11:43:54 DriverUnload _ 0 0 0 00000037 11:43:56 DRIVER_NAME : DriverReadCallBack 00000038 11:43:56 DriverUnload KeWaitForSingleObject 0 0 0 00000039 11:43:56 DriverUnload ZwClose 0 0 0 00000040 11:43:56 DriverRead _ 0 0 0 00000041 11:43:56 DriverUnload IoDeleteSymbolicLink 0 0 0 00000042 11:43:56 DriverRead IoCallDriver 103 0 0 00000043 11:43:56 DriverUnload IoDetachDevice 0 0 2262795872 00000044 11:43:56 DriverUnload IoDeleteDevice 0 0 2240838328 00000045 11:43:56 SnakeLog Finalizate 0 43 1024 Соответствующие строчки из лога KbdIntcpt: 0000000748 21.09 07:43:50.500 DriverRead IoCallDriver Overlapped I/O operation is in progress ( $000003E5 ) 0000000000 0000000000 0000000025 0000000046 -->0000000052 21.09 07:43:54.062 DriverUnload _ The operation completed successfully 0000000000 0000000000 0000000026 0000000047 0000000052 21.09 07:43:56.593 DriverUnload KeWaitForSingleObject The operation completed successfully 0000000000 0000000000 0000000027 0000000048 0000000052 21.09 07:43:56.593 DriverUnload ZwClose The operation completed successfully 0000000000 0000000000 0000000028 0000000049 0000000748 21.09 07:43:56.593 DriverRead IoCallDriver Overlapped I/O operation is in progress ( $000003E5 ) 0000000000 0000000000 0000000031 0000000051 0000000052 21.09 07:43:56.593 DriverUnload IoDetachDevice The operation completed successfully 0000000000 2262795872 0000000032 0000000052 0000000052 21.09 07:43:56.593 DriverUnload IoDeleteDevice The operation completed successfully 0000000000 2240838328 0000000033 0000000053 0000000052 21.09 07:43:56.593 SnakeLog Finalizate The operation completed successfully 0000000043 0000001024 0000000034 0000000054 "-->" - помечен вход в процедуру DriverUnload Видно, что паралельно с ней у нас отрабатывает и процедура DriverRead, причем работают они "из разных потоков" (ID одного - 52, другого - 748). Т.е. у нас получается следующая последовательность действий: DriverUnload --> KeWaitForSingleObject DriverUnload --> ZwClose DriverRead --> входим в процедуру DriverUnload --> IoDeleteSymbolicLink DriverRead --> IoCallDriver DriverUnload --> IoDetachDevice DriverUnload --> IoDeleteDevice Вот такие пироги. P.S. Очень надеюсь, что ты найдешь ошибку в рассуждениях и мне не придется разбираться еще и потоко-безопасностью, вместо похода на дискотеку ![]() P.P.S. У меня еще возникли вопросы по работе с памятью, но это после того как с этим разберемся ![]() Добавлено через 5 минут и 1 секунду Вот черт. У меня такие аккуратные таблички были, а тут все съехало. Sorry. Надеюсь они стали не очень нечитабельны ![]() |
|||
|
||||
Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
Если кому интересно...
![]() Попробовала чуть более детально разобраться с нашей потоко-безопасностью. Вот что получилось: Для синхронизации выбрала (после очень долгих и тяжких раздумий) объект ERESOURCE. (Выбирала с учетом своих планов, так что кому-то может лучше подойдут объекты другого типа) Эффект искажения данных в логе исчез сразу после заключения "логовых" функций в "критические обертки". Для проверки, что одновременная запись в лог разными нитями мне не померещилась в кошмарном сне ![]()
Вот выдержка из лога Dbgview: 00000043 07:48:45.484 DriverRead IoCallDriver 103 0 Free 00000044 07:48:45.562 ReadCompleteCallback 00000045 07:48:45.562 DriverRead _ 0 0 Free 00000046 07:48:45.562 DriverRead IoCallDriver 103 0 Free 00000047 07:48:48.718 DriverUnload _ 0 0 Free 00000048 07:48:50.859 ReadCompleteCallback 00000049 07:48:50.859 DriverUnload KeWaitForSingleObject 0 0 Free 00000050 07:48:50.859 DriverUnload ZwClose 0 0 Free 00000051 07:48:50.859 DriverRead _ 0 0 Locked(!) 00000052 07:48:50.859 DriverUnload IoDeleteSymbolicLink 0 0 Locked(!) 00000053 07:48:50.859 DriverRead IoCallDriver 103 0 Locked(!) 00000054 07:48:50.859 DriverUnload IoDetachDevice 0 0 Free 00000055 07:48:50.859 DriverUnload IoDeleteDevice 0 0 Free 00000056 07:48:50.859 LatchFile LatchFile_Finalizate 0 38 1024 Как мне кажется, из нее (выдержки) видно как происходит борьба двух нитей за ресурс ![]() P.S. То, что мне помогло использование ERESOURCE (это утверждение основано на отсутствии BSOD в течении трех часов ![]() Требуется более тщательная проверка. |
|||
|
||||
ama_kid |
|
|||
![]() АСУТП-кодер ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1460 Регистрация: 5.3.2007 Где: Москва Репутация: 19 Всего: 95 |
Ой, что-то как-то я упустил свою тему из виду, извиняюсь, просто уже несколько дней не заглядывал на форум...
![]() Имхо, нет в твоих рассуждениях ошибки, насколько я разобрался в той каше, которую ты вывалила ![]() Насколько я понял, у тебя вызвал непонятки момент одновременной записи в лог из DriverRead и DriverUnload? Не забывай (или имей ввиду), что функции DriverEntry и DriverUnload - это не функции-диспетчеры, а функции, выполняющиеся в контексте одного из системных потоков (случайным образом выбирается один из потоков процесса SYSTEM). А функции-диспетчеры выполняются в контексте процесса, выполняющего запрос ввода-вывода . А раз так - то для синхронизации между функциями-диспетчерами и системным потоком конечно нужно использовать объекты синхронизации... Кроме того, меня смутила твоя фраза про "немного переделанный вариант" KbdIntcpt. Насколько я понял, ты ввела Overlapped-режим? Если я правильно помню - то отложенные операции выполняются тоже в контексте системного потока (аналогично callback-функциям), поэтому между двумя системными потоками тоже неплохо бы вводить синхронизацию при использовании ими общих ресурсов ![]() -------------------- самурай без меча подобен самураю с мечом, но только без меча |
|||
|
||||
microxa |
|
||||||||
Новичок Профиль Группа: Участник Сообщений: 2 Регистрация: 2.12.2008 Репутация: 1 Всего: 1 |
hi, all
![]() Относительно темы delphi драйверов... Надо отметить что некоторым недостатком является сборка драйверов из obj-ектников, или использованием сторонних тулз (omf2d, m$-link). Вобщем куда удобней использовать собственный линкер delphi, устраняя некоторые неровности в производимых им PE dll-ках, таким вот напильником:
Дабы компиль не напихал вредных зависимостей, разюмеется для сборки необходимы минимальные System/Sysinit
Особености реализации модулей позволяют использовать блоки try/except (хотя от всех видов исключений (например GPF) - они не спасут). Ну и собственно как использовать:
удачи ![]() |
||||||||
|
|||||||||
Pavia |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 418 Регистрация: 6.12.2008 Репутация: нет Всего: 12 |
Использую DDDK0004
Никак не пойму почему bsod. Пробую пообщаться с IO-APIC
вылитает на этих строчках. Может кто подскажет в чем дело? А еще dbgprint не работает. |
|||
|
||||
Pavia |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 418 Регистрация: 6.12.2008 Репутация: нет Всего: 12 |
Судя по всему срыв стека. Такое впечатление что неправильно экспортирую функции.
|
|||
|
||||
ReInit |
|
|||
Новичок Профиль Группа: Участник Сообщений: 11 Регистрация: 14.11.2008 Репутация: 1 Всего: 1 |
ama_kid
Спасибо! Отличная инфа! microxa, Т.е. ты собираешь ДЛЛ и используешь ее как драйвер? Какую версию Делфи ты используешь? Потому что слышал, если собирать МС линкером, то он понимает обьектники только 3-й Делфи, т.к. после 3-й пошел неправильный COFF формат... И спасибо за System/SysInit, я юзал несколько попроще, без поддержки исключений ![]() |
|||
|
||||
ama_kid |
|
|||
![]() АСУТП-кодер ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1460 Регистрация: 5.3.2007 Где: Москва Репутация: 19 Всего: 95 |
Есть подозрение, что экспортировать их надо следующим образом:
Не сильно понятное описание ошибки, телепатировать сложно... ![]() Вообще, для тематических вопросов есть соответствующий раздел форума ![]() Не за что ![]() microxa, действительно, достаточно ценное замечание, использование try...except...end сильно упростит жизнь во многих случаях... -------------------- самурай без меча подобен самураю с мечом, но только без меча |
|||
|
||||
Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
А можно меня ткнуть носом в тот потолок, с которого взялись все (без исключения) константы в напильнике ? ![]() P.S. На всякий случай оговорюсь: я не утверждаю, что что-то "не так", просто не умею воспринимать любые магические числа в коде, акромя разве что нуля и единицы ![]() Это сообщение отредактировал(а) Riply - 7.12.2008, 18:15 |
|||
|
||||
bems |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 3400 Регистрация: 5.1.2006 Репутация: 21 Всего: 88 |
ну как минимум там добавляется not pageable
Добавлено через 5 минут и 9 секунд и еще discardable -------------------- Обижено школьников: 8 |
|||
|
||||
ama_kid |
|
|||
![]() АСУТП-кодер ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1460 Регистрация: 5.3.2007 Где: Москва Репутация: 19 Всего: 95 |
Больше похоже что просто копируются значения, генерируемые мелкомягким линкером. Потому что если этот напильник натравить на нормальный драйвер - эти магические числа равны содержащимся в образе...
-------------------- самурай без меча подобен самураю с мечом, но только без меча |
|||
|
||||
Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
Если это так (просто копируются), то где гарантии, что и у другого драйвера в образе тоже самое ? Или под другим SP-ом или под другой версией Win ? |
|||
|
||||
ReInit |
|
|||
Новичок Профиль Группа: Участник Сообщений: 11 Регистрация: 14.11.2008 Репутация: 1 Всего: 1 |
Riply,
Если ты про характеристики секций, то это комбинации констант IMAGE_SCN_... http://www.wasm.ru/article.php?article=green2red02
|
|||
|
||||
Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
Да я про все, ибо если мне вместо SizeOf(BYTE) напишут 1, то я перестану понимать ![]() Хотя, себе любимой, иногда такое и позволяю ![]() Во. Уже что-то. Спасибо ![]() |
|||
|
||||
microxa |
|
||||||||||||
Новичок Профиль Группа: Участник Сообщений: 2 Регистрация: 2.12.2008 Репутация: 1 Всего: 1 |
Приветствую адептов столь продвинутой "дельфийской магии"
![]()
Насчет констант - мне просто не хотелось перегружать прогу километровыми PAGE_EXECUTE_READ or IMAGE_SCN_MEM_NOT_PAGED и тп. (имеються в модуле windows) Напильник пришлось немного доработать в области "фиксатора" import table:
(гм.. FirstThunk OriginalFirstThunk взяты из описания структур PE формата из windows.h) Переделаные таким образом DLL, работают (по моему опыту) ничуть не хуже слинкованых мc-линкером. Ну и какбы в качестве примера.. Одним из возможных применений драйвера - вызов Ring0 процедур непосредственно в самой программе. Понятное дело - трюк связан с определенным риском, и расчитан на "железячников" более менее знакомых с архитектурой PC/х86 (или желающих изучать это дело). В режиме ядра снимаються проблемы только с операциями in/out и доступом к привелигированиым регистрам и инструкциям CPU. Это в ряде случаев может оказаться недостаточным, например для обращения к физическим адресам памяти, что потребует вызова системных ф-кций. В противном случае несогласование этого вопроса с системой, может приведет к bsod (и даже SEH не пикнет)))... Пример простого драйвера:
Собираеться в любой среде (IDE delphi/CMD32), главное в папку с проектом драйвера не забыть поместить облегченные версии RTL. Для упрощения, здесь адрес процедуры передаеться в драйвер в качестве параметра в DeviceIOControl, а так как user-space программа, экспортировать функции ядра не может, между драйвером и программкой будет некоторый общий интерфейс:
Тестовый пример "хелловорлда" работает исключительно в режиме консольного fullscreen'а (80x25), поскольку маппит район $B8000 (видеопамять текстового режима, стандарт времен царя гороха))). /added Riply, спасибо! благодаря Вашему замечанию теперь я буду поступать так ![]()
Для полноты художественной картины Осталось от DeviceIoControl избавиться (в нем куда больше странностей, касаемо нюансах в параметрах ;) ) Шерлок Холмс был прав, насчет того что голова не чердак, и не стоит ее захламлять! ![]() ммм... даже интересно стало прикрутить к драйверу IRP_MJ_READ/ IRP_MJ_WRITE Это сообщение отредактировал(а) microxa - 8.12.2008, 06:47 |
||||||||||||
|
|||||||||||||
Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
microxa,
Здравствуйте ![]()
Вот скажи-ка мне честно: неужели, ты в следующей строчке сразу понимаешь, что и как создается ? Если да, то не кажется ли тебе, что уж лучше "перегружать прогу километровыми константами", чем свой мозг ? ![]() P.S. Кстати, Шерлок Холмс сравнивал человеческий мозг с чердаком, на котором не так уж и много места ![]() Это сообщение отредактировал(а) Riply - 8.12.2008, 03:32 |
|||
|
||||
ReInit |
|
|||
Новичок Профиль Группа: Участник Сообщений: 11 Регистрация: 14.11.2008 Репутация: 1 Всего: 1 |
Riply,
Шерлок Холмс (точнее Конан Дойль) заблуждался... |
|||
|
||||
EagleXK |
|
|||
![]() Новичок Профиль Группа: Участник Сообщений: 13 Регистрация: 11.9.2006 Где: Украина, Житомир Репутация: нет Всего: нет |
Хмм... Странно, но Ctrl+Alt+Del не перехватился на XP SP2...
|
|||
|
||||
Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
День добрый !
ama_kid, а ты не мог бы дать файлы sysinit.pas и system.pas, которые послужили "прототипом" для dcu-шек ? Ну и командную строчку, с которой собирались ![]() |
|||
|
||||
bems |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 3400 Регистрация: 5.1.2006 Репутация: 21 Всего: 88 |
Riply, в командной строке нужен ключ -Y
Это работало в 7ке. -------------------- Обижено школьников: 8 |
|||
|
||||
jungle |
|
|||
![]() Аппаратный кодер Профиль Группа: Участник Сообщений: 40 Регистрация: 17.1.2006 Где: Беларусь Репутация: нет Всего: нет |
Добрый день!
Можно ли использовать 64-битовый линкер для сборки 64-разрядного драйвера? |
|||
|
||||
Alexeis |
|
|||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 16 Всего: 459 |
Разве он проглотит 32х разрядные бинарники? Кроме того как работать с указателями, ведь они 32х разрядные. Так что скорее всего нельзя. -------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
|||
|
||||
jungle |
|
|||
![]() Аппаратный кодер Профиль Группа: Участник Сообщений: 40 Регистрация: 17.1.2006 Где: Беларусь Репутация: нет Всего: нет |
OK. И еще вопрос, если позволите, многоуваемый All. Автор статьи говорит об отсутствии возможности применить блок try-except-end, но вот в сырцах драйвера тов. microxa для считывания физ. памяти этот блок присутствует. Причем, microxa заявляет о нормальной компиляции и т.д. И кто не прав?
|
|||
|
||||
Alexeis |
|
|||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 16 Всего: 459 |
Есть такие соображения, что если код драйвера вызывается при обработке прерывания, то аппаратное исключение может не сработать ведь его приоритет может оказаться более низким, чем у кода обработчика прерывания, вот он и будет ждать окончания работы.
-------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
|||
|
||||
Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
Присутствует - не означает работает. Надо у него спросить на чем основано его утверждение о "нормальной компиляции". На том, что успешно создается sys - файл ? Если так, то этого мало. Код ama-kid`а тоже будет успешно собираться и компилироваться с try/finally блоками. Но вот если "перехватить" жалобные крики dcc32.exe в процессе компиляции, ![]() то там можно увидеть примерно следующие строки: Shd_QuerySys.obj: error LNK2001: uresolved external symbol @@HandleFinally$qqrv |
|||
|
||||
Alexeis |
|
|||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 16 Всего: 459 |
Это уже ошибка линкера. Но ведь линкер используется другой, может он подставляет туда то что нужно из RTL. -------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
|||
|
||||
Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
Угу. Перепутала. Sorry.
Полностью согласна. Именно поэтому я и написала, что "Надо у него спросить на чем основано его утверждение" ![]() А без его пояснений, нам остается только гадать на кофейной гуще ![]() |
|||
|
||||
Акакий |
|
|||
![]() Новичок Профиль Группа: Участник Сообщений: 28 Регистрация: 6.7.2009 Репутация: нет Всего: нет |
Всем здравствуйте! Пишу (точнее - пытаюсь написать
![]() Перехватываю ZwMapViewOfSection. Новая функция NewZwMapViewOfSection при выполнении некоторых условий должна изменять содержимое памяти, возвращенное "оригинальной" ZwMapViewOfSection. Код замещающей функции:
В данном примере изменение памяти происходит в случае, если ее 2-й байт равен 81 (буква "Q"). Открываю блокнотом текстовый файл, начинающийся с "QQQQQ....". Блокнот запускается после чего виндовоз уходит в перезагрузку. Если убрать присваивание BaseAddress:=pp, то перезагрузки не происходит. Я не делаю там Unmap(BaseAddress), т.к. это отладочный вариант. Попытка воспользоваться ZwAllocateVirtualMemory не помогла. Пожалуйста, объясните мне, как нужно правильно делать. P.S. Сильно подозреваю, что в моем коде, мягко выражаясь, много неправильного, а более точно - там вообще один бред :( Но все-равно я верю в то, что найдется добрый человек и укажет мне на мои ошибки ![]() Это сообщение отредактировал(а) Акакий - 6.7.2009, 16:29 |
|||
|
||||
Riply |
|
||||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
Т.е. при любом вызове ZwMapViewOfSection (кем угодно !) она с вероятностью 1/256 возвращает бред, а мы удивляемся почему падает система ? ![]() Т.е. при отладке память бесконечна ? ![]()
Осознание сего факта - большой шаг вперед (без смайлика) Для того чтобы перехватывать, надо очень хорошо понимать и чуствовать как работает перехватываемая функция. Какие, где и когда будут последствия от твоего изменения. У тебя этого понимания пока нет. И двумя, тремя словами его не дать. Так что, садись за книги. |
||||
|
|||||
Акакий |
|
||||||
![]() Новичок Профиль Группа: Участник Сообщений: 28 Регистрация: 6.7.2009 Репутация: нет Всего: нет |
Riply, благодарю за отзыв.
Да это я знаю, просто это "сиюминутный" отладочный вариант. Ну добавлю я анализ хендла на принадлежность его блокноту - это ничего не изменит. Я гружу драйвер, открываю блокнотом все файлы, начинающиеся не с "QQQQQ..." и все прекрасно открывается, но как только я открою "QQQQQ..." - сразу reboot. Сделал перехват ZwRead/WriteFile, все прекрасно работает(происходит расшифровка/шифрование "на лету"). А блокнот пользуется "маппингом" вот и встала задача перехвата ZwMapViewOfSection.
См. выше ![]()
Ну читал я все эти книги (заранее принимаю аплодисменты, но все же не верю в свою безнадежность ![]() Перехватом я занимаюсь уже давно, только вот в ринг 3. В ринг 0 кодил, испрользуя Call Gate (шлюз вызова в GDT). Это сообщение отредактировал(а) Акакий - 6.7.2009, 20:38 |
||||||
|
|||||||
Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
Так. Давай с самого начала. Ты спрашиваешь почему "виндовоз уходит в перезагрузку". Я дала тебе (для начала) пару причин, по которым это может происходить. 1. При "заргузке блокнота" ZwMapViewOfSection может вызываться отнюдь не один раз и не только для чтения содержимого твоего файла. Откуда у тебя может быть уверенность, что при загрузке какой-нибудь библиотеки, ты не возвращаешь мусор вместо ее образа ? 2. ZwMapViewOfSection может быть вызвана не только блокнотом, а кем угодно (Система живет и работает). Откуда у тебя уверенность, что в течении твоего опыта она не вызвалась 567 раз и суммарный объем выделенной тобой памяти при этом не привысил максимально возможный ? (Кстати и здесь существует вероятность возврата мусора вместо образа) Мне кажется, что сначала надо исключить возможность перезагрузки по любой из этих причин, и только потом идти дальше. |
|||
|
||||
Акакий |
|
|||
![]() Новичок Профиль Группа: Участник Сообщений: 28 Регистрация: 6.7.2009 Репутация: нет Всего: нет |
1. Сделал проверку на принадлежность хэндла процессу блокнота. 2. Заменил символ "Q" уникальной комбинацией из 100 символов (сильно сомневаюсь, что данная последовательность байтов может быть где-то еще). Результат тот же. Уточню свой вопрос: параметр BaseAddress функции ZwMapViewOfSection содержит адрес переменной, в которую ZwMapViewOfSection засылает адрес спроецированного объекта (в моем случае - файла) или ZwMapViewOfSection шлет этот адрес непосредственно в переменную BaseAddress (Var BaseAddress)? Мелкомягкие пишут, что BaseAddress - это "Pointer to a variable that receives the base address of the view". Значит, вроде как BaseAddress должен указывать на переменную с адресом. Да и у Рема в его NativeAPI.pas этот параметр идет без "var". Только вот я пробовал оба варианта - результат одинаковый - при попытке подменить BaseAddress, или записать по адресу BaseAddress новый адрес "спроецированной" памяти виндовоз уходит в ребут. |
|||
|
||||
Riply |
|
||||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
В данном вопросе я их слушаюсь и все работает ![]() Устрани и остальные скользкие моменты:
у меня нет уверенности в том, что при любом вызове, ViewSize <> nil, BaseAddress <> nil, BaseAddress^ <> nil. Так же у меня нет уверенности, что ViewSize^ < максимальный размер памяти, который мы можем выделить. А почему тогда сначала не оттестировать перехват в user mode ? (Тем более, если нет уверенности в правильном понимании параметров ф-ии ZwMapViewOfSection) |
||||
|
|||||
Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
||||
|
||||
Акакий |
|
||||
![]() Новичок Профиль Группа: Участник Сообщений: 28 Регистрация: 6.7.2009 Репутация: нет Всего: нет |
Хорошая мысь, спасибо, нужно попробовать. В user mode я перехватывал MapViewOfFile/Ex, но блокнот ее не вызывает, что есть несколько странно(блокнот пользуется только функциями Zw?). Попробую перехватить ZwMapViewOfSection из ring3, но у меня странное предчуствие, что из блокнота она не будет вызываться.
Это да, при выделении памяти в драйвере я получаю память в сегменте данных нулевого кольца(селектор с RPL=0), а в блокноте, скорее всего, имеем 3-е кольцо (RPL=2) и может получаться некорректное смещение относительно базы сегмента данных блокнота. Пробовал делать ZwAllocateVirtualMemory, но она не работает, по крайней мере при вызове из ring 3. |
||||
|
|||||
Акакий |
|
|||
![]() Новичок Профиль Группа: Участник Сообщений: 28 Регистрация: 6.7.2009 Репутация: нет Всего: нет |
Перехватил ZwMapViewOfSection в ринг 3. Блокнот вызывает эту функцию, но использует ее только для вывода списка файлов, а сами файлы он читает с помощью чего-то другого. Интересно, при перехвате этой функции в ринг 0 она вызывается и при загрузке блокнотом файлов. Отсюда и происходят мои сомнения о корректности перехвата Zw функций в ринг 3. Кстати, на форуме rsdn, кто-то "жаловался", что от блокнота не приходит IRP_MJ_READ.
|
|||
|
||||
Акакий |
|
|||
![]() Новичок Профиль Группа: Участник Сообщений: 28 Регистрация: 6.7.2009 Репутация: нет Всего: нет |
Все, разобрался.
![]()
Riply, спасибо. Это сообщение отредактировал(а) Акакий - 7.7.2009, 13:54 |
|||
|
||||
Акакий |
|
|||
![]() Новичок Профиль Группа: Участник Сообщений: 28 Регистрация: 6.7.2009 Репутация: нет Всего: нет |
Хочу выразить огромную благодарность ama_kid за то, что он бескорыстно делится с нами своими знаниями и своим трудом. Уважаемый ama_kid, если бы Вы еще написали статью о создании драйвера виртуального диска, то это была бы такая Вещь, переоценить которую было бы просто невозможно. Во всем нете нет ни одной подобной статьи. Все только для С++, а с этого, осмелюсь заявить, кривого языка, у меня не получается переводить на Delphi. Товарищи, да здравствует Delphi+Assembler!
|
|||
|
||||
Акакий |
|
|||
![]() Новичок Профиль Группа: Участник Сообщений: 28 Регистрация: 6.7.2009 Репутация: нет Всего: нет |
Ура! После долгих изысканий, изучений и мучений я все-таки сделал драйвер виртуального диска! Жалко только, что драйвер этот я сделал на С++. Итого, со всей ответственностью могу заявить, что сделать драйвер диска на Delphi в принципе невозможно, для этого, как минимум, прийдется переводить ПОЧТИ ВСЕ сишные библиотеки на Delphi. Точнее - теоретически написать драйвер на Delphi можно, но только теоретически(примерно так же, как и создать машину времени).
Конечно, статья, написанная ama_kid может пригодиться для начального ознакомления "дельфистов" с драйверами. Но, к сожалению, в практическом плане статья эта абсолютно бесполезна. Все то, что могут делать "драйвера", приведенные в этой статье(и вообще, написанные на Delphi), я смогу сделать на Delphi через Call Gate безо всяких драйверов. Модератор: Акакий сможет продолжить сообщать неправдивые сведения не раньше чем через два дня. Это сообщение отредактировал(а) bems - 11.2.2010, 14:58 |
|||
|
||||
FalseMaster |
|
|||
Новичок Профиль Группа: Участник Сообщений: 21 Регистрация: 18.11.2009 Репутация: нет Всего: нет |
Модератор: Сообщение скрыто. |
|||
|
||||
birks |
|
|||
Новичок Профиль Группа: Участник Сообщений: 1 Регистрация: 13.11.2011 Репутация: нет Всего: нет |
А как с помощью данного примера отправить допустим нажатие клавиши f1 ?
|
|||
|
||||
FalseMaster |
|
|||
Новичок Профиль Группа: Участник Сообщений: 21 Регистрация: 18.11.2009 Репутация: нет Всего: нет |
Модератор: SDK не SDK, а тема не создана для ссылок Это сообщение отредактировал(а) bems - 25.8.2013, 00:57 |
|||
|
||||
![]() ![]() ![]() |
Правила форума "Delphi: WinAPI и системное программирование" | |
|
Запрещено: 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, bartram, MetalFan, bems, Poseidon, Rrader, Riply. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Delphi: WinAPI и системное программирование | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |