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

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章