除了 SSDT hook和Inline hook外,内核还提供其他官方的API方便我们进行hook操作从而完成一些安全软件的研发等。
举例其中以下API
函数
PsSetCreateProcessNotifyRoutine
typedef VOID (*PCREATE_PROCESS_NOTIFY_ROUTINE)(_In_ HANDLE ParentId,_In_ HANDLE ProcessId,_In_ BOOLEAN Create);NTSTATUS PsSetCreateProcessNotifyRoutine([in] PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,[in] BOOLEAN Remove
);
PsSetCreateProcessNotifyRoutineEx
typedef VOID (*PCREATE_PROCESS_NOTIFY_ROUTINE_EX) (_Inout_ PEPROCESS Process,_In_ HANDLE ProcessId,_Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo);NTSTATUS PsSetCreateProcessNotifyRoutineEx([in] PCREATE_PROCESS_NOTIFY_ROUTINE_EX NotifyRoutine,[in] BOOLEAN Remove
);
两个函数都是用于注册一个回调监听进程的创建或者退出时调用NotifyRoutine
,不同的是EX
后缀函数不仅可以监听而且还可以控制创建的进程结果。
参数说明
NotifyRoutine
: 回调函数
Remove
: 如果为TRUE ,从系统回调表中删除回调函数的注册。FALSE为注册函数到回调函数表中。
我们以PsSetCreateProcessNotifyRoutineEx 为示例具体讲解。
函数返回值
STATUS_SUCCESS
成功注册
STATUS_INVALID_PARAMETER
函数已经注册过,或者注册表已经达到上限不能注册
STATUS_ACCESS_DENIED
如果没有PE格式设置 IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY
标记,那么会抛出这个。
关于IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY
一些介绍可参阅:
/INTEGRITYCHECK(需要签名检查)
具体在编写驱动时加入以下标志:
我们最后看相关的回调函数
typedef VOID (*PCREATE_PROCESS_NOTIFY_ROUTINE_EX) (//可以通过这个获取一些进程的上下文信息_Inout_ PEPROCESS Process,//进程id_In_ HANDLE ProcessId,//如果这个参数为NULL表示程序退出。 不为NULL表示程序创建_Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo);
我编写一个相关案例实现效果如下:
(1) 打印创建/退出的进程名字
(2) 如果进程是计算器进程修改进程创建结果,使其创建失败
#include //系统隐藏API 只需要声明即可
extern "C" UCHAR * PsGetProcessImageFileName(PEPROCESS Process);//设置的进程监听的回调函数
VOID MyProcessNotify(_Inout_ PEPROCESS Process,_In_ HANDLE ProcessId,_Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo
) {DbgPrint("[My learning] MyProcessNotify invoke \r\n");//获取进程的名称UCHAR* ImageFileName = PsGetProcessImageFileName(Process);//如果不为空证明创建进程if (CreateInfo != NULL){DbgPrint("[My learning] MyProcessNotify create process \r\n");DbgPrint("[My learning] MyProcessNotify %s pid: %d path:%wZ \r\n",ImageFileName,ProcessId,CreateInfo->ImageFileName);//比较当前的进程名称是否为计算器if (RtlCompareMemory("Calculator.exe", ImageFileName, sizeof "Calculator.exe")){DbgPrint("[My learning] MyProcessNotify create process \r\n");//控制创建进程的标志为失败标志CreateInfo->CreationStatus = STATUS_INVALID_PARAMETER;}}else {//进程为空 退出进程DbgPrint("[My learning] MyProcessNotify exit process %s \r\n", ImageFileName);}}//这个函数被注册用于驱动卸载调用
VOID myUnload(struct _DRIVER_OBJECT* DriverObject
) {UNREFERENCED_PARAMETER(DriverObject);DbgPrint("[My learning] drive myUnload \r\n");//一定设置卸载回调。不然一直会在注册表中PsSetCreateProcessNotifyRoutineEx(&MyProcessNotify, TRUE);
}//驱动被加载的时候会调用此函数
extern "C"
NTSTATUS
DriverEntry(_In_ struct _DRIVER_OBJECT* DriverObject,_In_ PUNICODE_STRING RegistryPath
)
{//如果你没有用到参数需要告诉系统。UNREFERENCED_PARAMETER(RegistryPath);//打印信息DbgPrint("[My learning] drive loaded\r\n ");//注册监听回调NTSTATUS stat = PsSetCreateProcessNotifyRoutineEx(&MyProcessNotify, FALSE);//打印注册结果DbgPrint("[My learning] PsSetCreateProcessNotifyRoutineEx ret %p \r\n", stat);DriverObject->DriverUnload = myUnload;return STATUS_SUCCESS;
}
开启调试后日志:
[My learning] drive loaded[My learning] PsSetCreateProcessNotifyRoutineEx ret 0000000000000000
Suspending
[My learning] MyProcessNotify invoke
[My learning] MyProcessNotify create process
[My learning] MyProcessNotify taskhostw.exe pid: 2964 path:\??\C:\Windows\system32\taskhostw.exe
[My learning] MyProcessNotify invoke
[My learning] MyProcessNotify create process
[My learning] MyProcessNotify ApplicationFra pid: 2076 path:\??\C:\Windows\system32\ApplicationFrameHost.exe
[My learning] MyProcessNotify invoke
[My learning] MyProcessNotify create process
[My learning] MyProcessNotify dllhost.exe pid: 348 path:\??\C:\Windows\system32\DllHost.exe[My learning] MyProcessNotify invoke
[My learning] MyProcessNotify create process
[My learning] MyProcessNotify Calculator.exe pid: 3108 path:\??\C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.1506.19010.0_x64__8wekyb3d8bbwe\Calculator.exe
[My learning] MyProcessNotify create process
[My learning] MyProcessNotify invoke
[My learning] MyProcessNotify exit process Calculator.exe
运行后你发现你永远无法打开计算器这个应用程序,并且会出输出所有的程序创建。
PsSetCreateProcessNotifyRoutineEx 会构造一张表存储相关。
我们反编译相关window内核文件C:\Windows\System32\ntoskrnl.exe。
也就是我们清空这个表地址数据那么我们的hook计算器无法打开的操作讲失效.我们使用windbg尝试对应的操作