FSDHOOK恢复

	WCHAR DriverName[] = L"\\FileSystem\\ntfs";
	WCHAR DriverPath[] = L"\\??\\C:\\WINDOWS\\system32\\drivers\\ntfs.sys";
	RestoreFSDMajorRoutine(&DriverName, &DriverPath, IRP_MJ_CREATE);


//函数名: RestoreFSDMajorRoutine
	//
	// 参数: 
	//      DriverName - 文件系统驱动名
	//      DriverPath - 文件系统驱动全路径
	//      MajorFunctionIndex - IRP处理函数索引
	//
	// 返回值: 
	//       STATUS_SUCCESS - 成功
	//       STATUS_NOT_FOUND - 失败,没有找到指定的驱动
	//       STATUS_UNSUCCESSFUL - 失败
	//
	// 说明: 恢复FSD的IRP处理函数
	//
NTSTATUS RestoreFSDMajorRoutine(PCWSTR DriverName, PCWSTR DriverPath, ULONG MajorFunctionIndex)
{
	NTSTATUS            ntStatus = STATUS_SUCCESS;
	ULONG               ModuleBase = 0;
	UNICODE_STRING      uniDriverName;
	UNICODE_STRING      uniDriverPath;
	PDRIVER_OBJECT      DriverObject;
	ULONG               CurIrpDispatchRoutine;
	ULONG               OldIrpDispatchRoutine;
	ULONG               IrpIndex;

	OBJECT_ATTRIBUTES   objectAttributes;
	IO_STATUS_BLOCK     ioStatus;
	HANDLE              ntFileHandle;
	LARGE_INTEGER       byteOffset;

	ULONG               NtHeadersOffset;
	ULONG               AddressOfEntryPoint;
	ULONG               SizeOfImage;
	ULONG               ImageBase;
	ULONG               NeedSize;
	ULONG               Delta;
	PUCHAR              FileContent;
	ULONG               i;
	KIRQL               OldIrql;


	// 通过驱动文件名获得DriverObject
	RtlInitUnicodeString(&uniDriverName, DriverName);
	ntStatus = ObReferenceObjectByName(&uniDriverName,
		OBJ_CASE_INSENSITIVE,
		NULL,
		0,
		IoDriverObjectType,
		KernelMode,
		NULL,
		&DriverObject);

	if (!NT_SUCCESS(ntStatus))
		goto End;

	ModuleBase = DriverObject->DriverStart;

	// 当前的IRP分发历程
	CurIrpDispatchRoutine = (ULONG)DriverObject->MajorFunction[MajorFunctionIndex];
	IrpIndex = MajorFunctionIndex;
	IrpIndex = (IrpIndex + 0xE) << 2;
	// 索引+14,然后左移2位。[shl,即*4]

	// 设置属性后,打开指定位置的驱动文件
	RtlInitUnicodeString(&uniDriverPath, DriverPath);
	InitializeObjectAttributes(&objectAttributes, &uniDriverPath,
		OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);

	ntStatus = IoCreateFile(&ntFileHandle,
		FILE_READ_ATTRIBUTES,
		&objectAttributes,
		&ioStatus,
		0,
		FILE_ATTRIBUTE_NORMAL,
		FILE_SHARE_READ,
		FILE_OPEN,
		0,
		NULL,
		0,
		0,
		NULL,
		IO_NO_PARAMETER_CHECKING);

	if (!NT_SUCCESS(ntStatus))
	{
		ntStatus = STATUS_UNSUCCESSFUL;
		ObDereferenceObject(DriverObject);
		goto End;
	}

	// IMAGE_DOS_HEADER
	// +0x3c e_lfanew
	byteOffset.LowPart = 0x3C;
	byteOffset.HighPart = 0;

	// 打开驱动文件后,读之
	ntStatus = ZwReadFile(ntFileHandle,
		NULL,
		NULL,
		NULL,
		&ioStatus,
		&NtHeadersOffset,
		4,
		&byteOffset,
		NULL);

	if (!NT_SUCCESS(ntStatus))
	{
		ObDereferenceObject(DriverObject);
		ZwClose(ntFileHandle);
		goto End;
	}

	// NtHeadersOffset中保存的是PE头的偏移地址
	// IMAGE_OPTIONAL_HEADER
	// +0x010 AddressOfEntryPoint
	// 指向程序入口RVA地址
	byteOffset.LowPart = NtHeadersOffset + 0x28;
	byteOffset.HighPart = 0;

	ntStatus = ZwReadFile(ntFileHandle,
		NULL,
		NULL,
		NULL,
		&ioStatus,
		&AddressOfEntryPoint,
		4,
		&byteOffset,
		NULL);

	if (!NT_SUCCESS(ntStatus))
	{
		ObDereferenceObject(DriverObject);
		ZwClose(ntFileHandle);
		goto End;
	}

	// IMAGE_OPTIONAL_HEADER
	// +0x038 SizeOfImage 
	// 内存中整个PE个映像尺寸
	byteOffset.LowPart = NtHeadersOffset + 0x50;
	byteOffset.HighPart = 0;

	ntStatus = ZwReadFile(ntFileHandle,
		NULL,
		NULL,
		NULL,
		&ioStatus,
		&SizeOfImage,
		4,
		&byteOffset,
		NULL);

	if (!NT_SUCCESS(ntStatus))
	{
		ObDereferenceObject(DriverObject);
		ZwClose(ntFileHandle);
		goto End;
	}

	// IMAGE_OPTIONAL_HEADER
	// +0x01c ImageBase
	// 载入程序首选的RVA
	byteOffset.LowPart = NtHeadersOffset + 0x34;
	byteOffset.HighPart = 0;

	ntStatus = ZwReadFile(ntFileHandle,
		NULL,
		NULL,
		NULL,
		&ioStatus,
		&ImageBase,
		4,
		&byteOffset,
		NULL);

	if (!NT_SUCCESS(ntStatus))
	{
		ObDereferenceObject(DriverObject);
		ZwClose(ntFileHandle);
		goto End;
	}

	// 经过一系列的读PE后,得到一些偏移值。计算PE在内存中需要的空间。
	// 为其分配一个非分页内存
	// 将文件的内容都读取到这里
	NeedSize = SizeOfImage - AddressOfEntryPoint;

	FileContent = ExAllocatePool(NonPagedPool, NeedSize);

	if (FileContent == NULL)
	{
		ntStatus = STATUS_UNSUCCESSFUL;
		ObDereferenceObject(DriverObject);
		ZwClose(ntFileHandle);
		goto End;
	}

	byteOffset.LowPart = AddressOfEntryPoint;
	byteOffset.HighPart = 0;

	ntStatus = ZwReadFile(ntFileHandle,
		NULL,
		NULL,
		NULL,
		&ioStatus,
		FileContent,
		NeedSize,
		&byteOffset,
		NULL);

	if (!NT_SUCCESS(ntStatus))
	{
		ObDereferenceObject(DriverObject);
		ZwClose(ntFileHandle);
		ExFreePool(FileContent);
		goto End;
	}

	OldIrpDispatchRoutine = 0;
	if (NeedSize <= 0)
	{
		ntStatus = STATUS_NOT_FOUND;
		ObDereferenceObject(DriverObject);
		ZwClose(ntFileHandle);
		ExFreePool(FileContent);
		goto End;
	}

	// 这样的找法比较容易崩溃。。。汗。。。
	for (i = 0; i < NeedSize; ++i)
	{
		// 对于fastfat.sys和ntfs.sys都是
		// mov dword ptr [esi+IrpIndex], local_XXXX
		// 不晓得MJ这里的0x46或0x43是哪个了。。。
		// 
		if (FileContent[i] == 0xC7 &&
			(FileContent[i + 1] == 0x46 || FileContent[i + 1] == 0x43) &&
			FileContent[i + 2] == IrpIndex &&
			FileContent[i + 7] == 0xC7)
		{
			// 找到了,这才是原IRP分发例程的原地址
			OldIrpDispatchRoutine = *(PULONG)&FileContent[i + 3];

			if (OldIrpDispatchRoutine == 0)
				goto NotFound;

			if (OldIrpDispatchRoutine > SizeOfImage)
				goto NotFound;

			// 因为可能重定位了。所以用实际的基址-程序首选的RVA地址。得到的是一个偏移值
			Delta = ModuleBase - ImageBase;

			// 加上此偏移值才是真正的内存地址
			OldIrpDispatchRoutine += Delta;

			if (!MmIsAddressValid((PVOID)OldIrpDispatchRoutine))
				goto NotFound;

			/* ++ RestoreFSDHook --*/
			if (OldIrpDispatchRoutine == CurIrpDispatchRoutine)
				goto NotFound;


			WPOFF();
			DriverObject->MajorFunction[MajorFunctionIndex] = (PDRIVER_DISPATCH)OldIrpDispatchRoutine;
			WPON();


			ExFreePool(FileContent);
			ZwClose(ntFileHandle);
			ObDereferenceObject(DriverObject);

			goto End;

			/* ++ RestoreFSDHook --*/
		}
	}

NotFound:
	ntStatus = STATUS_NOT_FOUND;
	ObDereferenceObject(DriverObject);
	ZwClose(ntFileHandle);
	ExFreePool(FileContent);

End:
	return ntStatus;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值