📄 dispatch.c
字号:
// Version history
// 27-Apr-99 1.0.0 CC creation
/////////////////////////////////////////////////////////////////////////////
#include "MySpyKer.h"
extern FAST_MUTEX gSpyDeviceExtensionListLock;
extern LIST_ENTRY gSpyDeviceExtensionList;
NTSTATUS
SpyControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PIO_STACK_LOCATION irpStack;
PVOID ioBuffer;
ULONG InputBufferLength;
ULONG OutputBufferLength;
PDEVICE_EXTENSION deviceExtension;
ULONG ioControlCode;
PWSTR deviceName = NULL;
#if DBG
DebugPrint("IRP_MJ_DEVICE_CONTROL\n");
#endif
//
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
//
deviceExtension = (PDEVICE_EXTENSION)
DeviceObject->DeviceExtension;
// Can't accept a new io request if:
// 1) device is removed,
// 2) has never been started,
// 3) is stopped,
// 4) has a remove request pending,
// 5) has a stop device pending
irpStack = IoGetCurrentIrpStackLocation (Irp);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
// get pointers and lengths of the caller's (user's) IO buffer
ioBuffer = Irp->AssociatedIrp.SystemBuffer;
InputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
OutputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
switch( ioControlCode)
{
case FILESPY_Attach:
if (ioBuffer == NULL || InputBufferLength <= 0)
{
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Copy the device name and add a null to ensure that it is null terminated
//
deviceName = (PWSTR)ExAllocatePool( NonPagedPool, InputBufferLength + sizeof(WCHAR) );
if (NULL == deviceName) {
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
RtlCopyMemory( deviceName, ioBuffer, InputBufferLength );
deviceName[InputBufferLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
ntStatus = Irp->IoStatus.Status = MyFileSpyAttachDevice(DeviceObject,deviceName);
break;
case FILESPY_Detach:
if (ioBuffer == NULL || InputBufferLength <= 0)
{
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Copy the device name and add a null to ensure that it is null terminated
//
deviceName = ExAllocatePool( NonPagedPool, InputBufferLength + sizeof(WCHAR) );
if (NULL == deviceName) {
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
RtlCopyMemory( deviceName, ioBuffer, InputBufferLength );
deviceName[InputBufferLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
ntStatus = Irp->IoStatus.Status = SpyDetachDevice(deviceName);
break;
}
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return ntStatus;
}
//
NTSTATUS
MyFileSpyAttachDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PWSTR DeviceName)
{
WCHAR nameBuf[DEVICE_NAME_SZ];
UNICODE_STRING volumeNameUnicodeString;
NTSTATUS status;
PDEVICE_OBJECT nextDriverDeviceObject;
PDEVICE_OBJECT attachedDeviceObject;
PFILE_OBJECT volumeFileObject;
HANDLE fileHandle;
OBJECT_ATTRIBUTES objectAttributes;
PDEVICE_EXTENSION devext;
IO_STATUS_BLOCK openStatus;
volumeNameUnicodeString.MaximumLength = sizeof(nameBuf);
volumeNameUnicodeString.Buffer = nameBuf;
volumeNameUnicodeString.Length= 0;
RtlAppendUnicodeToString(&volumeNameUnicodeString,DeviceName);
//????????????????????????????
devext = SpyFindAttachedDevice(&volumeNameUnicodeString);
if (devext != NULL) {
devext->LogThisDevice = TRUE;
return STATUS_SUCCESS;
}
volumeNameUnicodeString.Length= 0;
RtlAppendUnicodeToString(&volumeNameUnicodeString, L"\\DosDevices\\");
RtlAppendUnicodeToString(&volumeNameUnicodeString,DeviceName);
InitializeObjectAttributes(
&objectAttributes,
&volumeNameUnicodeString,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,//
NULL,
NULL);
// open the file object for the given device
status = ZwCreateFile(
&fileHandle,
SYNCHRONIZE|FILE_READ_DATA,
&objectAttributes,
&openStatus,
NULL,
0,
FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT/*|FILE_DIRECTORY_FILE*/,
NULL,
0);
if( !NT_SUCCESS( status ) ) {
return status;
}
// get a pointer to the volumes file object
status = ObReferenceObjectByHandle(
fileHandle,
FILE_READ_DATA,
*IoFileObjectType,
KernelMode,
(PVOID*)&volumeFileObject,
NULL);
if( !NT_SUCCESS( status )) {
ZwClose( fileHandle );
return status;
}
// Get the device object we want to attach to (parent device object in chain)
nextDriverDeviceObject = IoGetRelatedDeviceObject( volumeFileObject );
if (nextDriverDeviceObject == NULL)
{
ObDereferenceObject( volumeFileObject );
ZwClose( fileHandle );
return status;
}
if (!SpyAlreadyAttached( nextDriverDeviceObject, &devext )) {
//
// We are not already attached, so attach to this device object.
//
// create a new device object so we can attach it in the call chain
status = IoCreateDevice(
DeviceObject->DriverObject,
sizeof(DEVICE_EXTENSION),
NULL,
nextDriverDeviceObject->DeviceType,
0,
FALSE,
&attachedDeviceObject);
if ( !NT_SUCCESS(status) ) {
ObDereferenceObject( volumeFileObject );
ZwClose( fileHandle );
return status;
}
devext = (PDEVICE_EXTENSION)
attachedDeviceObject->DeviceExtension;
devext->LogThisDevice = TRUE;
devext->Type = FILESPY_DEVICE_TYPE;
devext->Size = sizeof( DEVICE_EXTENSION );
devext->DeviceName.MaximumLength = sizeof(devext->NameBuffer);
devext->DeviceName.Buffer = devext->NameBuffer;
devext->DeviceName.Length= 0;
RtlAppendUnicodeToString(&devext->DeviceName, DeviceName);
// Add our device object to chain
devext->NextDriverDeviceObject = IoAttachDeviceToDeviceStack(
attachedDeviceObject,
nextDriverDeviceObject );
// see if we could not attach
if (devext->NextDriverDeviceObject == NULL) {
IoDeleteDevice(attachedDeviceObject);
ObDereferenceObject(volumeFileObject);
ZwClose(fileHandle);
return STATUS_UNSUCCESSFUL;
}
ExAcquireFastMutex(&gSpyDeviceExtensionListLock);
InsertTailList(&gSpyDeviceExtensionList, &devext->NextDevice);
ExReleaseFastMutex(&gSpyDeviceExtensionListLock);
if (nextDriverDeviceObject->Flags & DO_BUFFERED_IO) {
attachedDeviceObject->Flags |= DO_BUFFERED_IO;
}
if (nextDriverDeviceObject->Flags & DO_DIRECT_IO) {
attachedDeviceObject->Flags |= DO_DIRECT_IO;
}
attachedDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
} else {
//
// We are already attached, so just add this name to the
// device name for this device extension.
//
RtlAppendUnicodeToString( &devext->DeviceName, L"," );
RtlAppendUnicodeToString( &devext->DeviceName, DeviceName );
}
ObDereferenceObject( volumeFileObject );
ZwClose( fileHandle );
return STATUS_SUCCESS;
}
//
PDEVICE_EXTENSION
SpyFindAttachedDevice (
IN PUNICODE_STRING devName
)
/*++
Routine Description:
This scans the list of devices we have physical attachments too and
sees if we already have an attachment to this device.
Arguments:
devName - the name of the device to check
Return Value:
The DEVICE_EXTENSION object for the given named object, NULL if it was
not found.
--*/
{
PDEVICE_EXTENSION devext;
PLIST_ENTRY link;
try {
ExAcquireFastMutex( &gSpyDeviceExtensionListLock );
for (link = gSpyDeviceExtensionList.Flink;
link != &gSpyDeviceExtensionList;
link = link->Flink) {
devext = CONTAINING_RECORD(link, DEVICE_EXTENSION, NextDevice);
if (SpyFindSubString(devName,&devext->DeviceName))
{
try_return(devext);
}
}
devext = NULL;
try_exit:
NOTHING;
} __finally {
ExReleaseFastMutex( &gSpyDeviceExtensionListLock );
return devext; // didn't find the name, return
}
}
//
BOOLEAN
SpyAlreadyAttached (
IN PDEVICE_OBJECT CandidateDeviceObject,
OUT PDEVICE_EXTENSION *DeviceExtension
)
/*++
Routine Description:
This routine looks through the list of FileSpy device extensions to
see if we have attached to CandidateDeviceObject's device.
This is necessary to work around attaching to network devices. All
network drives are represented by one device object. If we
have more that one network drive, we don't want to attach to this
device object more than once (if we attached more than once, we
would see all I/O to any network drive as many times as we are
attached).
Arguments:
CandidateDeviceObject - Device object that the FileSpy driver is
considering attaching to. We want to make sure that we haven't
already attached to this device object.
DeviceExtension - Gets set to the device extension already attached
to CandidateDeviceObject if we are already attached to
CandidateDeviceObject.
Return Value:
Returns TRUE if we have already attached and FALSE otherwise.
--*/
{
PLIST_ENTRY entry;
PDEVICE_EXTENSION currentExtension;
PDEVICE_OBJECT currentDevice;
BOOLEAN found = FALSE;
*DeviceExtension = NULL;
ExAcquireFastMutex( &gSpyDeviceExtensionListLock );
try {
//
// Look through our deviceExtension list and see if we have a device
// extension for CandidateDeviceObject already.
//
for (entry = gSpyDeviceExtensionList.Flink;
entry != &gSpyDeviceExtensionList;
entry = entry->Flink) {
currentExtension = CONTAINING_RECORD( entry, DEVICE_EXTENSION, NextDevice);
if (currentExtension->NextDriverDeviceObject == CandidateDeviceObject) {
//
// We do have a device extension that references this CandidateDeviceObject
// so return TRUE after setting the output parameter DeviceExtension.
//
*DeviceExtension = currentExtension;
try_return( found = TRUE );
} else {
//
// The NextDriverDeviceObject for this extension may be up the
// stack of CandidateDeviceObject. If so, we don't want to attach
// again. So we look through CandidateDeviceObject->AttachedDevice
// so that we catch this.
//
for (currentDevice = currentExtension->NextDriverDeviceObject->AttachedDevice;
currentDevice != NULL;
currentDevice = currentDevice->AttachedDevice) {
if (currentDevice == CandidateDeviceObject) {
//
// We found a deviceObject in the stack that we are attached to,
// so return this extension.
//
*DeviceExtension = currentExtension;
try_return( found = TRUE );
}
}
}
}
try_exit:
NOTHING;
} __finally {
ExReleaseFastMutex( &gSpyDeviceExtensionListLock );
}
return found;
}
//
BOOLEAN
SpyFindSubString (
IN PUNICODE_STRING String,
IN PUNICODE_STRING SubString
)
{
ULONG index;
//
// First, check to see if the strings are equal.
//
if (RtlEqualUnicodeString( String, SubString, TRUE )) {
return TRUE;
}
//
// String and SubString aren't equal, so now see if SubString
// in in String any where.
//
for (index = 0;
index + SubString->Length <= String->Length;
index++) {
if (_wcsnicmp(&(String->Buffer[index]),
SubString->Buffer,
SubString->Length) == 0) {
//
// SubString is found in String, so return TRUE.
//
return TRUE;
}
}
return FALSE;
}
//
NTSTATUS
SpyDetachDevice (
IN PWSTR DeviceName
)
/*++
Routine Description:
This routine stop logging the specified device. Since you can not
physically detatch from devices, this routine simply sets a flag saying
to not log the device anymore.
Note: Since all network drives are represented by _one_ device object,
and, therefore, one device extension, if the user detaches from one
network drive, it has the affect of detaching from _all_ network
devices.
Arguments:
DeviceName - The name of the device to "detach" from.
Return Value:
NT Status code
--*/
{
WCHAR nameBuf[DEVICE_NAME_SZ];
UNICODE_STRING volumeNameUnicodeString;
PDEVICE_EXTENSION devext;
volumeNameUnicodeString.MaximumLength = sizeof(nameBuf);
volumeNameUnicodeString.Buffer = nameBuf;
volumeNameUnicodeString.Length= 0;
RtlAppendUnicodeToString(&volumeNameUnicodeString,DeviceName);
devext = SpyFindAttachedDevice(&volumeNameUnicodeString);
if (devext != NULL) {
ExAcquireFastMutex( &gSpyDeviceExtensionListLock );
RemoveEntryList(&devext->NextDevice); // remove from LOG list
ExReleaseFastMutex( &gSpyDeviceExtensionListLock );
devext->LogThisDevice = FALSE;
//???????????????????????????????????
IoDetachDevice(devext->NextDriverDeviceObject);
return STATUS_SUCCESS;
}
return STATUS_INVALID_PARAMETER;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -