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


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

中转inline hook,不需要恢复首字节的hook

注:我实验的环境:win7 x64 经验证XP会有稍微区别,主要是我本次实验HOOK的API, 从XP到WIN7微软有了些许改变。 ----------------------------------...
  • friendan
  • friendan
  • 2015年02月23日 23:38
  • 3680

VC++实现恢复SSDT

SSDT(System Services Descriptor Table),系统服务描述符表。这个表就是一个把ring3的Win32 API和ring0的内核API联系起来。SSDT并不仅仅只包含一...
  • whatday
  • whatday
  • 2013年09月04日 10:12
  • 1520

FSD HOOK与SSDT HOOK恢复简单思路

FSD 解释: File System Driver文件系统驱动程序,分为本地FSD和远程FSD。 (1) 本地FSD:允许用户访问本地计算机上的数据 ——本地FSD负责向I/O管理器注...
  • cosmoslife
  • cosmoslife
  • 2015年12月24日 15:29
  • 604

SSDT HOOK的恢复

根据内核文件ntoskrnl.exe或ntkrnlpa.exe获得原始SSDT,与当前SSDT内容相比,如果不相同就说明被HOOK了,用原始值改写。 具体流程: 1. 确定windows所...
  • andylau00j
  • andylau00j
  • 2014年05月24日 21:06
  • 698

驱动保护中的ObjectType_Callback探索

最近学习驱动保护,有点小小心德与大家分享下。 当前环境:VM中的win7 32 保护程序是某游戏的驱动保护。 具体现象是:在用PCHunter工具查看object钩子时发现如下的信息:   ...
  • whatday
  • whatday
  • 2013年10月31日 23:03
  • 6220

活用mysql的binlog进行数据恢复

在日常操作mysql的过程中可能会遇到因为操作失误导致数据丢失,由于操作之前没有进行备份,而最近备份的文件时间又早,很可能导致备份之后到现在这段时间数据的丢失,那么如何应对这种突发状况?其实mysql...
  • a7442358
  • a7442358
  • 2015年08月08日 16:30
  • 5412

R-Studio如何恢复被格式化移动硬盘数据

前一段时间帮同学装系统,在做u盘启动盘的时候一不小心把1T的移动硬盘格式化了,当时大半夜实在是难过极了,后来花了一些钱找人恢复数据,恢复了大部分,但还是丢失了一些,但在恢复的过程中我发现了他们使用的工...
  • grape875499765
  • grape875499765
  • 2017年03月20日 23:39
  • 1061

IAT随便HOOK+反检测方法

防IAT检测方法:IAT在指定目标文件的PE结构里面指定了的,我们把自己内存里面做了修改,没有修改目标文件,只要不让目标文件被其他文件映射,读取PE结构和我们内存中修改过的比较,保证能反一切IAT检测...
  • kingswb
  • kingswb
  • 2016年06月15日 22:27
  • 670

FSD HOOK与SSDT HOOK恢复简单思路

首先是FSD HOOK。 网上比较容易找到的是sudami对360superkiller的逆向,映射大小计算上好像有些错误。 这里贴出我的想法,备忘 :) 1.       向ZwQuerySys...
  • whatday
  • whatday
  • 2013年09月03日 16:08
  • 2049

Linux ext3/ext4误删文件,数据恢复方法

测试环境: Ubuntu 12.04 X86 +ext4 恢复文件使用的工具:extundelete(点击下载) 说明:当文件异常消失或者rm误删除后,避免在该分区中继续读、写、删除...
  • lanyzh0909
  • lanyzh0909
  • 2014年11月05日 17:42
  • 8680
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:FSDHOOK恢复
举报原因:
原因补充:

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