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