Создание драйверов. Часть 2

Начинаем наращивать наш драйвер, будем использовать скелет, который мы создали в прошлой статье. В данном примере мне хотелось бы объяснить, как осуществляется «общение» с драйвером. Для этого как Вы знаете, существует API функция:

BOOL DeviceIoControl(
HANDLE hDevice, // хэндл устройства
DWORD dwIoControlCode, // управляющий код
LPVOID lpInBuffer, // передаваемый буфер данных
DWORD nInBufferSize, // размер буфера данных
LPVOID lpOutBuffer, // возвращаемый буфер данных
DWORD nOutBufferSize, // размер буфера данный
LPDWORD lpBytesReturned, // подсчет возвратившихся байтов
LPOVERLAPPED lpOverlapped // указатель на структуру OVERLAPPED
);

Данная функция используется в загрузчике драйвера, ниже представлен код загрузчика, где выделенным показано, что нужно добавить:

#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,
"MyFirstDriver","MyFirstDriver",SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER,SERVICE_DEMAND_START,SERVICE_ERROR_NORMAL,
"C:\\MyFirstDriver\\sys\\objchk\\i386\\MyFirstDriver.sys",
NULL,NULL,NULL,NULL,NULL);
 
                if(schService)
                {
                        if(StartService(schService,NULL,NULL))
                        {
                                HANDLE hHandl = CreateFile("\\\\.\\MyFirstDriver",
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,NULL);
                                if(hHandl != INVALID_HANDLE_VALUE)
                                {
                                        DWORD dwReturnBytes;
                                        if(!DeviceIoControl(hHandl,
NULL,/*(*/NULL,NULL,/*)(*/NULL,NULL/*)*/,
&dwReturnBytes,NULL))
{cout<<"Error ControlService..."<<endl;ErrorView();}
 
/*****/
 
                                        unsigned long ioctl = 0x801;
 
                                        if(!DeviceIoControl(hHandl,
ioctl,/*(*/NULL,NULL,/*)(*/NULL,NULL/*)*/,
&dwReturnBytes,NULL))
{cout<<"Error ControlService..."<<endl;ErrorView();}
 
                                        ioctl = 0x802;
 
                                        if(!DeviceIoControl(hHandl,
ioctl,/*(*/NULL,NULL,/*)(*/NULL,NULL/*)*/,
&dwReturnBytes,NULL))
{cout<<"Error ControlService..."<<endl;ErrorView();}
 
/*****/
 
                                        /**/if(CloseHandle(hHandl))
{cout<<"CloseHandle - status ok"<<endl;}
else{cout<<"Error CloseHandle..."<<endl;ErrorView();}/**/
 
                                        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 CreateFile..."<<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 continue"<<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);
}

В коде драйвера необходимо добавить в функцию обработчика IOCTL запросов следующее:

#include "ntddk.h"
/*--------------------------------------------------------------*/
NTSTATUS MyFirstDriverCreate  (IN PDEVICE_OBJECT fdo, IN PIRP irp);
NTSTATUS MyFirstDriverClose   (IN PDEVICE_OBJECT fdo, IN PIRP irp);
NTSTATUS MyFirstDriverControl (IN PDEVICE_OBJECT fdo, IN PIRP irp);
VOID     MyFirstDriverUnload  (IN PDRIVER_OBJECT fdo);
/*--------------------------------------------------------------*/
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
{
        NTSTATUS       status;
        PDEVICE_OBJECT fdo;
        UNICODE_STRING devName;
        UNICODE_STRING devLink;
 
#if DBG
        DbgPrint("in DriverEntry");
#endif
 
        DriverObject->DriverUnload                         = MyFirstDriverUnload;
        DriverObject->MajorFunction[IRP_MJ_CREATE]         = MyFirstDriverCreate;
        DriverObject->MajorFunction[IRP_MJ_CLOSE]          = MyFirstDriverClose;
        DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MyFirstDriverControl;
 
        RtlInitUnicodeString(&devName,L"\\Device\\MyFirstDriver");
 
        status = IoCreateDevice(DriverObject,sizeof(PDEVICE_OBJECT),&devName,FILE_DEVICE_UNKNOWN,0,FALSE,&fdo);
        if(!NT_SUCCESS(status))return status;
 
#if DBG
        DbgPrint("IoCreateDevice status ok");
#endif
 
        RtlInitUnicodeString(&devLink,L"\\??\\MyFirstDriver");
 
        status = IoCreateSymbolicLink(&devLink,&devName);
        if(!NT_SUCCESS(status))
        {
                IoDeleteDevice( fdo );
                return status;
        }
 
#if DBG
        DbgPrint("DriverEntry STATUS_SUCCESS");
#endif
        
        return STATUS_SUCCESS;
}
/*--------------------------------------------------------------*/
NTSTATUS MyFirstDriverCreate(IN PDEVICE_OBJECT fdo, IN PIRP irp)
{
#if DBG
        DbgPrint("Run MyFirstDriverCreate");
#endif
        irp->IoStatus.Status      = STATUS_SUCCESS;
        irp->IoStatus.Information = 0;
        IoCompleteRequest(irp, IO_NO_INCREMENT);
                
        return STATUS_SUCCESS;
}
 
NTSTATUS MyFirstDriverClose(IN PDEVICE_OBJECT fdo, IN PIRP irp)
{
#if DBG
        DbgPrint("Run MyFirstDriverClose");
#endif
        irp->IoStatus.Status      = STATUS_SUCCESS;
        irp->IoStatus.Information = 0;
        IoCompleteRequest(irp, IO_NO_INCREMENT);
 
        return STATUS_SUCCESS;
}
 
NTSTATUS MyFirstDriverControl (IN PDEVICE_OBJECT fdo, IN PIRP irp)
{
/**********************************************************************/
        PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(irp);
        ULONG ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
        
        if(ControlCode == 0x801)
        {
                #if DBG
                        DbgPrint("IoControlCode 0x801: %d",ControlCode);
                #endif
                
        }
        if(ControlCode == 0x802)
        {
                #if DBG
                        DbgPrint("IoControlCode 0x802: %d",ControlCode);
                #endif
        }
/**********************************************************************/
 
        irp->IoStatus.Status      = STATUS_SUCCESS;
        irp->IoStatus.Information = 0;
        IoCompleteRequest(irp, IO_NO_INCREMENT);
 
        return STATUS_SUCCESS;
}
 
VOID MyFirstDriverUnload(IN PDRIVER_OBJECT fdo)
{
        UNICODE_STRING deviceLink;
        RtlInitUnicodeString(&deviceLink,L"\\??\\MyFirstDriver");
        IoDeleteSymbolicLink(&deviceLink);
        IoDeleteDevice(fdo->DeviceObject);
 
#if DBG
        DbgPrint("Run MyFirstDriverUnload - delete link");
#endif
}
/*--------------------------------------------------------------*/

Как Вы видите мы использовали новую для нас функцию IoGetCurrentIrpStackLocation, которая в качестве аргумента принимает указатель на IRP – это пакет запроса, который представляет из себя структуру состоящую из двух частей. Функция возвращает указатель на стек ввода/вывода для данного драйвера. Стек ввода/вывода тоже представляет из себя структуру, описание которой Вы сможете найти в заголовочных файлах «wdm.h» или «ntddk.h». Получив указатель, мы проверяем управляющий код, и соответственно выводим отладочную информацию.
Создание драйверов