За основу был взят драйвер из этой статьи.
Он был немного изменен и в место поиска заданного модуля, выводит в отладчик список всех загруженных модулей.
Declare DriverEntry(*DriverObject, *RegistryPath) ImportC "ntoskrnl.lib" DbgPrint(*String) memset(*mem, Byte, Size) EndImport Import "ntoskrnl.lib" ZwQuerySystemInformation(SysInfoClass, *SysInfo, SysInfoLength.l, *ReturnLength) ExAllocatePool(PoolType, NumBytes) ExFreePool(*Point) EndImport !extrn _DbgPrint !extrn _memset !extrn _ZwQuerySystemInformation@16 !extrn _ExAllocatePool@8 !extrn _ExFreePool@4 !extrn _PB_PokeS@8 !extrn PB_PeekL !public PureBasicStart !section '.code' code readable executable align 8 !PureBasicStart: *A=@DriverEntry() !jmp [p_A] ; Переход в процедуру DriverEntry(). XIncludeFile #PB_Compiler_Home+"DDK\StringDr.pbi" EnableExplicit Structure DrArray_SMI Arrays.SYSTEM_MODULE_INFORMATION[1] EndStructure ; Процедура загрузки драйвера. Вызывается однократно при его запуске. Procedure DriverEntry(*DriverObject.DRIVER_OBJECT, *RegistryPath.UNICODE_STRING) Protected cb.l, *p, *pArray.DrArray_SMI Protected dwNumModules.l ;, *pMessage Protected Buffer.s{128}, Temp DbgPrint(@"LoadDriver") cb=0 ZwQuerySystemInformation(#SystemModuleInformation, @*p, 0, @cb) If cb <> 0 ; cb + 32 *p = ExAllocatePool(#PagedPool, cb) If *p<>#Null If ZwQuerySystemInformation(#SystemModuleInformation, *p, cb, @cb)= #STATUS_SUCCESS *pArray = *p dwNumModules = PeekL(*pArray) PokeS(@Buffer, "Bytes: ") : Temp=8 Temp+StrDr(@Buffer+Temp, 128-Temp, cb) PokeS(@Buffer+Temp, "; Address: 0x") : Temp+14 Temp+HexDr(@Buffer+Temp, 128-Temp, *p) PokeS(@Buffer+Temp, "; Modules: ") : Temp+12 Temp+StrDr(@Buffer+Temp, 128-Temp, dwNumModules) DbgPrint(@Buffer) memset(@Buffer, 0, 128) *pArray + 4 Temp=0 While Temp < dwNumModules DbgPrint(@*pArray\Arrays[Temp]\ImageName[0]) Temp+1 Wend EndIf ExFreePool(*p) EndIf EndIf ; Собщаем об ошибке чтобы система выгрузила драйвер. ProcedureReturn #STATUS_DEVICE_CONFIGURATION_ERROR EndProcedure
Я не буду рассматривать подробно код, т. к. это уже сделано в вышеуказанной статье.
Рассмотрим только отдельные моменты, которых нет в той статье или которые отличаются.
Функции ядра импортируются из библиотеки ntoskrnl.lib. Оператор ImportC, импортирует используя соглашение вызова cdecl, а оператор Import импортирует функции используя соглашение stdcall.
Далее функции объявляются оператором ассемблера FASM - extrn. Восклицательный знак перед ними означает что данные строки не обрабатывает транслятор PureBasic и они будут переданы в неизменном виде FASM'у.
Далее располагается метка PureBasicStart, которая так же в неизменном виде будет передана FASM'у. Это точка входа с которой начинается выполнение программы, в нашем случае, драйвера. За меткой следует переход в процедуру DriverEntry(), которая должна вызываться при старте драйвера. Нужно отметить что в данном случае ее имя может быть другим, но по традиции оно именно такое, какое заданно.
Оператор EnableExplicit включает явное объявление переменных. По умолчанию переменные объявлять не обязательно, но в случае драйвера, ошибка может слишком дорого стоить, поэтому подстрахуемся.
В процедуре DriverEntry(), в первую очередь отправляется отладочное сообщение с текстом "LoadDriver". Затем, первым вызовом функции ZwQuerySystemInformation() узнаем сколько байт нужно под данные. Этот вызов естественно завершится с ошибкой, т. к. мы задали размер буфера *p, равным 0. Но зато в переменной cb будет значение требуемого размера буфера. Далее запрашиваем у системы блок памяти функцией ExAllocatePool() и если его успешно получили, то снова вызываем функцию ZwQuerySystemInformation(). На сей раз, был указан необходимый размер буфера и вызов функции должен пройти успешно, если конечно за это время не появился новый модуль, что маловероятно. Если вызов успешный, то считываем из первых четырех байт полученных данных, число модулей, и выводим их в отладчик, а так же адрес и число байт. Далее располагается массив структур с данными модулей. Нас интересуют только имена этих модулей, а они хранятся в статическом массиве символов ImageName. Их мы извлекаем из массива структур в цикле While - Wend в котором выводятся в отладчик имена всех загруженных модулей. После чего, освобождается запрошенная память, функцией ExFreePool().
Запомните, в режиме ядра нужно освобождать все ресурсы, которые нам больше не нужны. Даже если драйвер выгрузится, то в отличие от режима пользователя, ресурсы все равно будут заняты драйвером и система их не освободит!
При завершении процедуры, возвращается код ошибки #STATUS_DEVICE_CONFIGURATION_ERROR, что поведет к выгрузке драйвера.
Если же процедура DriverEntry() сообщит что ошибок нет, то драйвер так и останется висеть в памяти, а нам это не нужно, ведь весь код находится в этой процедуре и нужно завершить работу драйвера при завершении процедуры.
Итак, копируйте код в редактор PureBasic. Если кто не знает, его можно скачать здесь.
Затем компилируйте выбрав в меню "Компилятор", пункт "Создать драйвер". Если до этого исходный текст драйвера не был сохранен, то его придется сохранить. Потом указываем место сохранения драйвера и если в коде ошибок нет (а их нет, разве что вы неправильно скопировали код со станицы), то будет создан драйвер в указанном месте.
Как видите, создать драйвер не сложнее чем обычную программу.
Перед проделыванием нижеследующего, обязательно сохраните все документы, т. к. возможно появление BSoD'а (синего экрана смерти).
Теперь мы имеем драйвер и его нужно запустить чтобы посмотреть как он работает.
С помощью меню "Инструменты" среды PureBasic, запускаете два инструмента, имеющие имена Dbgview и KmdManager. В KmdManager указываете путь к драйверу. Далее последовательно нажимаете следующие кнопки в окне: "Register", "Run" и "Unregister". Кнопку "Stop" после "Run" нажимать не нужно, потому что драйвер сообщил об ошибке и система сама его выгрузила, т. е. проделала действие эквивалентное кнопке "Stop".
Если все сделано правильно, то вы увидите следующее:
Скачать файлы к статье можно здесь. http://pure-basic.narod.ru/forum_files/ … elPool.zip