Создание драйверов. Часть 5. Фильтр драйвер. В этой части цикла статей, рассматривается создание и тестирование фильтр драйвера – это драйвер, основной функцией которого является обработка проходящих через него IRP пакетов, это возможно благодаря многоуровневой модели драйверов Windows, где несколько драйверов можно выстроить в одну цепочку, соответственно добавляя новые возможности нижележащему драйверу.
Это может быть шифрование данных, форматирование данных, обработка ошибок, вплоть до уничтожения информации или ее логирования и скрытия.
Передача и обработка запросов ввода/вывода производится в виде пакетов IRP, которые формирует диспетчер ввода/вывода, находящийся в ядре Windows, где для каждого драйвера выделяется своя собственная структура стека IRP, то есть если в цепочке находится три драйвера, то пакет будет иметь в своей структуре стека три указателя на IO_STACK_LOCATION, для каждого драйвера. Схематически многоуровневая модель показана на рисунке:
В качестве устройства-цели к которому мы будем добавлять наш фильтр драйвер, выступит \Device\Beep, это устройство которое отвечает за работу системного динамика. Драйвер фильтр должен обрабатывать те же самые функции, что драйвер находящийся ниже его, а также должен иметь одинаковые флаги создаваемого объекта устройства. Ниже приводится код драйвера фильтра и пояснения:
#include "ntddk.h" PDEVICE_OBJECT pdDevObjTarg; PFILE_OBJECT FileObj = NULL; /*--------------------------------------------------------------*/ VOID FilterDriverUnload (IN PDRIVER_OBJECT fdo); NTSTATUS DispatchPass (IN PDEVICE_OBJECT fdo, IN PIRP irp); /*--------------------------------------------------------------*/ NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath) { NTSTATUS status; UNICODE_STRING devName; PDEVICE_OBJECT fdo; int i; DbgPrint("DriverEntry..."); for(i=0; i<IRP_MJ_MAXIMUM_FUNCTION; i++) { DriverObject->MajorFunction[i] = DispatchPass; } DriverObject->DriverUnload = FilterDriverUnload; status = IoCreateDevice(DriverObject, sizeof(PDEVICE_OBJECT),NULL,FILE_DEVICE_BEEP, 0,FALSE,&fdo); if(!NT_SUCCESS(status))return status; fdo->Flags |= 0x44; RtlInitUnicodeString(&devName,L"\\Device\\Beep"); status = IoGetDeviceObjectPointer(&devName,STANDARD_RIGHTS_ALL,&FileObj,&pdDevObjTarg); if(!NT_SUCCESS(status))return status; DbgPrint("IoGetDeviceObjectPointer -ok-"); IoAttachDeviceToDeviceStack(fdo,pdDevObjTarg); if(!NT_SUCCESS(status))return status; DbgPrint("IoAttachDeviceToDeviceStack -ok-"); return STATUS_SUCCESS; } VOID FilterDriverUnload(IN PDRIVER_OBJECT fdo) { IoDetachDevice(pdDevObjTarg); ObDereferenceObject(FileObj); IoDeleteDevice(fdo->DeviceObject); DbgPrint("FilterDriverUnload"); } NTSTATUS DispatchPass(IN PDEVICE_OBJECT fdo, IN PIRP irp) { PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(irp); if(IrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) { DbgPrint("-IOCTL-"); } IoSkipCurrentIrpStackLocation(irp); return IoCallDriver(pdDevObjTarg,irp); }
PDEVICE_OBJECT pdDevObjTarg; — глобальная переменная для хранения указателя на устройство находящееся ниже фильтра.
PFILE_OBJECT FileObj = NULL; — переменная для хранения указателя на объект-файл, для выгрузки нижележащего драйвера.
for(i=0; i
}
В примере мы делаем одну точку входа в драйвер для всех рабочих процедур драйвера, выглядит она вот так:
NTSTATUS DispatchPass(IN PDEVICE_OBJECT fdo, IN PIRP irp)
{
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(irp);
if(IrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
{
DbgPrint(«-IOCTL-«);
}
IoSkipCurrentIrpStackLocation(irp);
return IoCallDriver(pdDevObjTarg,irp);
}
где мы просто получаем указатель на текущий стек IRP пакета, и если к драйверу обратились при помощи функции DeviceIoControl, то мы отлавливаем код рабочей процедуры и выводим сообщение.
IoSkipCurrentIrpStackLocation(irp);
return IoCallDriver(pdDevObjTarg,irp);
здесь фильтр просто пропускает пакеты без модификаций.
status = IoCreateDevice(DriverObject,sizeof(PDEVICE_OBJECT),NULL,FILE_DEVICE_BEEP,0,FALSE,&fdo);
if(!NT_SUCCESS(status))return status;
fdo->Flags |= 0x44;
Создаем безымянное устройство и не имеющее символьной ссылки, и добавляем флаги как у нижележащего устройства.
RtlInitUnicodeString(&devName,L»\\Device\\Beep»);
Копируем строку с именем устройства к которому хотим присоединить наш фильтр.
status = IoGetDeviceObjectPointer(&devName,STANDARD_RIGHTS_ALL,&FileObj,&pdDevObjTarg);
if(!NT_SUCCESS(status))return status;
получаем указатель на объект-устройство нижележащего драйвера.
IoAttachDeviceToDeviceStack(fdo,pdDevObjTarg);
if(!NT_SUCCESS(status))return status;
подключаем наш фильтр к устройству.
VOID FilterDriverUnload(IN PDRIVER_OBJECT fdo)
{
IoDetachDevice(pdDevObjTarg);
ObDereferenceObject(FileObj);
IoDeleteDevice(fdo->DeviceObject);
DbgPrint(«FilterDriverUnload»);
}
Функция выгрузки драйвера, в которой удаляется из стека фильтр, удаляется объект-файл и сам фильтр.
Код программы запуска драйвера:
#include <windows.h> #include <iostream> #include <conio.h> using namespace std; void ErrorView(); int main() { cout<<" ------------------- "<<endl; cout<<"| Loader is running |"<<endl; cout<<" ------------------- "<<endl; SC_HANDLE sch = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); if(sch) { SC_HANDLE schService = CreateService(sch,"FilterDriver","FilterDriver", SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER,SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, "C:\\FilterDriver\\sys\\objchk\\i386\\FilterDriver.sys", NULL,NULL,NULL,NULL,NULL); if(schService) { if(StartService(schService,NULL,NULL)) { cout<<"PAUSE: Press any key to exit pause..."<<endl; while(!getch()); SERVICE_STATUS ServiceStatus; if(ControlService(schService,SERVICE_CONTROL_STOP,&ServiceStatus)) {cout<<"ControlService - status ok"<<endl;} else{cout<<"Error ControlService..."<<endl;ErrorView();} if(DeleteService(schService)) {cout<<"DeleteService - status ok"<<endl;} else{cout<<"Error DeleteService..."<<endl;ErrorView();}/**/ if(CloseServiceHandle(schService)) {cout<<"CloseServiceHandle - status ok"<<endl;} else{cout<<"Error CloseServiceHandle..."<<endl;ErrorView();}/**/ if(CloseServiceHandle(sch)) {cout<<"CloseServiceHandle - status ok"<<endl;} else{cout<<"Error CloseServiceHandle..."<<endl;ErrorView();}/**/ }else{cout<<"Error StartService..."<<endl;ErrorView();} }else{cout<<"Error CreateService..."<<endl;ErrorView();} }else{cout<<"Error OpenSCManager..."<<endl;ErrorView();} cout<<" ------------------- "<<endl; cout<<"| Loader is stopped |"<<endl; cout<<" ------------------- "<<endl; cout<<"Press any key to exit"<<endl; while(!getch()); return 0; } void ErrorView() { LPVOID lpMsgBuf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL,GetLastError(), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPTSTR)&lpMsgBuf,0,NULL); CharToOem((LPTSTR)lpMsgBuf,(LPTSTR)lpMsgBuf); cout<<(LPCTSTR)lpMsgBuf<<endl; LocalFree(lpMsgBuf); }
Когда программа запуска драйвера запущена и находится в режиме паузы, то можно увидеть что фильтр присоединился к устройству:
И теперь достаточно запустить любую программу, которая будет вызывать функцию Beep, например такую:
#ifdef NDEBUG #pragma optimize("gsy",on) #pragma comment(linker,"/IGNORE:4078 /IGNORE:4089") #pragma comment(linker,"/RELEASE") #pragma comment(linker,"/merge:.rdata=.data") #pragma comment(linker,"/merge:.text=.data") #pragma comment(linker,"/merge:.reloc=.data") #pragma comment(linker,"/ENTRY:WinMainX") #pragma comment(linker,"/NODEFAULTLIB") #if _MSC_VER >= 1000 #pragma comment(linker,"/FILEALIGN:0x200") #endif #endif #pragma comment (exestr, "Code by Lazy_elf") const do1=130,re=146,mi=164,fa=174,sol=196, la=220,si=246,do2=261,re2=293,mi2=329; #include <windows.h> int WinMainX(void) { Beep(sol,500/2); Beep(do2,1500/2); Beep(sol,1000/2); Beep(la, 500/2); Beep(si, 1500/2); Beep(mi, 1000/2); Beep(mi, 500/2); Beep(la, 1500/2); Beep(sol,1000/2); Beep(fa, 500/2); Beep(sol,1500/2); Beep(do1,1000/2); Beep(do1,500/2); Beep(re, 1000/2); Beep(re, 500/2); Beep(mi, 500/2); Beep(fa, 1000/2); Beep(fa, 500/2); Beep(sol,500/2); Beep(la, 1000/2); Beep(si, 500/2); Beep(do2,500/2); Beep(re2,2000/2); return 0; }
Сразу становится видно, что идет фильтровка кода IRP_MJ_DEVICE_CONTROL:
Добрый день!
Необходимо написание фильтрующего драйвера Штрих-ФР-К для задач нашей компании.
Задача несложная: при отбитии чека (всегда одно наименование, количество Х цену = сумма) по определенному отделу (8)
8 Наим. 5 X 25 руб
Итого: 125 руб
Необходимо разбивать один заказ на два по алгоритму (второй заказ по 10 отделу равен: количество первого наименования Х 1 руб,
при этом цена товара по 8 отделу уменьшается на 1 руб., чтобы общий итог чека не изменился )
8 Наим. 5 Х 24 руб
10 Авансы 5 Х 1 руб
Итого: 125 руб
При отбитии чека по любым другим отделам кроме 8, разбивка не нужна, чеки без изменений.
Прошу сообщить сколько будет стоить такая доработка и какой срок необходим.
С уважением, специалист по эксплуатации, Артур Фратович.
+7 (3435) 92 00 83
Здравствуйте Артур, к сожалению, не занимаюсь более написанием драйверов и вообще программированием. Советую вам обратится по следующим адресам: http://freelansim.ru и https://www.free-lance.ru/.
Обсуждение закрыто.