HOOK SSDT

这篇文章是根据作者Tesla.Angela 在 看雪论坛 发布的文章所写

这个 X86还是比较好实现的  但是  X64 就有些绕了 而且   比较麻烦吧     其实x64做的保护 听容易看出来的  

他先把ssdt 搞成动态 然后 又把 ssdt 放入的地址搞成偏移地址  这个让我有点奇怪    

我先发一下  作者 Tesla.Angela的原话 

 知道了这一套机制,HOOK SSDT 就很简单了,首先获得待 HOOK 函数的序号 Index,然后通过公式把自己的代理函数的地址转化为偏移地址,然后把偏移地 址的数据填入 ServiceTableBase[Index]。也许有些读者看到这里,已经觉得胜 利在望了,我当时也是如此。但实际上我在这里栽了个大跟头,整整郁闷了很长 时间!因为我低估了设计这套算法的工程师的智商,我没有考虑一个问题,为什 么 WIN64 的 SSDT 表存放地址的形式这么奇怪?只存放偏移地址,而不存放完整 地址?难道是为了节省内存?这肯定是不可能的,要知道现在内存白菜价。那么 不是为了节省内存,唯一的可能性就是要给试图挂钩 SSDT 的人制造麻烦!要知 道,WIN64 内核里每个驱动都不在同一个 4GB 里,而 4 字节的整数只能表示 4GB 的范围!所以无论你怎么修改这个值,都跳不出 ntoskrnl 的手掌心。如果你想 通过修改这个值来跳转到你的代理函数,那是绝对不可能的。因为你的驱动的地 址不可能跟 ntoskrnl 在同一个 4GB 里。然而,这位工程师也低估了我们中国人 的智商,在中国有两句成语,这位工程师一定没听过,叫“明修栈道,暗渡陈仓” 以及“上有政策,下有对策”。虽然不能直接用 4 字节来表示自己的代理函数所 在的地址,但是还是可以修改这个值的。要知道,ntoskrnl 虽然有很多地方的代 码通常是不会被执行的,比如 KeBugCheckEx。所以我的办法是:修改这个偏移地 址的值,使之跳转到 KeBugCheckEx,然后在 KeBugCheckEx 的头部写一个 12 字 节的 mov - jmp,这是一个可以跨越 4GB 的跳转,跳到我们的函数里!

其实 这里我现在还不是很了解   win64内核每个驱动都不在同一个4gb    这句话不是很了解 

(今天问了一下 很多大佬 他们 和我说 可以理解成和虚拟进程差不多)

64位实际只用了48位 这个是我通过问别人得出来的   这个是根据系统而言来定的  然后 我们就可以 

直接撸代码 了  但是 问了很多人  也没有个回答 等以后懂了在添上去把

其实这里 作者 Tesla.Angela  做的方法 还是比较 可以的 

因为 KeBugCheckEx 如果执行的话也是蓝屏 那么作者的想法就是 也不用修复了

只要把 我们hook的那个函数 给填回去就好了 

然后我们 在x86 只需改寄存器的值 就能够  把空间改成可写  这里作者  Tesla.Angela 也是  写了两个函数  

KIRQL WPOFFx64()
{
	KIRQL irql=KeRaiseIrqlToDpcLevel();
	UINT64 cr0=__readcr0();
	cr0 &= 0xfffffffffffeffff;
	__writecr0(cr0);
	_disable();
	return irql;
}

void WPONx64(KIRQL irql)
{
	UINT64 cr0=__readcr0();
	cr0 |= 0x10000;
	_enable();
	__writecr0(cr0);
	KeLowerIrql(irql);
}

下面就是代码  ~~~~~~ 看起来 下章的  UNHOOK 好像更难一些~~~

#include <ntddk.h>
#include <windef.h>
#pragma intrinsic(__readmsr)
typedef struct _SYSTEM_SERVICE_TABLE{
	PLONG  		ServiceTableBase;
	PVOID  		ServiceCounterTableBase;
	ULONGLONG  	NumberOfServices;
	PVOID  		ParamTableBase;
} SYSTEM_SERVICE_TABLE, *PSYSTEM_SERVICE_TABLE;
PSYSTEM_SERVICE_TABLE ssdt;
typedef NTSTATUS(__fastcall *NTTERMINATEPROCESS)(IN HANDLE ProcessHandle, IN NTSTATUS ExitStatus);
NTKERNELAPI
UCHAR *
PsGetProcessImageFileName(PEPROCESS Process);
NTTERMINATEPROCESS NtTerminateProcess = NULL;
ULONG addr = 0;
ULONGLONG GetSsdt()
{
	PUCHAR startaddr = (PUCHAR)__readmsr(0xc0000082);//这里是两个下划线
	PUCHAR Endaddr = startaddr + 0x500;
	PUCHAR i = NULL;
	UCHAR b1, b2, b3;
	ULONG temp = 0;
	ULONGLONG addr = 0;
	for (i = startaddr; i < Endaddr; i++)
	{
		b1 = *i;
		b2 = *(i + 1);
		b3 = *(i + 2);
		if (b1 == 0x4c && b2 == 0x8d && b3 == 0x15)
		{
			memcpy(&temp, i + 3, 4);
			addr = (ULONGLONG)temp + (ULONGLONG)i + 7;
			return addr;
		}
	}
	return 0;
}
KIRQL OFF()
{
	KIRQL f = KeRaiseIrqlToDpcLevel();
	UINT64 cr0 = __readcr0();
	cr0 &= 0xfffffffffffeffff;
	__writecr0(cr0);
	_disable();
	return f;
}
VOID ON(KIRQL f)
{
	UINT64 cr0 = __readcr0();
	cr0 |= 0x10000;
	_enable();
	__writecr0(cr0);
	KeLowerIrql(f);
}
ULONG GetOffsetAddress(ULONGLONG FuncAddr)
{
	ULONG dwtmp = 0;
	PULONG ServiceTableBase = NULL;
	ServiceTableBase = (PULONG)ssdt->ServiceTableBase;
	dwtmp = (ULONG)(FuncAddr - (ULONGLONG)ServiceTableBase);
	return dwtmp << 4;
}
ULONGLONG GetFunctionAddress(ULONGLONG index)
{	
	PULONG ServiceTableBase = NULL;
	LONG Temp;
	ULONGLONG temp,ret=0;
	ServiceTableBase = (PULONG)ssdt->ServiceTableBase;
	Temp = ServiceTableBase[index];
	Temp = Temp >> 4;
	ret = (LONGLONG)ServiceTableBase + (LONGLONG)Temp;
	return ret; 
}
NTSTATUS __fastcall Fake_NtTerminateProcess(IN HANDLE ProcessHandle, IN NTSTATUS ExitStatus)
{
	PEPROCESS Process;
	NTSTATUS status = ObReferenceObjectByHandle(ProcessHandle, 0 ,* PsProcessType, KernelMode, &Process, NULL);
	KdPrint(("hook已经开始"));
	if (NT_SUCCESS(status))
	{
		if (!_stricmp(PsGetProcessImageFileName(Process), "loaddrv.exe") || !_stricmp(PsGetProcessImageFileName(Process), "calc.exe"))
		{
			return STATUS_ACCESS_DENIED;
		}
		else
			return NtTerminateProcess(ProcessHandle, ExitStatus);

	}
	else
		return STATUS_ACCESS_DENIED;
}
VOID FuckKeBugCheckEx()//跳转 HOOK 函数
{
	KIRQL irql;
	ULONGLONG fun;
	fun = (ULONGLONG)Fake_NtTerminateProcess;
	UCHAR jmp[] = "\x48\xB8\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xE0";
	memcpy(jmp + 0x2, &fun, 8);
	irql = OFF();
	memset(KeBugCheckEx, 0x90, 15);
	memcpy(KeBugCheckEx, jmp, 12);
	ON(irql);
}
VOID HookSsdt()
{
	KIRQL f;
	PULONG ServiceTableBase = NULL;
	NtTerminateProcess = (NTTERMINATEPROCESS)GetFunctionAddress(41);
	FuckKeBugCheckEx();
	ServiceTableBase = ssdt->ServiceTableBase;	
	addr = ServiceTableBase[41];
	f = OFF();
	ServiceTableBase[41] = GetOffsetAddress((ULONGLONG)KeBugCheckEx);
	ON(f);
	KdPrint(("KeBugCheckEx: %llx", (ULONGLONG)KeBugCheckEx));
	KdPrint(("New_NtTerminateProcess: %llx", GetFunctionAddress(41)));
	  
}
VOID UnHookSsdt()
{
	KIRQL f;
	PULONG ServiceTableBase = NULL;
	ServiceTableBase = ssdt->ServiceTableBase;
	f = OFF();
	ServiceTableBase[41] =addr;
	ON(f);
	KdPrint(("NtTerminateProcess: %llx", GetFunctionAddress(41)));
}
VOID DriverUnload(PDRIVER_OBJECT driver)
{
	UnHookSsdt();
	KdPrint(("goodbye"));
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
	ULONGLONG i = 0;
	PSYSTEM_SERVICE_TABLE add=NULL;
	ULONGLONG addxr = GetSsdt();
	if (addxr== 0)
	{
		KdPrint(("大哥对不起 没有找到ssdt!\n"));
		return STATUS_SUCCESS;
	}
	ssdt = (PSYSTEM_SERVICE_TABLE)addxr;//得到ssdt的表
	HookSsdt();
	
	DriverObject->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;
}

猜你喜欢

转载自blog.csdn.net/qq_41071646/article/details/86488131