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