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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章