背景
对于内核层实现监控模块的加载,包括加载DLL模块、内核模块等。你也许会想到 HOOK 各种内核函数来实现。确定,在内核层中的 HOOK 已经给人留下太多深刻的印象了,有 SSDT HOOK、Inline HOOK、IRP HOOK、过滤驱动等等。
但是,Windows 其实给我们提供现成的内核函数接口,方便我们在内核下监控用户层上模块加载的情况,即 PsSetLoadImageNotifyRoutine 内核函数,可以设置一个回调函数,来监控监控模块加载。
现在,本文就使用 PsSetLoadImageNotifyRoutine 实现监控模块加载以及卸载加载模块的实现过程和原理进行整理,形成文档,分享给大家。
函数介绍
PsSetLoadImageNotifyRoutine 函数设置模块加载回调函数,只要有模块加载完成就会通知回调函数。
函数声明
NTSTATUSPsSetLoadImageNotifyRoutine(
_In_PLOAD_IMAGE_NOTIFY_ROUTINENotifyRoutine
);
参数
NotifyRoutine [in]
指向回调函数 PLOAD_IMAGE_NOTIFY_ROUTINE 的指针。
返回值
成功,则返回 STATUS_SUCCESS;否则,返回其它失败错误码 NTSTATUS。
备注
可通过调用 PsRemoveLoadImageNotifyRoutine 函数来删除回调。
PLOAD_IMAGE_NOTIFY_ROUTINE 回调函数函数声明
PLOAD_IMAGE_NOTIFY_ROUTINESetLoadImageNotifyRoutine;
voidSetLoadImageNotifyRoutine(
_In_opt_PUNICODE_STRINGFullImageName,
_In_HANDLEProcessId,
_In_PIMAGE_INFOImageInfo
)
{...}
参数
FullImageName [in,可选]
指向缓冲的Unicode字符串的指针,用于标识可执行映像文件。 (在程序创建时操作系统无法获取图像的全名的情况下,FullImageName参数可以为NULL。)
ProcessId [in]
加载模块所属的进程ID,但如果新加载的映像是驱动程序,则该句柄为 0。
ImageInfo [in]
指向包含图像信息的 IMAGE_INFO 结构的指针。 见备注。
返回值
无返回值。
IMAGE_INFO 结构体typedefstruct_IMAGE_INFO{
union{
ULONGProperties;
struct{
ULONGImageAddressingMode:8;
ULONGSystemModeImage:1;
ULONGImageMappedToAllPids:1;
ULONGExtendedInfoPresent:1;
ULONGMachineTypeMismatch:1;
ULONGImageSignatureLevel:4;
ULONGImageSignatureType:3;
ULONGReserved:13;
};
};
PVOIDImageBase;
ULONGImageSelector;
SIZE_TImageSize;
ULONGImageSectionNumber;
}IMAGE_INFO,*PIMAGE_INFO;
成员<