FSDHOOK恢复

原创 2016年08月30日 16:10:57
	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;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

vSphere ESXi 的虚拟机恢复

安装的 ESXi 的物理主机出现故障,需要重新安装 ESXi ,安装后恢复原先物理主机上的 虚拟机的方法如下(VMFS分区完好): 关于 VMFS 分区:  ESXi 的安装时会划分一个分区用于 ...

详述 IntelliJ IDEA 中恢复代码的方法

在咱们正常开发项目的时候,难免遇到在开发过程中由于某种原因,想要将代码恢复到前一版本的情景。特别是在咱们删除了某些代码,想要恢复之前删除的代码的时候,了解这个在 IntelliJ IDEA 中恢复代码...

svn的恢复到指定版本操作

本文目的 让未使用过版本控制器软件或者未使用过subversion软件的人员尽快上手。 subversion的使用技巧很多,这里只总结了最小使用集,即主要的基本功能,能够用来应付日常工作。...

ORACLE11g 重装系统后根据dbf恢复数据库

1.安装一个和原系统一致的oracle 环境,主要包括版本、数据名sid、实例名、路径和数据库编码一致 2.修改listener.ora的参数SID_LIST_LISTENER = (SID_LI...
  • ywswen
  • ywswen
  • 2017年01月02日 12:57
  • 2084

RMAN实战10:完全恢复数据库

完全恢复是:恢复到故障前所有已经提交的事物。 必须满足下面条件: 1.处于归档模式 2.有良好基点备份 3.有上次备份操作后生成的所有重做日志 4.有上次备份操作后生成的...
  • x6_9x
  • x6_9x
  • 2015年12月21日 21:02
  • 638

Oracle 表空间时点恢复(TSPITR)

表空间时点恢复,是Oracle在基于冷备,热备恢复以外的一种以表空间为粒度的,不完全恢复的形式来将表空间恢复到过去某个特定的时间点的一种恢复方式。它整合了RMAN以及DataPump这2个备份恢复工具...

PostgreSQL 恢复数据库数据

PostgreSQL 恢复数据库数据 a.     开始恢复数据库数据           选择好恢复文件后,点击恢复...

利用jquery插件中的拖拽与放置实现的相册效果,可以删除和恢复

该效果为官方提供,本人只是进行了一下翻译,加了些详细注释供大家参考,对大家有帮助就ok了,如有解释错误谢谢提出。 以下是需要引入的一些文件,如果没有您可以通过给定的地址进行下载,谢谢: j...

Quartz的任务的临时启动和暂停和恢复

Quartz的任务的临时启动和暂停和恢复   在项目中需要手动启停某些服务,那么需要有一个控制这些任务的类。由于任务是有Quartz控制的,我们只需要通过Quartz的相关的API实现相关的功能即可。...
  • xpsharp
  • xpsharp
  • 2014年02月16日 16:47
  • 5361

移动硬盘,U盘出现USBC病毒乱码恢复的可能性分析

详尽分析USBC的产生以及处理,纠正度娘的危险方案
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:FSDHOOK恢复
举报原因:
原因补充:

(最多只允许输入30个字)