File Operations on windows Kernel drivers (reprinted 2)

Source: Internet
Author: User

Create a file in the kernel driver and read and write the file. Used to save information about the driver running.

Method:
You can perform this operation in two ways.
1. Create a file in the application, and the driver uses IOCTL to send the information to the application layer. The application reads and writes the file. Tdi_fw records the driver filter information in this way. The Tdi_fw application creates a thread, cyclically reads the driver information using IOCTL, and saves it to the file.
2. Complete all these operations in the driver. Here we mainly discuss this method.

Implementation:
Use ZwCreateFile to create disk files and use ZwReadFile and ZwWriteFile to read and write files.
The code for creating a file is as follows:
RtlInitUnicodeString (& usname, L "// SystemRoot // System32 // LogFiles // passthru. log ");
InitializeObjectAttributes (& oa, & usname, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL );
Status = ZwCreateFile (& hfile, GENERIC_WRITE, & oa, & iostatus, NULL,
FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OVERWRITE_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );

The code for writing files is as follows:
ZwWriteFile (hfile, NULL, & iostatus, PrintContent, count, NULL, NULL );

This code is not difficult. You can find some examples on the Internet.
Note:
1. Remember to close ZwClose (hFile) at the end ).
2. When the system is just started, it is best to create the file in C: or under the system file. Otherwise, the file fails to be created.
The real problem is that all these Zw functions can only run on PASSIVE_LEVEL. BSOD occurs when you call these functions on DISPATCH_LEVEL. The problem arises. We also need to save some running information in the PtReceive function, and the PtReceive is at the DISPATCH_LEVEL level. This problem needs to be solved.

There are two methods:
1. Using WorkItem in the work queue, the callback function that WorkItem can queue for registration. When the routine is at the DISPATCH_LEVEL level, the callback function is inserted into the queue. when the process is reduced to PASSIVE_LEVEL, the callback functions in these queues will be called by the system.
2. Use PsCreateSystemThread to register a thread, register an event, and apply for a memory segment.
When we have information written to a file, we first write the information into the memory, and then Set this event. Loop the KeWaitForSingleObject Event in this thread. Then, call ZwWriteFile to write information to the file. Note the synchronization of file read/write. I implemented this solution.

1. You can use RtlStringCbPrintfA to replace the sprintf function and initialize the memory string. Example:

# Include "ntstrsafe. h"

CHAR pszDest [30];
ULONG cbDest = 30;
LPCSTR pszFormat = "% s % d + % d = % d .";
CHAR * pszTxt = "The answer is ";

RtlStringCbPrintfA (pszDest, cbDest, pszFormat, pszTxt, 1, 2, 3 );
KdPrint ("% s", pszDest ));
It should be noted that this function also has another version RtlStringCbPrintfW, which is specially used to superexecute UNICODE. Other functions that may be useful to us are RtlStringCbCopyA and RtlStringCbCatA for copying and connecting. The operations are simple. They are the alternative sprintf version under the driver.

2. One problem found is that after the driver is installed and restarted, The ZwCreateFile function called in DriverEntry will return a failure. This problem does not occur when Passthru is installed after the system is started. The reason is that when the operating system is started, the system initializes Passthru and calls our DriverEntry function. At this time, the disk is not fully initialized and cannot be accessed.
This problem has no effect on us. When we need to record information, it must be something after the application client is enabled. At this time, the disk has already been started, so we don't have to worry about it.
The solution here is that ZwCreateFile is used only when the driver is enabled when the application is started. This is certainly acceptable.

3. It is not difficult to use WorkItem to queue system callback functions. In NDIS, NdisInitializeWorkItem and NdisScheduleWorkItem functions can be used to queue unexecutable actions under high irql. When the process drops to passive_level, these queued callback functions will Dequeue.
I have tried this method today and can use it. However, in terms of efficiency, there is nothing outstanding. According to the CSDN introduction, there are two areas to note in the work queue. First, the operation cannot be performed too long and will lead to deadlocks. 2. Before queuing work items, it is best to release all mutex, lock, and semaphore; otherwise, it is easy to deadlock. Both operations are good anyway (for the method of the other thread, see the previous document ). Just select one and use it.
Regmon (2)

If (nt_success (ntstatus ))
{
Create a symbolic connection so that the GUI can access this driver/device by name
Create a distribution point for each method to be processed
Driverobject-> majorfunction [irp_mj_shutdown] =
Driverobject-> majorfunction [irp_mj_create] =
Driverobject-> majorfunction [irp_mj_close] =
Driverobject-> majorfunction [irp_mj_device_control] = regmondispatch;
# If dbg
Driverobject-> driverunload = regmonunload;
# End if
}

