Our learning program is from "Hello World". The driver is no exception. Today I wrote a driver version "Hello World" to warm up, I hope that everyone can understand the basic framework of the driver. . The driver is divided into 2 categories, one is the Kernel mode driver, the other is Windows mode driver, the nature of the two modes is different, but the details are different. This article describes the installation and use of the kernel mode driver and drivers. The driver is the same as normal EXE, DLL, and there is an inlet function. However, in EXE, the entrance function is Main () / WinMain () and Unicode () / wwinmain (), and the port function of the DLL can be available, it is dllmain (). The driver also has an entry function, and it is necessary, it is driverenTry (), again prompt, because I / O Manager will first call the driver's DriveREntry (), its role like dllmain () - - Complete some initialization work. Driverentry () has 2 parameters: 1PDriver_Object DriverObject, pointing to the pointer of the driver object, we operate the driver, rely on it, it is passed by the I / O Manager; 2) Punicode_String RegistryPath, the service primary key of the driver This parameter is not used, but it is important to note that after driverenTry () returns, it may disappear, so if you need to use it, remember to save first. Driverentry () returns a NTSTATUS value, which is a Ulong value, a specific definition, see Ntstatus.h header file in DDK, in detail. Since you want to write the "Hello World" of the drive version, you need to determine how to communicate with the driver, usually shared memory, sharing event, ioctl macro, or use readfile () or writefile (), in this article With a simple, but very commonly used IOCTL macro, its dependent IRP dispatch routine is IRP_MJ_DEVICE_CONTROL, WIN32 program uses DeviceIoControl () to communicate with the driver, output different debug information depending on the different IOCTL macros, outputs different debugging information. For the sake of easy, I didn't use readfile () to read the information, but directly using dbgprint (), so you need to use DBGVIEW to view, other debugging tools. PS: Lazy! The driver communicates with the I / O manager, use IRP, ie I / O request packages. IRP is divided into two parts: 1) IRP header; 2) IRP stack.
The IRP header information is as follows: IORP header: IO_STATUS_BLOCK IOSTATUS contains the status of I / O request PVOID AssociatedIrp.systemBuffer If the buffer I / O is performed, this pointer points to the system buffer PMDL MDLADDRESS if directly I / O, this pointer points to the user buffer user memory space address descriptor table PVOID UserBuffer I / O buffers IRP stack: UCHAR MajorFunction indicated above UCHAR MinorFunction IRP_MJ_XXX dispatch routine, the general file system drivers and SCSI parameters that joint type union parameters MajorFunction of the {struct Read IRP_MJ_READ ULONG Length ULONG Key LARGE_INTEGER ByteOffset struct Write IRP_MJ_WRITE parameters ULONG Length ULONG Key LARGE_INTEGER ByteOffset struct DeviceIoControl IRP_MJ_DEVICE_CONTROL parameters ULONG OutputBufferLength ULONG InputBufferLength ULONG IoControlCode PVOID Type3InputBuffer} pointer to the target file object pointer to the target device object PDEVICE_OBJECT DeviceObject request PFILE_OBJECT FileObject request, if There are anything to operate IRP.
For different IRP functions, the operation is also different: some operation only IRP header; some only operate IRP stack; there are also integral operations of IRP, below is some common functions: IRP overall: Name Description Call IRP to Start I / O routine Dispatch IoCompleteRequest represents all the processing is completed DpcForIsr IoStartNextPacket IRP to a next send the Start I / O routines DpcForIsr IoCallDriver transmission request IRP Dispatch IoAllocateIrp request additional IRP Dispatch IoFreeIrp driver releases the allocated IRP I / O completion IRP stack : name description caller IoGetCurrentIrpStackLocation give the caller stack pointer Dispatch IoMarkIrpPending for further processing flag caller I / O stack Dispatch IoGetNextIrpStackLocation get the next driver in the I / O stack pointer Dispatch IoSetNextIrpStackLocation the I / O stack pointer onto the stack DISPATC plays a very important role in drivers, IRP dispatched routines, each IRP dispatch routine, almost all corresponding Win32 functions, below is a few commonly used: IRP dispatch routines: Name Description The caller requests a handle CreateFile IRP_MJ_CLEANUP IRP_MJ_CREATE suspended canceled when the handle is closed off IRP CloseHandle IRP_MJ_CLOSE handle CloseHandle IRP_MJ_READ ReadFile IRP_MJ_WRITE data obtained from the data transfer apparatus to control the operation of the device WriteFile IRP_MJ_DEVICE_CONTROL (using macro IOCTL)
DeviceIoControl IRP_MJ_INTERNAL_DEVICE_CONTROL control operation (only the kernel calls) N / A IRP_MJ_QUERY_INFORMATION GetFileSize IRP_MJ_SET_INFORMATION provided to give longitudinal length of the file write SetFileSize IRP_MJ_FLUSH_BUFFERS output buffer or discard the input buffer FlushFileBuffers FlushConsoleInputBuffer PurgeComm IRP_MJ_SHUTDOWN system shutdown InitiateSystemShutdown ======= ============================================================================================================================================================================================================= =================================================== 下 开始 开始 我们 写 写"Hello World", the program is simple, first introduce the process: 1. Call IOCREATEDEVICE () Create a device and return a device object. 2. Call IOCREATESYNBOLICLINK () Create a symbolic connection so that the Win32 program can use the driver 3, set the IRP_MJ_DEvice_Control dispatch routine helloworlddispatch () and uninstall routine helloWorldunload ().
If the Win32 program uses DeviceIocontrol (), execute the HelloWorldDisPatch () function 4, call igetcurrentirPstackLocation () to get the current caller's IRP pointer 5, get the IO control code, use IOCOMPLETEREQUEST () to complete IRP operation If you use controlService () The program is executed, then the HelloWorldunLoad () function is executed, call IodeeteSymbolicLink () Delete Symbol connection 5, call odeltedevice () Delete established device driver DriveREntry () // Create device IOCREATEDEVICE (driverObject, // driver object 0, // The size of the extension device, because it is not required, set 0 & DeviceNameString, // device name file_device_unknown, // device type 0, // indicate the operation of the device allowable false, // If true, indicates that only one thread can use the device. For False, there is no restrictions & lpDeviceObject); // Returned device object // Create symbol connection IOCREATESYMBOLICLINK (Unicode_String & DeviceNameString); // Device Name // Display routine and uninstall routine DriverObject- > MajorFunction [IRP_MJ_DEVICE_CONTROL] = HelloWorldDispatch; it DriverObject-> DriverUnload = HelloWorldUnLoad; IRP dispatch routine HelloWorldDispatch () IrpStack = IoGetCurrentIrpStackLocation (pIrp); // get the current caller IRP stack // get the IO control code, and perform the specified operation , Here is just dbgprint () i oControlCodes = IrpStack-> Parameters.DeviceIoControl.IoControlCode; switch (IoControlCodes) {...... IoCompleteRequest (pIrp, IO_NO_INCREMENT); // unloading operation IRP completion routine HelloWorldUnLoad () // delete symbolic links and devices IoDeleteSymbolicLink (& DeviceLinkString ); Odeletedevice (driverObject-> deviceObject); ======================================== ===========================
==================================================================================================================================001 h "// drive inlet NTSTATUS DriverEntry (iN PDRIVER_OBJECT DriverObject, iN PUNICODE_STRING RegistryPath) {NTSTATUS ntStatus = STATUS_SUCCESS; PDEVICE_OBJECT lpDeviceObject = NULL; // pointer pointing device object UNICODE_STRING DeviceNameString; // device name UNICODE_STRING DeviceLinkString; // symbolic link / / debug information #ifdef DEBUGMSG DbgPrint ( "Starting DriverEntry () / n"); #endif RtlInitUnicodeString (& DeviceNameString, NT_DEVICE_NAME); // // create a device initialization Unicode string ntStatus = IoCreateDevice (DriverObject, 0, & DeviceNameString, FILE_DEVICE_UNKNOWN, 0 , FALSE, & lpDeviceObject); // use NT_SUCCESS detect macro function call is successful if) {#ifdef DEBUGMSG DbgPrint ( "Error IoCreateDevice () / n"); #endif goto Error;} (NT_SUCCESS (ntStatus!) RtlInitUnicodeString (& DeviceLinkString, DOS_DEVICE_NAME); // Creating a symbol connection ntstatus = ocreateSymbolicl ink (& DeviceLinkString, & DeviceNameString); (! NT_SUCCESS (ntStatus)) if {#ifdef DEBUGMSG DbgPrint ( "Error IoCreateSymbolicLink () / n"); #endif goto Error;} // set IRP dispatch routine and unload routine DriverObject- > MajorFunction [IRP_MJ_CREATE] = // HelloWorldDispatch; DriverObject-> MajorFunction [IRP_MJ_CLOSE] = // HelloWorldDispatch; DriverObject-> MajorFunction [IRP_MJ_DEVICE_CONTROL] = HelloWorldDispatch; DriverObject-> DriverUnload = HelloWorldUnLoad; return ntStatus;
Error: #ifdef DEBUGMSG DbgPrint ( "Error DriverEntry () / n"); #endif return ntStatus;} NTSTATUS HelloWorldDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp) {NTSTATUS ntStatus = STATUS_SUCCESS; ULONG IoControlCodes = 0; // I / O control Code PIO_STACK_LOCATION IrpStack = NULL; // IRP IRP stack // set state pIrp-> IoStatus.Status = STATUS_SUCCESS; pIrp-> IoStatus.Information = 0; #ifdef DEBUGMSG DbgPrint ( "Starting HelloWorldDispatch () / n"); # endif IrpStack = IoGetCurrentIrpStackLocation (pIrp); // get the current caller IRP switch (IrpStack-> MajorFunction) {case IRP_MJ_CREATE: #ifdef DEBUGMSG DbgPrint ( "IRP_MJ_CREATE / n"); #endif break; case IRP_MJ_CLOSE: #ifdef DEBUGMSG DbgPrint ("IRP_MJ_CLOSE / N"); #ENDIF BREAK; CASE IRP_MJ_DEVICE_CONTROL: #IFD ef DEBUGMSG DbgPrint ( "IRP_MJ_DEVICE_CONTROL / n"); #endif // obtain I / O control code IoControlCodes = IrpStack-> Parameters.DeviceIoControl.IoControlCode; switch (IoControlCodes) {// Start case START_HELLPWORLD: DbgPrint ( "Starting /" Hello World / "/ n"); break; // Stop Case Stop_hellpworld: dbgprint ("stoping /" hello world / "/ n"); Break;
default: pIrp-> IoStatus.Status = STATUS_INVALID_PARAMETER; break;} break; default: break;} ntStatus = pIrp-> IoStatus.Status; IoCompleteRequest (pIrp, IO_NO_INCREMENT); return ntStatus;} VOID HelloWorldUnLoad (IN PDRIVER_OBJECT DriverObject) {UNICODE_STRING DeviceLinkString; PDEVICE_OBJECT DeviceObjectTemp1 = NULL; PDEVICE_OBJECT DeviceObjectTemp2 = NULL; #ifdef DEBUGMSG DbgPrint ( "Starting HelloWorldUnLoad () / n"); #endif RtlInitUnicodeString (& DeviceLinkString, DOS_DEVICE_NAME); IoDeleteSymbolicLink (& DeviceLinkString); // delete symbolic links if (DriverObject) {DeviceObjectTemp1 = DriverObject-> DeviceObject; // remove the device while (DeviceObjectTemp1) {DeviceObjectTemp2 = DeviceObjectTemp1; DeviceObjectTemp1 = DeviceObjectTemp1-> NextDevice; IoDeleteDevice (DeviceObjectTemp2); }}} #ENDIF ============================================= ============================================================================================================================================================================================================= ===== Driver compilation requires the build utility in the DDK, which is a command line program, which is not very convenient to use. The VC Knowledge Base has an article compiled in VC 6.0, interested in see.
1. Makefile compile the driver, first, you should prepare a makefile, this file is simple, only one code: ## do not edit this file !!! Edit ./sources. If you want to add a new source # file to this component This File Melely Indirects To The Real Make File # That Shared by All the Driver Components of the Windows NT DDK #! INCLUDE $ (NTMAKEENV) /makefile.def is just as described, do not modify this file --- it is universal of! 2, the second file prepared by Sources is Sources, which describes some detail of compilation. For this program, the content of the Sources file is like this: targetname = helloworld // Drive Name TargetPath =. // After compiling SYS path TargetType = driver // Type of driver Sources = helloworld.c // only one source file With these 2 files, you can compile it using Build. Enter "Start" menu / program / development kits / windows 2000 DDK, 3 CMD programs: 1) CHECKED 64 Bit Build Environment, "Debug" 64-bit version; 2) 32-bit version of Checked Build Environment "debug" ; 3) 32-bit versions of Free Build Environment, "Release". Needless to say, it is definitely using Free Build Environment. . New or updated MSVC detected Updating DDK environment .... Setting environment for using Microsoft Visual C tools.Starting dirs creation ... Completed.C: / NTDDK> cd / C: /> cd HelloWorldC: / HelloWorld> buildBUILD: Object root set to: ==> objfreBUILD: / i switch ignoredBUILD: Compile and Link for i386BUILD: Loading c: /NTDDK/build.dat ... BUILD: Computing Include file dependencies: BUILD: Examining c: / helloworld directory for files to compile c: / helloworld - 1 source files (127 lines) BUILD:. Saving c: /NTDDK/build.dat ... BUILD: Compiling c: / helloworld directoryCompiling - helloworld.c for i386BUILD: Linking c: / helloworld directoryLinking Executable - i386 / helloworld.sys for i386build: Done 1 File Compiled 1 Executable Builtc: / HelloWorld> Now C: / HelloWorld / i386 directory, HelloWorld.sys.
============================================================================================================================================================================================================= ============================================================================================================================================================================================================= The installation of the driver is the same as the installation service, the only difference is that the type is the kernel driver, and the other is nothing difference with the operation service.
Install the driver process: 1. Call OpenScManager () Open Service Control Manager 2. Call CREATSERVICE () Create a service, the service type is kernel driver 3, call openservice () get the service handle Start Service 4, call startService () boot service Stop Service 4. Call the ControlService () Stop Service Delete Service 4, call deleteService () Delete Service 5, call closESERVICEHANDLE () Close Service handle Operation driver process: 1. Call createfile () get the device handle 2, call DeviceIocontrol () transfer I / O Control Code 3, Call CloseHandle () Close Device Handle There is a complete driver installer, so I will not write, only give the code full code for the operation driver: #define debugmsghttp://www.xfocus .net / tools / 200411 / 882.html #include
Erron); #ndif retturn false;} // Start IF (Strcmpi (MAIK, MY_DEVICE_START == 0) {// Passage I / O Control Code IF (! (Deviceiocontrol (HDevice, Start_hellpworld, Null, 0, NULL, 0, & RETBYTES, NULL)) {#ifDef debugmsg printf ("Deviceiocontrol () getLastError Reports% D / N", Erron); #ENDIF CloseHandle (HDEvice); Return False;}} // Stop IF (Strcmpi MAIK, MY_DEVICE_STOP) == 0) {// Transfer I / O Control Code IF (! (Deviceiocontrol (HDevice, Stop_hellpworld, Null, 0, Null, 0, & Retbytes, NULL)) {#ifdef debugmsg printf (" Deviceiocontrol () getLastError REPORTS% D / N ", Erron); #ndif closeHandle (HDEvice); Return False;}}}} (hdevice) closehandle (HDEVICE); // Close handle return true;} void usage (tchamerter) {FPRINTF (stderr, "=============================================== ============ ==================== / n "" drive version of Hello World / n "" Author: dahubaobao [EST] / n "" Home: www.eviloctal.com or Www.ringz.org/n "" mail: dahubaobao@eviloctal.com/n "" OICQ: 382690 / n / n ""% s -start / t start / N ""% s -stop / t stop / N / N ""