⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 新建 文本文档 (2).txt

📁 是很不错的工具在你找系统文件的时候
💻 TXT
📖 第 1 页 / 共 2 页
字号:

在本文的前面部分,我们已经描述了在一个没有被装配的物理磁盘卷被访问时IO管理器如何调用所有注册了的文件系统。每一个文件系统驱动程序都有机会去分析卷直到一个驱动程序声明可以识别此卷。所以文件系统识别器在这里收到一个装配请求,文件系统识别器调用Recognizer _DetectFileSystem函数,这个函数将在稍候被描述。如果该函数返回STATUS_SUCCESS,说明该卷该文件系统识别器的文件系统驱动识别。接着返回STATUS_FS_DRIVER_REQUIRED给IO管理器。这个错误码被IO管理器特殊对待,因为对文件系统识别器的支持是建立在IO管理器的装配过程。一旦收到此IRP,IO管理器便发送一个新的IO请求给文件系统识别器。这一次发送的次功能码IRP_MN_LOAD_FILE_SYSTEM。识别器用ZwLoadDriver函数处理这个请求。该函数唯一的参数是需要加载的驱动的注册表项。如果加载驱动成功,ZwLoadDriver返回STATUS_SUCCESS,识别器可以反注册和删除识别器设备对象,这将导致识别器驱动程序被卸载。从该文件系统被注册开始,这是它第一次被调用。 

当整个文件系统被加载后,IO管理器将和文件系统程序再进行一次装配请求。因为整个文件系统被加载了,识别器已经不再需要了。随后的请求将被文件系统驱动程序处理。 
//
// RecognizerDetectFileSystem
//
// 用户需要根据自己文件系统的不同改变这些代码
// 输入参数:
// Irp – 请求装配卷的IRP.
//
// 输出参数:
// None.
//
// Returns:
// STATUS_SUCCESS – 这是我们的驱动可以识别的文件系统
// Other - I/O error
//
// Notes:
// None.
//

static NTSTATUS RecognizerDetectFileSystem(PIRP Irp)
{
	NTSTATUS code =STATUS_SUCCESS;
	DISK_GEOMETRY diskGeometry;
	PARTITION_INFORMATION partitionInfo;
	PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
	PVPB vpb = irpSp->Parameters.MountVolume.Vpb;
	PDEVICE_OBJECT mediaDeviceObject = irpSp->Parameters.MountVolume.DeviceObject;
	unsigned char* pBuffer = NULL;

	//首先构造一个可以获得卷的分区表等信息的IRP,用RecognizerIoControl传递到下层驱动。
	// IF error{
	//   return error
	//}
	// else
	//   {
	//用RecognizerReadDiskSector 读卷参数块(VPB)}
	// If read error{
	//    return error
	//}
	// else
	// {检查文件系统的标识符,如果不匹配
	// return error
	//}
	// else
	// return code STATUS_SUCCESS;
	// endif
	// endif
	// endif
	//

	// 现在返回错误码
	code = STATUS_UNRECOGNIZED_VOLUME;
	return code;
}

上面的代码显示RecognizerDetectFileSystem的全部内容。它负责实际的的卷的类型的检测。因为它的实现依赖于实际的物理卷。所以我们只提供一个通用的方法。你需要修改使得它适用于实际的卷。 

这个例程需要实现两个关键的功能,一个是从存储介质读取数据,另外一个是从存储介质中获得关于介质的关键信息。这些功能被两个函数封装了,第一个是RecogizerReadDiskSector()从物理卷中读取用于分析的数据。第二个函数RecognizerIoControl(…)用于向下层设备发送请求,这些请求返回关于物理介质的信息,例如每一个扇区多少个字节。IOCTL_DISK_GET_PARTITION_ INFORMATION用于返回已经被装配了的卷的信息。NT文件系统用分区信息用作匹配签名算法的一部分。注意RecognizerReadDiskSector()函数用的是相对于分区的扇区数而不是相对于磁盘的扇区数。所以如果你传入参数0,你将得到的是分区的第一个扇区,而不是磁盘的第一个分区。换句话说,如果分区从第540扇区开始,用0做参数调用函数,你得到的是相对于分区为0,而相对于磁盘为549的扇区数据。. 
//
// RecognizerIoControl
//
// 这个函数用于发送特定的IRP个下层驱动
//
// 输出参数:
// MediaHandle – 特定设备的卷句柄
// Offset – 读请求的逻辑偏移量
// Length – 读的长度
// MDL – 数据将要被拷贝的MDL链t
//
// 输出参数:
// None.
//
// Returns:
// STATUS_SUCCESS - I/O completed successfully
// Other - I/O error
//
// Notes:
// None.
//

