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