Доброго! Вобщем пишу свой первый драйвер. Для начала собрал утилиту instdrv.exe (у меня - starter.exe): Код (Text): /*++ Copyright (c) 1993 Microsoft Corporation Module Name: Instdrv.c Abstract: A simple Win32 app that installs a device driver Environment: user mode only Notes: See readme.txt Revision History: 06-25-93 : created --*/ #include <windows.h> #include <stdio.h> #include <stdlib.h> #include <string.h> BOOL InstallDriver( IN SC_HANDLE SchSCManager, IN LPCTSTR DriverName, IN LPCTSTR ServiceExe ); BOOL RemoveDriver( IN SC_HANDLE SchSCManager, IN LPCTSTR DriverName ); BOOL StartDriver( IN SC_HANDLE SchSCManager, IN LPCTSTR DriverName ); BOOL StopDriver( IN SC_HANDLE SchSCManager, IN LPCTSTR DriverName ); BOOL OpenDevice( IN LPCTSTR DriverName ); VOID __cdecl main( IN int argc, IN char *argv[] ) /*++ Routine Description: Arguments: Return Value: --*/ { SC_HANDLE schSCManager; if (argc != 3) { char currentDirectory[128]; printf ("usage: instdrv <driver name> <.sys location>\n"); printf (" to install a kernel-mode device driver, or:\n"); printf (" instdrv <driver name> remove\n"); printf (" to remove a kernel-mode device driver\n\n"); GetCurrentDirectory (128, currentDirectory ); printf (" Example: instdrv simpldrv %s\\obj\\i386\\simpldrv.sys\n", currentDirectory ); exit (1); } schSCManager = OpenSCManager (NULL, // machine (NULL == local) NULL, // database (NULL == default) SC_MANAGER_ALL_ACCESS // access required ); if (!_stricmp (argv[2], "remove" )) { StopDriver (schSCManager, argv[1] ); RemoveDriver (schSCManager, argv[1] ); } else { InstallDriver (schSCManager, argv[1], argv[2] ); StartDriver (schSCManager, argv[1] ); OpenDevice (argv[1]); } CloseServiceHandle (schSCManager); } BOOL InstallDriver( IN SC_HANDLE SchSCManager, IN LPCTSTR DriverName, IN LPCTSTR ServiceExe ) /*++ Routine Description: Arguments: Return Value: --*/ { SC_HANDLE schService; DWORD err; // // NOTE: This creates an entry for a standalone driver. If this // is modified for use with a driver that requires a Tag, // Group, and/or Dependencies, it may be necessary to // query the registry for existing driver information // (in order to determine a unique Tag, etc.). // schService = CreateService (SchSCManager, // SCManager database DriverName, // name of service DriverName, // name to display SERVICE_ALL_ACCESS, // desired access SERVICE_KERNEL_DRIVER, // service type SERVICE_DEMAND_START, // start type SERVICE_ERROR_NORMAL, // error control type ServiceExe, // service's binary NULL, // no load ordering group NULL, // no tag identifier NULL, // no dependencies NULL, // LocalSystem account NULL // no password ); if (schService == NULL) { err = GetLastError(); if (err == ERROR_SERVICE_EXISTS) { // // A common cause of failure (easier to read than an error code) // printf ("failure: CreateService, ERROR_SERVICE_EXISTS\n"); } else { printf ("failure: CreateService (0x%02x)\n", err ); } return FALSE; } else { printf ("CreateService SUCCESS\n"); } CloseServiceHandle (schService); return TRUE; } BOOL RemoveDriver( IN SC_HANDLE SchSCManager, IN LPCTSTR DriverName ) /*++ Routine Description: Arguments: Return Value: --*/ { SC_HANDLE schService; BOOL ret; schService = OpenService (SchSCManager, DriverName, SERVICE_ALL_ACCESS ); if (schService == NULL) { printf ("failure: OpenService (0x%02x)\n", GetLastError()); return FALSE; } ret = DeleteService (schService); if (ret) { printf ("DeleteService SUCCESS\n"); } else { printf ("failure: DeleteService (0x%02x)\n", GetLastError() ); } CloseServiceHandle (schService); return ret; } BOOL StartDriver( IN SC_HANDLE SchSCManager, IN LPCTSTR DriverName ) { SC_HANDLE schService; BOOL ret; DWORD err; schService = OpenService (SchSCManager, DriverName, SERVICE_ALL_ACCESS ); if (schService == NULL) { printf ("failure: OpenService (0x%02x)\n", GetLastError()); return FALSE; } ret = StartService (schService, // service identifier 0, // number of arguments NULL // pointer to arguments ); if (ret) { printf ("StartService SUCCESS\n"); } else { err = GetLastError(); if (err == ERROR_SERVICE_ALREADY_RUNNING) { // // A common cause of failure (easier to read than an error code) // printf ("failure: StartService, ERROR_SERVICE_ALREADY_RUNNING\n"); } else { printf ("failure: StartService (0x%02x)\n", err ); } } CloseServiceHandle (schService); return ret; } BOOL StopDriver( IN SC_HANDLE SchSCManager, IN LPCTSTR DriverName ) { SC_HANDLE schService; BOOL ret; SERVICE_STATUS serviceStatus; schService = OpenService (SchSCManager, DriverName, SERVICE_ALL_ACCESS ); if (schService == NULL) { printf ("failure: OpenService (0x%02x)\n", GetLastError()); return FALSE; } ret = ControlService (schService, SERVICE_CONTROL_STOP, &serviceStatus ); if (ret) { printf ("ControlService SUCCESS\n"); } else { printf ("failure: ControlService (0x%02x)\n", GetLastError() ); } CloseServiceHandle (schService); return ret; } BOOL OpenDevice( IN LPCTSTR DriverName ) { char completeDeviceName[64] = ""; LPCTSTR dosDeviceName = DriverName; HANDLE hDevice; BOOL ret; // // Create a \\.\XXX device name that CreateFile can use // // NOTE: We're making an assumption here that the driver // has created a symbolic link using it's own name // (i.e. if the driver has the name "XXX" we assume // that it used IoCreateSymbolicLink to create a // symbolic link "\DosDevices\XXX". Usually, there // is this understanding between related apps/drivers. // // An application might also peruse the DEVICEMAP // section of the registry, or use the QueryDosDevice // API to enumerate the existing symbolic links in the // system. // strcat (completeDeviceName, "\\\\.\\" ); strcat (completeDeviceName, dosDeviceName ); hDevice = CreateFile (completeDeviceName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (hDevice == ((HANDLE)-1)) { printf ("Can't get a handle to %s\n", completeDeviceName ); ret = FALSE; } else { printf ("CreateFile SUCCESS\n"); CloseHandle (hDevice); ret = TRUE; } return ret; } Далее вот код самого драйвера: Код (Text): #include <ntddk.h> typedef struct _DEVICE_EXTENSION { PDEVICE_OBJECT pdo; UNICODE_STRING ustrSymLinkName; } DEVICE_EXTENSION, *PDEVICE_EXTENSION; VOID OnUnload(IN PDRIVER_OBJECT pDriverObject) { PDEVICE_OBJECT pNextDevObj; int i; DbgPrint("OnUnload"); pNextDevObj = pDriverObject->DeviceObject; for(i=0; pNextDevObj!=NULL; i++) { PDEVICE_EXTENSION dx = (PDEVICE_EXTENSION)pNextDevObj->DeviceExtension; UNICODE_STRING *pLinkName = &(dx->ustrSymLinkName); pNextDevObj = pNextDevObj->NextDevice; DbgPrint("OnUnload Deleting device (%d): pointer to PDO = %X.", i, dx->pdo); DbgPrint("OnUnload Deleting symlink = %ws.", pLinkName->Buffer); IoDeleteSymbolicLink(pLinkName); IoDeleteDevice(dx->pdo); } } NTSTATUS DriverEntry (IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath) { NTSTATUS status = STATUS_SUCCESS; PDEVICE_OBJECT pdo; UNICODE_STRING devName; UNICODE_STRING symLinkName; PDEVICE_EXTENSION dx; DbgPrint("Entering DriverEntry"); DbgPrint("RegistryPath = %ws.", pRegistryPath->Buffer); RtlInitUnicodeString(&devName, L"\\Device\\MyDevice"); RtlInitUnicodeString(&symLinkName, L"\\DosDevices\\MyDevice"); pDriverObject->DriverUnload = OnUnload; status = IoCreateDevice(pDriverObject, sizeof(DEVICE_EXTENSION), &devName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pdo); if(!NT_SUCCESS(status)) { DbgPrint("DriverEntry IoCreateDevice error!"); return status; } dx = (PDEVICE_EXTENSION)pdo->DeviceExtension; dx->pdo = pdo; dx->ustrSymLinkName = symLinkName; status = IoCreateSymbolicLink(&symLinkName, &devName); if(!NT_SUCCESS(status)) { IoDeleteDevice(pdo); return status; } DbgPrint("DriverEntry successfully completed."); return status; } Всё компилируется нормально, но когда я пытаюсь запустить драйвер: Код (Text): C:\CPP\objchk_wxp_x86\i386>starter MyDevice MyDevice.sys CreateService SUCCESS failure: StartService (0x02) Can't get a handle to \\.\MyDevice Пример набирал с книги, а исходник утилиты скачал с сети.. Подскажите, пожалуйста, где ошибка и почему не стартует сервис? зы и еще в DebugView вобще - пусто Хотя должны были сообщения DbgPrint показываться...
ОСь какая? Запусти под vmware с WinDbg и поставь __asm int 3 в DriverEntry(), если поймаеш значит драйвер грузится а DbgView не работает(Может просто не включен kernel capture, или прав не хватило).
DebugView -> Capture -> Capture Kernel стоит? У меня все выводится. Ай, не увидел что IceCrashLdr уже подсказал на счет Capture Kernel DebugView выводит Код (Text): Entering DriverEntry RegistryPath = \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\Driver. DriverEntry successfully completed.
оказывается дело не в драйвере самом, а в установщике. Скачал InstDrv с rootkit.com. Отлично запускается и устанавливается мой драйвер. DBGView тоже пишет JCronuz а вы компилировали мой пример установщика? или свой у вас? может быть нужно студию более новую? у меня: Windows XP SP3 VisualStudio 6 SP6
Да KmdLoader использовал для загрузки, тоже когда-то пробовал Instdrv.c использовать, потом решил создать свой, что и вам советую, за одно и разбиретесь с SCM. KmdLoader кстати с открытым кодом.
punxer Для открытия девайса нужен IRP_MJ_CREATE обработчик. А IRP_MJ_DEVICE_CONTROL для DeviceIoControl() нужен
Командная строка: C:\CPP\objchk_wxp_x86\i386>starter MyDevice MyDevice.sys Функции InstallDriver (schSCManager,argv[1],argv[2]) вы передаете в качестве argv[2] - MyDevice.sys, это будет параметр ServiceExe в функции CreateService, а ей нужно передать полный путь к файлу MyDevice.sys в этом параметре. Значит драйвер не загрузится. Что бы открыть хендл драйвера функцией OpenService ей нужно передать полное имя драйвера - с расширением, т.е. "MyDevice.sys" - а у вас функции StartDriver(schSCManager,argv[1]) передаётся аргумент argv[1] равный "MyDevice". А это значит что вы не откроете хендл драйвера который должен быть уже загружен. На первый взгляд кажется всё.
Great то есть для управления дровом через DeviceIoControl() нужно реализовать оба обработчега. Ведь для DeviceIoControl() нужен хэндл CreateFile()? так? Обработчик IOCTL я представляю, есть ли что то что обязательно делать в IRP_MJ_CREATE ?
Да, для CreateFile() нужно в обработчике IRP_MJ_CREATE и не только, просто вернуть Irp->IoStatus.Status = STATUS_SUCCESS; К стати я тоже сегодня сделал свой первый драйвер, у меня это так реализовано: Код из DriverEntry - Код (Text): for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) DriverObject->MajorFunction[i] = DriverDefaultHandler; //=========== DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverDeviceControl; DriverObject->DriverUnload = DriverUnload; pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; return STATUS_SUCCESS; А вот обработчик IRP_MJ_CREATE: Код (Text): NTSTATUS DriverDefaultHandler(IN PDEVICE_OBJECT pDeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION pSL = IoGetCurrentIrpStackLocation (Irp) ; switch (pSL->MajorFunction) { case IRP_MJ_CREATE : case IRP_MJ_CLOSE : case IRP_MJ_CLEANUP : { Irp->IoStatus.Status = STATUS_SUCCESS; break; } default: { Irp->IoStatus.Status = STATUS_NOT_SUPPORTED ; } } Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Irp->IoStatus.Status; }
Код (Text): #define _X86_ #include <ntddk.h> typedef struct _DEVICE_EXTENSION { PDEVICE_OBJECT pdo; UNICODE_STRING ustrSymLinkName; } DEVICE_EXTENSION, *PDEVICE_EXTENSION; NTSTATUS MJ_DispatchIoctl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PIO_STACK_LOCATION irpStack; NTSTATUS status= STATUS_SUCCESS; irpStack = IoGetCurrentIrpStackLocation (Irp); switch (irpStack->Parameters.DeviceIoControl.IoControlCode) { case 1: DbgPrint("IOCTL CODE PASSED"); break; default: break; }; Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; } NTSTATUS MJ_Create ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS status = STATUS_SUCCESS; PIO_STACK_LOCATION irpStack; irpStack = IoGetCurrentIrpStackLocation (Irp); Irp->IoStatus.Information = 0; // fill in the correct length Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; } NTSTATUS DriverDefaultHandler(IN PDEVICE_OBJECT pDeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION pSL = IoGetCurrentIrpStackLocation (Irp) ; switch (pSL->MajorFunction) { case IRP_MJ_CREATE : case IRP_MJ_CLOSE : case IRP_MJ_CLEANUP : { Irp->IoStatus.Status = STATUS_SUCCESS; break; } default: Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST ; } Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Irp->IoStatus.Status; } VOID OnUnload(IN PDRIVER_OBJECT pDriverObject) { PDEVICE_OBJECT pNextDevObj; int i; DbgPrint("OnUnload"); pNextDevObj = pDriverObject->DeviceObject; for(i=0; pNextDevObj!=NULL; i++) { PDEVICE_EXTENSION dx = (PDEVICE_EXTENSION)pNextDevObj->DeviceExtension; UNICODE_STRING *pLinkName = &(dx->ustrSymLinkName); pNextDevObj = pNextDevObj->NextDevice; IoDeleteSymbolicLink(pLinkName); IoDeleteDevice(dx->pdo); } } NTSTATUS DriverEntry (IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath) { NTSTATUS status = STATUS_SUCCESS; PDEVICE_OBJECT pdo; UNICODE_STRING devName; UNICODE_STRING symLinkName; PDEVICE_EXTENSION dx; int i; RtlInitUnicodeString(&devName, L"\\Device\\MyDevice"); RtlInitUnicodeString(&symLinkName, L"\\DosDevices\\MyDevice"); pDriverObject->DriverUnload = OnUnload; for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) pDriverObject->MajorFunction[i] = DriverDefaultHandler; pDriverObject->Flags &= ~DO_DEVICE_INITIALIZING; pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=MJ_DispatchIoctl; status = IoCreateDevice(pDriverObject, sizeof(DEVICE_EXTENSION), &devName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pdo); if(!NT_SUCCESS(status)) { DbgPrint("DriverEntry IoCreateDevice error!"); return status; } dx = (PDEVICE_EXTENSION)pdo->DeviceExtension; dx->pdo = pdo; dx->ustrSymLinkName = symLinkName; status = IoCreateSymbolicLink(&symLinkName, &devName); if(!NT_SUCCESS(status)) { IoDeleteDevice(pdo); return status; } DbgPrint("DriverEntry successfully completed."); return status; } Вот и я накатал) нашел пример тостера Вопрос: почему KmdManger не может послать IOCTL_CODE? Наверное потому что не знает имя девайса созданного драйвером, но тогда зачем это реализовано в нем. Решение: писатьсвой загрузчик свой можно взять исходник но открывать именно мой девайс и уже после CreateFile вызывать DeviceIoControl? может для KmdManger имя файла драйвера должно быть идентично имени устройства? Да, именно так и есть.
punxer И что, работает ? irpStack->Parameters.DeviceIoControl.IoControlCode врядли будет равным 1. Его можно сформировать в программе вызывающей DeviceIoControl() с помощью макроса: Код (Text): #define CTL_CODE( DeviceType, Function, Method, Access ) ( \ ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) А в дрйвере можно извлечь поле Function и вызвать соотвествующий обработчик. Флаг pDriverObject->Flags &= ~DO_DEVICE_INITIALIZING; сбрасывается только после полной инициализации объекта устройства см. http://www.microsoft.com/whdc/driver/tips/devinit.mspx , а в драйвере WDM в функции AddDevice. А зачем нужна функция MJ_Create которая нигде не используется ?
Charlief работает я просто ради примера передаю 1 через KmdMan, про макрос знаю/ забыл убрать думал сделать ввод/вывод через Write/ReadFile, но потом понял что обойдусь IOCTL да и макрос мне незачем, мне нужно просто эмулировать клаву через порты некоторые кнопки их немного так что нужны просто разные коды для разных клавиш передавать понял спасибо