📄 重入问题创建shadow device object.txt
字号:
Pdx->Type = STANDARD;
Pdx->FsDeviceObject = FileSysDevice;
Pdx->AttachToDeviceObject = FileSysDevice;
Pdx->[b]BuddyDeviceObject[/b] = ShadowDeviceObject;
//
// Finally, attach to the device. The second we're successfully attached, we may
// start receiving IRPs targetted at the device we've hooked.
//
Pdx->AttachToDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, FileSysDevice);
if (!Pdx->AttachToDeviceObject)
{
//
// Couldn' attach for some reason
//
KdPrint(("fdfilter.sys: Connect with Filesystem failed\n"));
//
// Derefence the object and get out
//
ObDereferenceObject(FileObject);
ZwClose(FileHandle);
IoDeleteDevice(ShadowDeviceObject);
IoDeleteDevice(DeviceObject);
return FALSE;
}
//
// Make a new drive group for the device,l if it does not have one
// already
//
KdPrint(("fdfilter.sys: Successfully connected to Filesystem device\n"));
DeviceObject->Flags |= FileSysDevice->Flags & (DO_DIRECT_IO | DO_BUFFERED_IO);
DeviceObject->Flags |= DO_POWER_PAGABLE;
DeviceObject->DeviceType = FileSysDevice->DeviceType;
DeviceObject->Characteristics = FileSysDevice->Characteristics;
//
// Clear the device's init flag as per NT DDK KB article on creating device
// objects from a dispatch routine
//
ShadowDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
//
// Close the file and update the hooked drive list by entering a
// pointer to the hook device object in it.
//
ObDereferenceObject(FileObject);
ZwClose(FileHandle);
return TRUE;
}
NTSTATUS
DispatchCreate(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
if (pdx->Type == SHADOW)
{
// ShadowDevice
// 调用过滤驱动的下一层驱动
PDEVICE_EXTENSION BuddyPdx = (PDEVICE_EXTENSION) pdx->[b]BuddyDeviceObject[/b]->DeviceExtension;
IoSkipCurrentIrpStatkLocation(Irp);
return IoCallDriver([b]BuddyPdx[/b]->AttachToDeviceObject, Irp);
}
else if (pdx->Type == STANDARD)
{
WCHAR wszFile[MAX_PATH] = {0};
// FilterDevice
// 我们需要再次打开该文件,为了避免重入...
GetFileNameFromFileObject(IrpSp->FileObject, wszFile);
// 假设 wszFile 里面原来内容为 L"1.txt"
// 修改为 L"\\Device\\FDFilterShadowA\\1.txt"
// 然后...
OBJECT_ATTRIBUTES oa;
InitializeObjectAttributes(&oa, wszFile, ...);
ZwCreateFile(..., &oa, ...); // 不会再有重入的问题了,:)))
// 因为会进入ShadowDevice's DispatchCreate
// ...
}
}
=========================
22222222
===========================
为解决重入问题创建shadow device object的代码,启动就蓝屏,请各位指点!
开发环境win2000,在sfilter的基础上修改,启动时就蓝屏。水平很菜,请高手纠正并请不要laugh at me。
根据OSR资料以及tooflat老大翻译的资料,想通过在SfMountCompletion中创建shadow device object来解决调用Zwxxx函数的重入问题(这样处理的话,以后在对文件进行操作时就不用自己创建IRP,我认为比较方便)。由于IoCreateDevice只能在<DISPATCH_LEVEL级别下运行,所以将创建的任务放到system worker thread中运行。
typedef struct _WORKER_CONTEXT
{
PDEVICE_OBJECT FilterDeviceObject;//attach到volume上的device object
KEVENT Event;//用于同步
} WORKER_CONTEXT, *PWORKER_CONTEXT;//sfCreateSecondDevice的参数
在SfMountCompletion中,在创建了一个filter device object并attach到设备栈顶部以后,将sfCreateSecondDevice放到system worker thread中:
MyworkContext.FilterDeviceObject = fsfDeviceObject;
KeInitializeEvent(&MyworkContext.Event, NotificationEvent, FALSE);
ExInitializeWorkItem(&MyWorkItem, sfCreateSecondDevice, &MyworkContext);
ExQueueWorkItem(&MyWorkItem, CriticalWorkQueue);
KeWaitForSingleObject(&MyworkContext.Event, Executive, KernelMode, FALSE, NULL);//等待sfCreateSecondDevice中的任务完成
VOID
sfCreateSecondDevice(IN OUT PWORKER_CONTEXT WorkContext)
{
PDEVICE_OBJECT DeviceObject1 = WorkContext->FilterDeviceObject;
PDEVICE_OBJECT DeviceObject2;
PDEVICE_EXTENSION Device1Extension;
PDEVICE_EXTENSION Device2Extension;
UNICODE_STRING Temp;//name of second device object
NTSTATUS status;
WCHAR Prefix[10] = {L'\0'};
Prefix[0] = L'M';
Prefix[1] = L'y';
Prefix[2] = L'D';
Prefix[3] = L'e';
Prefix[4] = L'v';
Prefix[5] = L'i';
Prefix[6] = L'c';
Prefix[7] = L'e';
Prefix[8] = MyDeviceSerialNo;
RtlInitUnicodeString(&Temp, Prefix);
status = IoCreateDevice(
FsDriverObject,
sizeof( DEVICE_EXTENSION ),
&Temp,
FILE_DEVICE_DISK_FILE_SYSTEM,
0,
FALSE,
&DeviceObject2
);
Device2Extension = DeviceObject2->DeviceExtension;
Device2Extension->RelatedDeviceObject = DeviceObject1;
Device2Extension->IsSecondDevice = TRUE;
Device2Extension->Size = sizeof( DEVICE_EXTENSION );
Device2Extension->FileSystemDeviceObject = NULL;
Device2Extension->RealDeviceObject = NULL;
Device2Extension->Attached = FALSE;
Device2Extension->Type = SFILTER_DEVICE_TYPE;
DeviceObject2->Flags &= ~DO_DEVICE_INITIALIZING;
Device1Extension = DeviceObject1->DeviceExtension;
Device1Extension->RelatedDeviceObject = DeviceObject2;
Device1Extension->IsSecondDevice = FALSE;
MyDeviceSerialNo = MyDeviceSerialNo + 1;//全局变量(其实最好用driverletter代替)
KeSetEvent(&(WorkContext->Event), IO_NO_INCREMENT, FALSE);
return;
}
==================
蓝屏是因为你的内存处理不对,或者没有判断pagefile
==============
znsoft老大的帮助,现在可以区分开由于调用ZwCreateFile引起的重入了,其实主要是犯了个低级错误,在创建shadow device object的时候名字搞错了,没加上 \Device\ 前缀:)
不过还是有几个问题请znsoft老大有时间的话解答一下,
1、你说“你在shdow object 进入它自己的dispatch时,需要修改fileobj下的realdevice. devicobject 为实际的设备才行.”,但是我没有这样做好象也可以啊,我在创建device object时将
DeviceExtension->Type设为自己定义的SHADOW_DEVICE_TYPE,进入sfCreate的时候只判断这个不就可以区别开了吗?
2、好象用创建shadow device object的方法只能对付Create的重入,因为在Zw系列函数中,只有ZwCreateFile参数中使用路径,其他函数都使用调用ZwCreateFile得到的file handle,而在调用ZwCreateFile发生重入后,已经将shadow device object换成了filter device object,所以在调用其他函数进行读/写/设置信息/询问信息 时都无法区别开。
是不是在进行读/写/设置信息/询问信息 时只能自己构造IRP?
3、在U盘插入时创建了一个shadow device object,那么如何在拔出U盘后找到并删除它?
谢谢znsoft老大!!!
=============
znsoft老大,请再帮我看看,我在read或write中调用ZwWriteFile为什么总是失败?这个函数没几个参数啊,应该不会错吧,是不是还是重入问题?是不是还是要自己构造IRP?谢谢!!!
TempBuffer = ExAllocatePool(NonPagedPool, 100);
for(i = 0; i<100; i++)
{
((PUCHAR) TempBuffer) = '9';
}//自己随便弄一个Buffer来写进去
RtlInitUnicodeString(&ObjectName, L"\\Device\\MyDeviceD\\temp.txt");
//MyDeviceD是自己定义的shadow device object,防止Create重入
InitializeObjectAttributes(&ObjectAttributes,
&ObjectName,
OBJ_KERNEL_HANDLE,
NULL,
NULL
);
Status = ZwCreateFile(&FileHandle,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes,
&IoStatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_OPEN_IF,
0,
NULL,
0
);//Create是成功的
if (!NT_SUCCESS(Status))
{
return Status;
}
Status = ZwWriteFile(FileHandle,
NULL,
NULL,
NULL,
&IoStatus,
TempBuffer,
100,
NULL,
NULL
);//write不知道怎么,就是fail
ZwClose(FileHandle);
ExFreePool(TempBuffer);
if (!NT_SUCCESS(Status))
{
return Status;
}
再次谢谢了!!!
==================
znsoft老大帮忙啊!
我前面回的帖子用了ZwWriteFile总是失败,不知道什么原因。现在想改用自己构造IRP的方法来写文件(在write dispatch routine中),代码如下,请帮忙看看:
RtlInitUnicodeString(&ObjectName, L"\\Device\\MyDeviceD\\temp.txt");
InitializeObjectAttributes(&ObjectAttributes,
&ObjectName,
OBJ_KERNEL_HANDLE,
NULL,
NULL
);
Status = ZwCreateFile(&FileHandle,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes,
&IoStatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_OPEN_IF,
0,
NULL,
0
);
if (!NT_SUCCESS(Status)));//Create是成功的
{
return Status;
}
KeInitializeEvent(&WriteEvent, NotificationEvent, FALSE);
WriteIrp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
DevExt->FileSystemDeviceObject,
OldBuffer,//从IRP中获得的buffer地址
Length,//从IRP中获得的数据长度
NULL,
&WriteEvent,
&IoStatus);//这里总是重启
if(WriteIrp == NULL)
{
ZwClose(FileHandle);
return Status;
}
Status = ObReferenceObjectByHandle(FileHandle, 0, NULL, KernelMode, WriteFileObject, NULL);
WriteIrp->RequestorMode = ExGetPreviousMode();
WriteIrp->Tail.Overlay.OriginalFileObject = WriteFileObject;
WriteStack = IoGetNextIrpStackLocation(WriteIrp);
WriteStack->FileObject = WriteFileObject;
Status = IoCallDriver(DevExt->FileSystemDeviceObject, WriteIrp);
if (!NT_SUCCESS(Status))
{
IoFreeIrp(WriteIrp);
ZwClose(FileHandle);
return Status;
}
KeWaitForSingleObject(&WriteEvent, Executive, KernelMode, FALSE, NULL);
KeClearEvent(&WriteEvent);
IoFreeIrp(WriteIrp);
ZwClose(FileHandle);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -