x64内核hook

x64中系统提供了api帮助我们进行hook,主要是如下三个函数

PsSetCreateProcessNotifyRoutineEx,这个函数的作用就是 当进程创建的时候会通知你.

PsSetCreateThreadNotifyRoutine,这个函数的作用是 当线程创建的时候会通知你。

PsSetLoadImageNotifyRoutine,这个函数的作用是 当模块加载的时候会通知你。

 

回调函数原型
VOID
  CreateProcessNotifyEx(
    __inout PEPROCESS  Process,          //进程的EPROCESS会提供给你.
    __in HANDLE  ProcessId,             //进程ID会提供给你.
    __in_opt PPS_CREATE_NOTIFY_INFO  CreateInfo  //进程信息的额外信息会提供给你. 注意参数是可操作的.也就是说可能为NULL
    );

NTSTATUS
  PsSetCreateThreadNotifyRoutine(
    IN PCREATE_THREAD_NOTIFY_ROUTINE  NotifyRoutine  //回调函数地址.当线程创建完毕,但还没运行的时候会调用你的回调.
    );

NTSTATUS
  PsSetLoadImageNotifyRoutine(
    IN PLOAD_IMAGE_NOTIFY_ROUTINE  NotifyRoutine
    );

进程和线程回调代码如下:

#include <ntddk.h>

NTKERNELAPI PCHAR PsGetProcessImageFileName(PEPROCESS Process);
NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process);

/*typedef struct _PS_CREATE_NOTIFY_INFO {
SIZE_T              Size;
union {
ULONG  Flags;
struct {
ULONG FileOpenNameAvailable  :1;
ULONG Reserved  :31;
};
};
HANDLE              ParentProcessId;
CLIENT_ID           CreatingThreadId;
struct _FILE_OBJECT  *FileObject;
PCUNICODE_STRING    ImageFileName;
PCUNICODE_STRING    CommandLine;
NTSTATUS            CreationStatus;
} PS_CREATE_NOTIFY_INFO, *PPS_CREATE_NOTIFY_INFO;*/

/*VOID MyCreateProcessNotifyEx	//仅监视
(
__inout   PEPROCESS Process,
__in      HANDLE ProcessId,
__in_opt  PPS_CREATE_NOTIFY_INFO CreateInfo
)
{
if(CreateInfo==NULL)
DbgPrint("[monitor_create_process_x64] Process exit: %s",PsGetProcessImageFileName(Process));
else
DbgPrint("[monitor_create_process_x64] Process create: %wZ",CreateInfo->CommandLine);
}*/

PCHAR GetProcessNameByProcessId(HANDLE ProcessId)
{
	NTSTATUS st = STATUS_UNSUCCESSFUL;
	PEPROCESS ProcessObj = NULL;
	PCHAR string = NULL;
	st = PsLookupProcessByProcessId(ProcessId, &ProcessObj);
	if (NT_SUCCESS(st))
	{
		string = PsGetProcessImageFileName(ProcessObj);
		ObfDereferenceObject(ProcessObj);
	}
	return string;
}

VOID MyCreateProcessNotifyEx
(
__inout   PEPROCESS Process,
__in      HANDLE ProcessId,
__in_opt  PPS_CREATE_NOTIFY_INFO CreateInfo
)
{
	char procName[16] = { 0 };
	if (CreateInfo != NULL)	//进程创建事件
	{
		DbgPrint("[monitor_create_process_x64][%ld]%s创建进程: %wZ",
			CreateInfo->ParentProcessId,
			GetProcessNameByProcessId(CreateInfo->ParentProcessId),
			CreateInfo->ImageFileName);
		strcpy(procName, PsGetProcessImageFileName(Process));
		DbgPrint("创建的进程名为:%p/n", procName);
		if (!_stricmp(procName, "calc.exe"))
		{
			DbgPrint("禁止创建计算器进程!");
			CreateInfo->CreationStatus = STATUS_UNSUCCESSFUL;	//禁止创建进程
		}
	}
	else
	{
		DbgPrint("[monitor_create_process_x64]进程退出: %s", PsGetProcessImageFileName(Process));
	}
}

VOID MyCreateThreadNotify
(
IN HANDLE  ProcessId,
IN HANDLE  ThreadId,
IN BOOLEAN  Create
)
{
	if (Create)
		DbgPrint("[monitor_create_process_x64]线程创建! PID=%ld;TID=%ld", ProcessId, ThreadId);
	else
		DbgPrint("[monitor_create_process_x64]线程退出! PID=%ld;TID=%ld", ProcessId, ThreadId);

	PEPROCESS Process = NULL;
	PETHREAD  Thread = NULL;
	UCHAR *pszImageName = NULL;
	NTSTATUS status;
	UCHAR *pWin32Address = NULL;

	status = PsLookupProcessByProcessId(ProcessId, &Process);//1.通过进程ID,获取EPROCESS
	if (!NT_SUCCESS(status))
		return;

	status = PsLookupThreadByThreadId(ThreadId, &Thread);//2.通过线程ID,获取ETHREAD

	pszImageName = PsGetProcessImageFileName(Process);//3.通过EPROCESS获取进程名


	if (Create)
	{
		//dprintf("[Hello] Create Thread pid=%d tid=%d ImageName=%s\r\n", ProcessId, ThreadId, pszImageName);
		if (strstr(pszImageName, "calc") != NULL)  //4.判断进程名是否是计算器
		{
			//KdBreakPoint();

			//修改回调函数代码
			pWin32Address = *(UCHAR**)((UCHAR*)Thread + 0x410);  //5.是的话.找到回调函数地址.并改为C3
			//KeAttachProcess();
			if (MmIsAddressValid(pWin32Address))
			{
				KdBreakPoint();
				//*pWin32Address = 0xC3;       //修改为C3,但是注意,你修改的是否内存保护属性需要去掉.但是在64位下,不允许使用内联汇编了.不过你可以写二进制进行更改.或者汇编生成obj,驱动来使用
				//这里直接手动更改为C3.
			}
			//KeUnstackDetachProcess();
		}
	}
	else
		//dprintf("[Hello] Exit Thread pid=%d tid=%d\r\n", ProcessId, ThreadId);


	if (Process)
		ObDereferenceObject(Process);     //引用计数--
	if (Thread)
		ObDereferenceObject(Thread);
}

VOID Monitor()
{
	// set create process/thread notify
	NTSTATUS st = PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)MyCreateProcessNotifyEx, FALSE);
	if (!NT_SUCCESS(st))
	{
		DbgPrint("PsSetCreateProcessNotifyRoutineEx return false");
	}
	
	st = PsSetCreateThreadNotifyRoutine(MyCreateThreadNotify);
	if (!NT_SUCCESS(st))
	{
		DbgPrint("PsSetCreateThreadNotifyRoutine return false");
	}
}

// 卸载驱动 一定要移除回调,否则蓝屏
VOID RemoveMonitor()
{
	//remove create process/thread notify
	PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)MyCreateProcessNotifyEx, TRUE);
	PsRemoveCreateThreadNotifyRoutine(MyCreateThreadNotify);
}

 模块加载回调函数如下

#include <ntddk.h>
#include <ntimage.h>

VOID UnicodeToChar(PUNICODE_STRING dst, char *src)
{
	ANSI_STRING string;
	RtlUnicodeStringToAnsiString(&string, dst, TRUE);
	strcpy(src, string.Buffer);
	RtlFreeAnsiString(&string);
}

PVOID GetDriverEntryByImageBase(PVOID pImageBase)
{
	PIMAGE_DOS_HEADER pDOSHeader;
	PIMAGE_NT_HEADERS64 pNTHeader;
	PVOID pEntryPoint;
	pDOSHeader = (PIMAGE_DOS_HEADER)pImageBase;
	pNTHeader = (PIMAGE_NT_HEADERS64)((ULONG64)pImageBase + pDOSHeader->e_lfanew);
	return (PVOID)((ULONG64)pImageBase + pNTHeader->OptionalHeader.AddressOfEntryPoint);
}

BOOLEAN VxkCopyMemory(PVOID pDestination, PVOID pSourceAddress, SIZE_T SizeOfCopy)
{
	PMDL pMdl = NULL;
	PVOID pSafeAddress = NULL;
	pMdl = IoAllocateMdl(pSourceAddress, (ULONG)SizeOfCopy, FALSE, FALSE, NULL);
	if (!pMdl) return FALSE;
	__try
	{
		MmProbeAndLockPages(pMdl, KernelMode, IoReadAccess);
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		IoFreeMdl(pMdl);
		return FALSE;
	}
	pSafeAddress = MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority);
	if (!pSafeAddress) return FALSE;
	RtlCopyMemory(pDestination, pSafeAddress, SizeOfCopy);
	MmUnlockPages(pMdl);
	IoFreeMdl(pMdl);
	return TRUE;
}

VOID DenyLoadDriver(PVOID DriverEntry)
{
	// “拒绝访问” 的机器码
	// mov eax, c0000022h
	// ret 
	// 机器码位 \xB8\x22\x00\x00\xC0\xC3

	UCHAR fuck[] = "\xB8\x22\x00\x00\xC0\xC3";
	VxkCopyMemory(DriverEntry, fuck, sizeof(fuck));
}

VOID LoadImageNotifyRoutine(
	_In_ PUNICODE_STRING FullImageName,
	_In_ HANDLE ProcessId,                // pid into which image is being mapped
	_In_ PIMAGE_INFO ImageInfo
	)
{
	PVOID pDrvEntry;
	char szFullImageName[260] = { 0 };
	if (FullImageName != NULL && MmIsAddressValid(FullImageName))
	{
		//KdPrint(("processid = %lld", ProcessId));
		// 根据回调函数 LoadImageNotifyRoutine 的第二个参数判断,如果 PID 是0,则表示加载驱动,如果 PID 位非零,则表示加载 DLL。

		if (0 == ProcessId)
		{ 
			pDrvEntry = GetDriverEntryByImageBase(ImageInfo->ImageBase);
			UnicodeToChar(FullImageName, szFullImageName);
			KdPrint(("当前加载的模块是:%wZ", FullImageName));
			// strlwr函数的功能是将字符串中的S参数转换为小写形式。
			if (strstr(szFullImageName, "Win7_x64_SSDT_Hook.sys"))
			{
				DenyLoadDriver(pDrvEntry);
			}
		}
	}
}

VOID MonitorLoadModule()
{
	NTSTATUS nt = PsSetLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)LoadImageNotifyRoutine);
	if (!NT_SUCCESS(nt))
	{
		KdPrint(("call PsSetLoadImageNotifyRoutine failed"));
	}
}

VOID RemoveMonitorLoadModule()
{
	PsRemoveLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)LoadImageNotifyRoutine);
}

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值