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