If (! Nt_success (ntstatus ))
{
Dbuplint ("regmon: failed to create our device! /N "));
When an error occurs, clean up the environment (resources, etc)
If (guidevice) iodeletedevice (guidevice );
Iodeletesymboliclink (& devicelinkunicodestring );
Return ntstatus;
}

Initialize mutex
Mutex_init (storemutex );
Mutex_init (hashmutex );
Mutex_init (filtermutex );

Initialize the Root Key Length
For (I = 0; I <numrootkeys; I ++)
{
Rootkey [I]. rootnamelen = strlen (rootkey [I]. rootname;
}
For (I = 0; I <2; I ++)
{
Currentuser [I]. rootnamelen = strlen (currentuser [I]. rootname;
}

System Table Data Structure pointer, an ntoskrnl Export
Servicetable = keservicedescriptortable; user-defined structure
Dbuplint ("hookregistry: servicetable: % x/N", servicetable ));
Get the offset of the process name
Processnameoffset = getprocessnameoffset (); this function is written by the ox.

Allocate initialization output buffer
Store = exallocatepool (pagepool, sizeof (* store ));
If (! Store)
{
Iodeletedevice (guidevice );
Iodeletesymboliclink (& devicelinkunicodestring );
Return STATUS_INSUFFICENT_RESOURCES;
}
Store-> Len = 0;
Store-> Next = NULL;
NumStore = 1;

Start logging if we are a Startup Device.
If (startType! = SERVICE_DEMAND_START)
{
Initialization log
BoolLogging = TRUE;

KeInitializeEvent (& LoggingEvent, SynchronizationEvent, FALSE );
GUIActive = TRUE;
Fileltet = BootFilter;
RegmonUpdateFilters ();
HookRegisters ();

Indicates that the log mode is enabled.
RtlInitUnicodeString (& bootMessageUnicodeString, bootMessage );
ZwDisplayString (& bootMessageUnicodeString );

Registration close notification
IoRegisterShutdonwNotification registers a system shutdown notification function provided by the driver and calls it before the system is completely shut down.
IoRegisterShutdown Notification (GUIDevice );

}
Return STATUS_SUCCESS;
}

 

 

 

RegmonDispatch
This function processes device requests. The request to be processed comes from the GUI. Of course, when the GUI is established and the driver-based communication is disabled, you also need to process Create and Close.
NTSTAUTS RegmonDispatch (IN PDEVICE_OBJECT DeviceObject, in pirp Irp)
{
PIO_STACK_LOCATION irpStack; current stack
PVOID inputBuffer;
PVOID outputBuffer;
ULONG inputBufferLength;
ULONG outputBufferLength;
ULONG ioControlCode;
PSTORE_BUF old;
WORK_QUEUE_ITEM workItem;

Set processing successful
Irp-> IoStatus. Status = STATUS_SUCCESS;
Irp-> IoStatus. Information = 0;

Gets the pointer to the current position in the Irp. This is where the code and parameters are located.
IrpStack = IoGetCurrentIrpStackLocation (Irp );

InputBuffer = Irp-> AssociatedIrp. SystemBuffer;
InputBufferLength = iprStack-> Parameters. DeviceIoControl. InputBufferLength;
OutputBuffer = Irp-> AssociatedIrp. SystemBuffer;
OutputBufferLength = irpStack-> Parameters. DeviceIoControl. OutputBufferLength;
IoControlCode = irpStack-> Parameters. DeviceIoControl. IoControlCode;

Switch (irpStack-> MajorFunction)
{
Case IRP_MJ_CREATE:
Dbuplint ("Regmon: IRP_MJ_CREATE/n "));
Disable startup logs
If (BootLogging)
{
BootLogging = FALSE;
IoUnregisterShutdownNotification (DeviceObject );
Mutex_wait (storemutex );
Exinitializeworkitem (& workitem, regmonclosebootlog, 0 );
This function has expired. You should use ioallocateworkitem. Returns a pointer to the private structure io_workitem. The driver should not access this structure in any form!
Exqueueworkitem (& workitem, criticalworkqueue );
This function has expired. You should use ioqueueworkitem. Insert a specified work item to the queue. The queue is accessed by the system worker thread. The system worker thread removes a work item from the queue and calls the callback function.
Kewaitforsingleobject (& loggingevent, executive, kernelmode, false, null );
Mutex_release (storemutex );
}
Sequence = 0;
Guiactive = true;
Dbuplint ("Gui active: % d/N", guiactive ));
Break;
}
}

Still Small
Project-> Settings open the link property page and delete all Lib in the object/library modules: edit the following box, and add msvcrt. Lib kernel32.lib user32.lib.
On the link property page of project-> Settings, add/align: 4096 to the edit box under project options.

These are simple methods.

From:

Http://blog.csdn.net/floweronwarmbed/archive/2009/06/01/4233452.aspx

Share:

Create a file in the kernel driver and read and write the file. Used to save information about the driver running.