static NTSTATUS RecognizerIoControl( IN PDEVICE_OBJECT deviceObject,
	IN ULONG IoctlCode,
	IN PVOID InputBuffer,
	IN ULONG InputBufferSize,
	OUT PVOID OutputBuffer,
	OUT ULONG OutputBufferSize)
{
	PIRP irp;
	NTSTATUS code;
	KEVENT event;
	IO_STATUS_BLOCK iosb;

	// 初始化用于等待操作成功完成的事件对象
	KeInitializeEvent(&event, SynchronizationEvent, FALSE);

	// 创建请求
	//
	irp = IoBuildDeviceIoControlRequest(IoctlCode,
		deviceObject,
		InputBuffer,
		InputBufferSize,
		OutputBuffer,
		OutputBufferSize,
		FALSE,
		&event,
		&iosb);

	// 向下层驱动发送IRP
	code = IoCallDriver(deviceObject, irp);

	//如果可能的话,我们必须等待。注意,我们不接受异步过程调用。在IO操作完成之前,我们不能返回。
	if (code == STATUS_PENDING) {
		(void) KeWaitForSingleObject(&event, Executive, KernelMode,
		TRUE, 0);
		code = iosb.Status;
	}

	//
	// 设置最终的输出缓冲区大小.
	//

	OutputBufferSize = iosb.Information;

	//
	// 完成
	//
	return(code);
}

//
//
// RecognizerReadDiskSector
//
// 从一个特定的卷读取一个扇区
//
// 输入参数:
// pDeviceObject –磁盘设备对象的指针.
// DiskSector – 需要读取的扇区数目.
//
// Outputs:
// Buffer – 用于接收读取内容的缓冲区.
//
// Returns:
// Returns TRUE if the disk sector was read.
//
// Notes:
// None.
//

static BOOLEAN RecognizerReadDiskSector(
	IN PDEVICE_OBJECT pDeviceObject,
	IN ULONG DiskSector,
	IN UCHAR* Buffer // must be DEVICE_LOGICAL_BLOCKSIZE bytes long.)
{
	LARGE_INTEGER sectorNumber;
	PIRP irp;
	IO_STATUS_BLOCK ioStatus;
	KEVENT event;
	NTSTATUS status;
	ULONG sectorSize;
	PULONG mbr;
	PAGED_CODE();
	sectorNumber.QuadPart = (LONGLONG) DiskSector *DEVICE_LOGICAL_BLOCKSIZE;

	//创建一个用于检查是否完成通知事件对象
	KeInitializeEvent(&event, NotificationEvent, FALSE);

	// 获得扇区大小
	sectorSize = DEVICE_LOGICAL_BLOCKSIZE;

	// 分配内存.
	mbr = ExAllocatePool(NonPagedPoolCacheAligned, sectorSize);
	if (!mbr) {
		return FALSE;
	}

	// 创建读MBR的IRP
	irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
		pDeviceObject,
		mbr,
		sectorSize,
		§orNumber,
		&event,
		&ioStatus );
	if (!irp) {
		ExFreePool(mbr);
		return FALSE;
	}

	// 把IRP传送个端口驱动程序
	status = IoCallDriver(pDeviceObject, irp);

	if (status == STATUS_PENDING) {
		KeWaitForSingleObject(&event,
		Suspended,
		KernelMode,
		FALSE,
		NULL);

	status = ioStatus.Status;
}


if (!NT_SUCCESS(status)) {
ExFreePool(mbr);
return FALSE;
}


//
// 返回读取的扇区信息
//

RtlCopyMemory(Buffer,mbr,sectorSize);
ExFreePool(mbr);
return TRUE;
}

上面的代码包含了RecognizerIoControl()和RecognizerReadDiskSector(…)的实现。和所有的代码一样,他们是自解释的。因为该函数运行在PASSIVE_LEVEL 级别的IRQL上,所以可以调用KeWaitForSingleObject()函数去等待相关操作完成。 

运行这个驱动程序

现在我们已经文件系统识别的全部讲述了一遍。现在是讨论如何注册文件系统识别器个文件系统驱动的时候了。你需要像这样配置识别器和驱动程序。 
SYSTEM\CurrentControlSet\Services\MyFsdRecognizer
Class Name: <NO CLASS>
Last Write Time: 10/10/96 - 4:09 AM
Value 0
Name: ErrorControl
Type: REG_DWORD
Data: 0x1
Value 1
Name: Group
Type: REG_SZ
Data: File system
Value 2
Name: Start
Type: REG_DWORD
Data: 0x1
Value 3
Name: Type
Type: REG_DWORD
Data: 0x8

Key Name: SYSTEM\CurrentControlSet\Services\MyFsd
Class Name: <NO CLASS>
Value 0
Name: ErrorControl
Type: REG_DWORD
Data: 0x1
Value 1
Name: Group
Type: REG_SZ
Data: File system
Value 2
Name: Start
Type: REG_DWORD
Data: 0x3
Value 3
Name: Type
Type: REG_DWORD
Data: 0x2


从上面的的配置信息你可以知道,识别器在系统启动时启动,它是“File System”组的一个成员。文件系统驱动程序是手动启动的,这一点是另人疑惑的。这样做可以让驱动程序被识别器用ZwLoadDriver()加载,而不是被NT内核加载。 

结论

一个文件系统识别器是一个简单的驱动程序,但它却是必须的。它可以使你的驱动“按需启动“,而且最小化内存需求。  
  
 返回页首
 
 
 
 
关于我们 | 联系方式 | 站点地图 | 招贤纳士 | 帝国论坛 
?2005-2007 C语言帝国(vcgood.com) 版权所有 闽ICP备05035124号 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -