在笔者上一篇文章《驱动开发:内核注册并监控对象回调》
介绍了如何运用ObRegisterCallbacks
注册进程与线程
回调,并通过该回调实现了拦截
指定进行运行的效果,本章LyShark
将带大家继续探索一个新的回调注册函数 , PsSetLoadImageNotifyRoutine
常用于注册LoadImage
映像监视,当有模块被系统加载时则可以第一时间获取到加载模块信息,需要注意的是该回调函数内无法进行拦截 , 如需要拦截则需写入返回指令这部分内容将在下一章进行讲解,本章将主要实现对模块的监视功能 。
监视模块加载与卸载需要费别使用两个函数 , 这两个函数的参数传递都是自己的回调地址 。
- PsSetLoadImageNotifyRoutine 设置回调
- PsRemoveLoadImageNotifyRoutine 移除回调
MyLySharkLoadImageNotifyRoutine
回调地址必须有三个参数传递组成,其中FullImageName
代表完整路径,ModuleStyle
代表模块类型 , 一般来说ModuleStyle=0
表示加载SYS驱动,如果ModuleStyle=1
则表示加载的是DLL
,最后一个参数ImageInfo
则是映像的详细参数结构体 。VOID MyLySharkLoadImageNotifyRoutine(PUNICODE_STRING FullImageName, HANDLE ModuleStyle, PIMAGE_INFO ImageInfo)
那么如何实现监视映像加载呢,来看如下完整代码片段,首先PsSetLoadImageNotifyRoutine
注册回调,当有模块被加载则自动执行MyLySharkLoadImageNotifyRoutine
回调函数 , 其内部首先判断ModuleStyle
得出是什么类型的模块,然后再通过GetDriverEntryByImageBase
拿到当前进程详细参数并打印输出 。// 署名权// right to sign one's name on a piece of work// PowerBy: LyShark// Email: me@lyshark.com#include <ntddk.h>#include <ntimage.h>// 未导出函数声明PUCHAR PsGetProcessImageFileName(PEPROCESS pEProcess);// 获取到镜像装载基地址PVOID GetDriverEntryByImageBase(PVOID ImageBase){ PIMAGE_DOS_HEADER pDOSHeader; PIMAGE_NT_HEADERS64 pNTHeader; PVOID pEntryPoint; pDOSHeader = (PIMAGE_DOS_HEADER)ImageBase; pNTHeader = (PIMAGE_NT_HEADERS64)((ULONG64)ImageBase + pDOSHeader->e_lfanew); pEntryPoint = (PVOID)((ULONG64)ImageBase + pNTHeader->OptionalHeader.AddressOfEntryPoint); return pEntryPoint;}// 获取当前进程名UCHAR* GetCurrentProcessName(){ PEPROCESS pEProcess = PsGetCurrentProcess(); if (NULL != pEProcess) {UCHAR *lpszProcessName = PsGetProcessImageFileName(pEProcess);if (NULL != lpszProcessName){return lpszProcessName;} } return NULL;}// 设置自己的回调函数VOID MyLySharkLoadImageNotifyRoutine(PUNICODE_STRING FullImageName, HANDLE ModuleStyle, PIMAGE_INFO ImageInfo){ PVOID pDrvEntry; // MmIsAddress 验证地址可用性 if (FullImageName != NULL && MmIsAddressValid(FullImageName)) {// ModuleStyle为零表示加载sysif (ModuleStyle == 0){// 得到装载主进程名UCHAR *load_name = GetCurrentProcessName();pDrvEntry = GetDriverEntryByImageBase(ImageInfo->ImageBase);DbgPrint("[LyShark SYS加载] 模块名称:%wZ --> 装载基址:%p --> 镜像长度: %d --> 装载主进程: %s \n", FullImageName, pDrvEntry, ImageInfo->ImageSize, load_name);}// ModuleStyle非零表示加载DLLelse{// 得到装载主进程名UCHAR *load_name = GetCurrentProcessName();pDrvEntry = GetDriverEntryByImageBase(ImageInfo->ImageBase);DbgPrint("[LyShark DLL加载] 模块名称:%wZ --> 装载基址:%p --> 镜像长度: %d --> 装载主进程: %s \n", FullImageName, pDrvEntry, ImageInfo->ImageSize, load_name);} }}VOID UnDriver(PDRIVER_OBJECT driver){ PsRemoveLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)MyLySharkLoadImageNotifyRoutine); DbgPrint("[LyShark.com] 驱动卸载完成...");}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath){ DbgPrint("hello lyshark.com \n"); PsSetLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)MyLySharkLoadImageNotifyRoutine); DbgPrint("[LyShark.com] 驱动加载完成..."); Driver->DriverUnload = UnDriver; return STATUS_SUCCESS;}
运行这个驱动程序 , 则会输出被加载的驱动详细参数 。![驱动开发:内核监视LoadImage映像回调](http://img.zhejianglong.com/231018/224T05292-0.jpg)
文章插图
【驱动开发:内核监视LoadImage映像回调】
推荐阅读
- iOS开发之自定义日历控件
- Windows10 + Eclipse C/C++开发环境配置极简教程
- 驱动开发:内核测试模式过DSE签名
- 驱动开发:内核枚举进程与线程ObCall回调
- 不妨试试更快更小更灵活Java开发框架Solon
- 了解 Flutter 开发者们的 IDE 使用情况
- 一 测试开发HTTP请求过程
- 驱动开发:内核枚举Registry注册表回调
- Teambition企业内部应用开发指南
- Doris开发手记4:倍速性能提升,向量化导入的性能调优实践