Method:
You can perform this operation in two ways.
1. Create a file in the application, and the driver uses IOCTL to send the information to the application layer. The application reads and writes the file. Tdi_fw records the driver filter information in this way. The tdi_fw application creates a thread, cyclically reads the driver information using ioctl, and saves it to the file.
2. Complete all these operations in the driver. Here we mainly discuss this method.

Implementation:
Use ZwCreateFile to create disk files and use ZwReadFile and ZwWriteFile to read and write files.
The code for creating a file is as follows:
RtlInitUnicodeString (& usname, L "// SystemRoot // System32 // LogFiles // passthru. log ");
InitializeObjectAttributes (& oa, & usname, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL );
Status = ZwCreateFile (& hfile, GENERIC_WRITE, & oa, & iostatus, NULL,
FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OVERWRITE_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );

The code for writing files is as follows:
ZwWriteFile (hfile, NULL, & iostatus, PrintContent, count, NULL, NULL );

This code is not difficult. You can find some examples on the Internet.
Note:
1. Remember to close ZwClose (hFile) at the end ).
2. When the system is just started, it is best to create the file in C: or under the system file. Otherwise, the file fails to be created.
The real problem is that all these Zw functions can only run on PASSIVE_LEVEL. BSOD occurs when you call these functions on DISPATCH_LEVEL. The problem arises. We also need to save some running information in the PtReceive function, and the PtReceive is at the DISPATCH_LEVEL level. This problem needs to be solved.

There are two methods:
1. Using WorkItem in the work queue, the callback function that WorkItem can queue for registration. When the routine is at the DISPATCH_LEVEL level, the callback function is inserted into the queue. when the process is reduced to PASSIVE_LEVEL, the callback functions in these queues will be called by the system.
2. Use PsCreateSystemThread to register a thread, register an event, and apply for a memory segment.
When we have information written to a file, we first write the information into the memory, and then Set this event. Loop the KeWaitForSingleObject Event in this thread. Then, call ZwWriteFile to write information to the file. Note the synchronization of file read/write. I implemented this solution.

1. You can use RtlStringCbPrintfA to replace the sprintf function and initialize the memory string. Example:

# Include "ntstrsafe. h"

CHAR pszDest [30];
ULONG cbDest = 30;
LPCSTR pszFormat = "% s % d + % d = % d .";
CHAR * pszTxt = "The answer is ";

RtlStringCbPrintfA (pszDest, cbDest, pszFormat, pszTxt, 1, 2, 3 );
KdPrint ("% s", pszDest ));
It should be noted that this function also has another version RtlStringCbPrintfW, which is specially used to superexecute UNICODE. Other functions that may be useful to us are RtlStringCbCopyA and RtlStringCbCatA for copying and connecting. The operations are simple. They are the alternative sprintf version under the driver.

2. One problem found is that after the driver is installed and restarted, The zwcreatefile function called in DriverEntry will return a failure. This problem does not occur when passthru is installed after the system is started. The reason is that when the operating system is started, the system initializes passthru and calls our DriverEntry function. At this time, the disk is not fully initialized and cannot be accessed.
This problem has no effect on us. When we need to record information, it must be something after the application client is enabled. At this time, the disk has already been started, so we don't have to worry about it.
The solution here is that zwcreatefile is used only when the driver is enabled when the application is started. This is certainly acceptable.

3. It is not difficult to use workitem to queue system callback functions. In NDIS, ndisinitializeworkitem and ndisscheduleworkitem functions can be used to queue unexecutable actions under high IRQL. When the process drops to passive_level, these queued callback functions will dequeue.
I have tried this method today and can use it. However, in terms of efficiency, there is nothing outstanding. According to the csdn introduction, there are two areas to note in the work queue. First, the operation cannot be performed too long and will lead to deadlocks. 2. Before queuing work items, it is best to release all mutex, lock, and semaphore; otherwise, it is easy to deadlock. Both operations are good anyway (for the method of the other thread, see the previous document ). Just select one and use it.
Regmon (2)

If (nt_success (ntstatus ))
{
Create a symbolic connection so that the GUI can access this driver/device by name
Create a distribution point for each method to be processed
Driverobject-> majorfunction [irp_mj_shutdown] =
Driverobject-> majorfunction [irp_mj_create] =
DriverObject-> MajorFunction [IRP_MJ_CLOSE] =
DriverObject-> MajorFunction [IRP_MJ_DEVICE_CONTROL] = RegmonDispatch;
# If DBG
DriverObject-> DriverUnload = RegmonUnload;
# End if
}

If (! NT_SUCCESS (ntStatus ))
{
Dbuplint ("Regmon: Failed to create our device! /N "));
When an error occurs, clean up the environment (resources, etc)
If (GUIDevice) IoDeleteDevice (GUIDevice );
IoDeleteSymbolicLink (& deviceLinkUnicodeString );
Return ntStatus;
}

Initialize mutex
MUTEX_INIT (StoreMutex );
MUTEX_INIT (HashMutex );
MUTEX_INIT (FilterMutex );

Initialize the Root Key Length
For (I = 0; I <NUMROOTKEYS; I ++)
{
RootKey [I]. RootNameLen = strlen (RootKey [I]. RootName;
}
For (I = 0; I <2; I ++)
{
CurrentUser [I]. RootNameLen = strlen (CurrentUser [I]. RootName;
}

System Table Data Structure pointer, an NTOSKRNL Export
ServiceTable = KeServiceDescriptorTable; user-defined structure
Dbuplint ("HookRegistry: Servicetable: % x/n", ServiceTable ));
Get the offset of the process name
ProcessNameOffset = GetProcessNameOffset (); this function is written by the ox.

Allocate initialization output buffer
Store = ExAllocatePool (PagePool, sizeof (* Store ));
If (! Store)
{
IoDeleteDevice (GUIDevice );
IoDeleteSymbolicLink (& deviceLinkUnicodeString );
Return STATUS_INSUFFICENT_RESOURCES;
}
Store-> Len = 0;
Store-> Next = NULL;
NumStore = 1;

Start logging if we are a Startup Device.
If (startType! = SERVICE_DEMAND_START)
{
Initialization log
BoolLogging = TRUE;

KeInitializeEvent (& LoggingEvent, SynchronizationEvent, FALSE );
GUIActive = TRUE;
Fileltet = BootFilter;
RegmonUpdateFilters ();
HookRegisters ();

Indicates that the log mode is enabled.
RtlInitUnicodeString (& bootMessageUnicodeString, bootMessage );
ZwDisplayString (& bootMessageUnicodeString );

Registration close notification
IoRegisterShutdonwNotification registers a system shutdown notification function provided by the driver and calls it before the system is completely shut down.
IoRegisterShutdown Notification (GUIDevice );

}
Return STATUS_SUCCESS;
}

 

 

 

RegmonDispatch
This function processes device requests. The request to be processed comes from the GUI. Of course, when the GUI is established and the driver-based communication is disabled, you also need to process Create and Close.
NTSTAUTS RegmonDispatch (IN PDEVICE_OBJECT DeviceObject, in pirp Irp)
{
Pio_stack_location irpstack; current stack
Pvoid inputbuffer;
Pvoid outputbuffer;
Ulong inputbufferlength;
Ulong outputbufferlength;
Ulong iocontrolcode;
Pstore_buf old;
Work_queue_item workitem;

Set processing successful
IRP-> iostatus. Status = STATUS_SUCCESS;
IRP-> iostatus. Information = 0;

Gets the pointer to the current position in the IRP. This is where the code and parameters are located.
Irpstack = iogetcurrentirpstacklocation (IRP );

Inputbuffer = IRP-> associatedirp. systembuffer;
Inputbufferlength = iprstack-> parameters. deviceiocontrol. inputbufferlength;
Outputbuffer = IRP-> associatedirp. systembuffer;
Outputbufferlength = irpstack-> parameters. deviceiocontrol. outputbufferlength;
IoControlCode = irpStack-> Parameters. DeviceIoControl. IoControlCode;

Switch (irpStack-> MajorFunction)
{
Case IRP_MJ_CREATE:
Dbuplint ("Regmon: IRP_MJ_CREATE/n "));
Disable startup logs
If (BootLogging)
{
BootLogging = FALSE;
IoUnregisterShutdownNotification (DeviceObject );
MUTEX_WAIT (StoreMutex );
ExInitializeWorkItem (& workItem, RegmonCloseBootLog, 0 );
This function has expired. You should use IoAllocateWorkItem. Returns a pointer to the private structure IO_WORKITEM. The driver should not access this structure in any form!
ExQueueWorkItem (& workItem, CriticalWorkQueue );
This function has expired. You should use IoQueueWorkItem. Insert a specified work item to the queue. The queue is accessed by the system worker thread. The system worker thread removes a work item from the queue and calls the callback function.
KeWaitForSingleObject (& LoggingEvent, Executive, KernelMode, FALSE, NULL );
MUTEX_RELEASE (StoreMutex );
}
Sequence = 0;
GUIActive = TRUE;
Dbuplint ("GUI Active: % d/n", GUIActive ));
Break;
}
}

Still Small
Project-> Settings open the Link property page and delete all lib in the Object/library modules: edit the following box, and add msvcrt. lib kernel32.lib user32.lib.
On the Link property page of Project-> Settings, add/ALIGN: 4096 to the edit box under Project Options.

These are simple methods.

From:

Http://blog.csdn.net/floweronwarmbed/archive/2009/06/01/4233452.aspx

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.