Win64 驱动内核编程-13.回调监控模块加载
回调监控模块加载
模块加载包括用户层模块(.DLL)和内核模块(.SYS)的加载。传统方法要监控这两者加在必须 HOOK 好几个函数,比如 NtCreateSection 和 NtLoadDriver
等,而且这些方法还不能监控未知的驱动加载方法。其实为了监控模块加载而HOOK API 是非常傻的,因为微软已经提供了一对标准的 API 实现此功能。它们
分别是 PsSetLoadImageNotifyRoutine 和 PsRemoveLoadImageNotifyRoutine,可以设置/取消一个“映像加载通告例程”,当有驱动或者 DLL 被加载时,回调函
数就会被调用。有人可能认为这个标准方法的监控非常表层,其实恰恰相反,这个方法非常底层,大部分隐秘的加载驱动的方法都可以绕过 NtLoadDriver,但
是无法绕过“映像加载通告例程”。所以用此方法监控驱动加载是最合适的了。
之前说过,这个通告例程不仅仅管加载驱动,连进程加载 DLL 也管,那我们怎么判断到底是加载驱动还是加载 DLL 呢?如果说根据后缀名判断则很明显是一个挫方法。我的方
法是, 根据回调函数 e LoadImageNotifyRoutine 的第二个参数判断,如果 D PID 是0 0 ,则表示加载驱动,如果 D PID 位非零,则 表示加载 DLL 。原因很简单,我之前说过这个函数很底层,到了一定的深度之后就无法判断到底是谁主动引发的行为了,一切都是系统的行为。当然,你也可以认为这是通过回调来监控驱动加载的缺点。判断了是驱动后,就通过 ImageInfo->ImageBase 来获取驱动的映像基址。过 如果不想让这个驱动加载,就通过 e ImageBase 得 来获得 y DriverEntry 的地址(ImageBase 就是 DOS 头,根据 DOS 头找到 NT 头,然后在 NT 头的 OptionalHeader里就能找到入口点了。入口点的数据就是 DriverEntry 的地址) , 并 写入 “拒绝访问 ” 的机器码 即可。
//添加:
PsSetLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)LoadImageNotifyRoutine);
//删除:
PsRemoveLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)LoadImageNotifyRoutine);
其中 NotifyRoutine 是一个函数指针,此回调函数的原型是:
VOID (*PLOAD_IMAGE_NOTIFY_ROUTINE)
(
__in_opt PUNICODE_STRING FullImageName,
__in HANDLE ProcessId,
__in PIMAGE_INFO ImageInfo
);
下面是实现模块监控,并且拒绝Powertool的驱动加载的例子代码:
#include <ntddk.h>
#include <ntimage.h>
#define dprintf DbgPrint
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 UnicodeToChar(PUNICODE_STRING dst, char *src)
{
ANSI_STRING string;
RtlUnicodeStringToAnsiString(&string,dst, TRUE);
strcpy(src,string.Buffer);
RtlFreeAnsiString(&string);
}
void DenyLoadDriver(PVOID DriverEntry)
{
UCHAR fuck[]="\xB8\x22\x00\x00\xC0\xC3";
VxkCopyMemory(DriverEntry,fuck,sizeof(fuck));
}
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;
}
VOID LoadImageNotifyRoutine
(
__in_opt PUNICODE_STRING FullImageName,
__in HANDLE ProcessId,
__in PIMAGE_INFO ImageInfo
)
{
PVOID pDrvEntry;
char szFullImageName[260]={0};
if(FullImageName!=NULL && MmIsAddressValid(FullImageName))
{
if(ProcessId==0)
{
DbgPrint("[MyDriver]%wZ\n", FullImageName);
pDrvEntry=GetDriverEntryByImageBase(ImageInfo->ImageBase);
DbgPrint("[MyDriver]DriverEntry: %p\n",pDrvEntry);
UnicodeToChar(FullImageName,szFullImageName);
if(strstr(_strlwr(szFullImageName),"kevp64.sys"))
{
DbgPrint("[MyDriver]Deny load [WIN64AST.SYS]");
//禁止加载win64ast.sys
DenyLoadDriver(pDrvEntry);
}
}
}
}
加载:
PsSetLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)LoadImageNotifyRoutine);
注销:
PsRemoveLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)LoadImageNotifyRoutine);
执行结果,通过Pchunter看监控当前驱动信息,PowerTool驱动被拒绝加载之后不但自己没有提示,而且还在桌面上留下了自己的驱动文件,这相当于是你双击了一个exe,结果在exe入口函数的地方内存编程不可操作了,这种很难检测出问题来:
禁止加载驱动的方式也可以用来禁止加载dll。
Win64 驱动内核编程-13.回调监控模块加载的更多相关文章
- Win64 驱动内核编程-11.回调监控进线程句柄操作
无HOOK监控进线程句柄操作 在 NT5 平台下,要监控进线程句柄的操作. 通常要挂钩三个API:NtOpenProcess.NtOpenThread.NtDuplicateObject.但是在 VI ...
- Win64 驱动内核编程-14.回调监控文件
回调监控文件 使用 ObRegisterCallbacks 实现保护进程,其实稍微 PATCH 下内核,这个函数还能实现文件操作监视.但可惜只能在 WIN7X64 上用.因为在 WIN7X64 上 P ...
- Win64 驱动内核编程-15.回调监控注册表
回调监控注册表 在 WIN32 平台上,监控注册表的手段通常是 SSDT HOOK.不过用 SSDT HOOK 的方式监控注册表实在是太麻烦了,要 HOOK 一大堆函数,还要处理一些 NT6 系统有而 ...
- Win64 驱动内核编程-12.回调监控进线程创建和退出
回调监控进线程创建和退出 两个注册回调的函数:PsSetCreateProcessNotifyRoutine 进程回调PsSetCreateThreadNotifyRoutine 线程回调分 ...
- Win64 驱动内核编程-10.突破WIN7的PatchGuard
突破WIN7的PatchGuard WIN64 有两个内核保护机制,KPP 和 DSE.KPP 阻止我们 PATCH 内核,DSE 拦截我们加载驱动.当然 KPP 和 DSE 并不是不可战胜的,WIN ...
- Win64 驱动内核编程-2.基本框架(安装.通讯.HelloWorld)
驱动安装,通讯,Hello World 开发驱动的简单流程是这样,开发驱动安装程序,开发驱动程序,然后安装程序(或者其他程序)通过通讯给驱动传命令,驱动接到之后进行解析并且执行,然后把执行结果返回. ...
- Win64 驱动内核编程-32.枚举与删除注册表回调
枚举与删除注册表回调 注册表回调是一个监控注册表读写的回调,它的效果非常明显,一个回调能实现在SSDT 上 HOOK 十几个 API 的效果.部分游戏保护还会在注册表回调上做功夫,监控 service ...
- Win64 驱动内核编程-31.枚举与删除映像回调
枚举与删除映像回调 映像回调可以拦截 RING3 和 RING0 的映像加载.某些游戏保护会用此来拦截黑名单中的驱动加载,比如 XUETR.WIN64AST 的驱动.同理,在反游戏保护的过程中,也可以 ...
- Win64 驱动内核编程-23.Ring0 InLineHook 和UnHook
Ring0 InLineHook 和UnHook 如果是要在R0里hook,作者的建议是InLine HOOK,毕竟SSDT HOOK 和 SHADOW SSDT HOOK比较麻烦,不好修改.目前R3 ...
随机推荐
- SEO 在 SPA 站点中的实践
背景 观察基于 create-react-doc 搭建的文档站点, 发现网页代码光秃秃的一片(见下图).这显然是单页应用 (SPA) 站点的通病 -- 不利于文档被搜索引擎搜索 (SEO). 难道 S ...
- 完全使用 VSCode 开发的心得和体会
前言 我刚开始是一名 Java 程序员,陪伴我最久的老伙计是 Java 世界里面出名好用的是 Jetbrains 家族的重量级产品 Intelli IDEA 编辑器,不过 IDEA 主要是用来写代码, ...
- 从零开始编写一个BitTorrent下载器
从零开始编写一个BitTorrent下载器 BT协议 简介 BT协议Bit Torrent(BT)是一种通信协议,又是一种应用程序,广泛用于对等网络通信(P2P).曾经风靡一时,由于它引起了巨大的流量 ...
- redis雪崩,穿透,击穿
缓存雪崩:同一时间大量key到过期时间失效,可在设置失效时间时加随机数,如果直接修改数据库,那么一定会有不一致,通过失效时间去反复刷新缩短不一致的时间, 为了避免数据一直存在,一定要设置过期时间如果通 ...
- Qt添加注释模板
背景 软件:Qt Creator 在写代码的时候我们为了规范化,一般会加文件注释.类注释和函数注释 用注释来说明我们的代码,也方便模块化开发 那么我们在写注释的时候经常会写一些重复的内容,我们会复制粘 ...
- CODING 首届金融科技技术交流闭门会议顺利召开
近期,由腾讯云旗下一站式 DevOps 开发平台 CODING 和中国 DevOps 社区主办的深圳第十一届 Meetup 圆满结束,会上三位专家分享了自己独到的行业见解,腾讯云 CODING Dev ...
- SpringBoot项目war包部署
服务部署 记录原因 将本地SpringBoot项目通过war包部署到虚拟机中,验证服务器部署. 使用war包是为了方便替换配置文件等. 工具 对象 版本 Spring Boot 2.4.0 VMwar ...
- “改造” VS Code 编辑器,一起写个插件吧!
作者:HelloGitHub-小夏(首发于 HelloGitHub 公众号) 作为一个靠代码作为"生计"的开发者,bug 写的好不好,编辑器真的很重要!那么 Visual Stud ...
- 【笔记】《Redis设计与实现》chapter18 发布与订阅
chapter18 发布与订阅 客户端订阅频道. 客户端向频道发送消息, 消息被传递至各个订阅者. 匹配模式 客户端订阅模式. 客户端向频道发送消息, 消息被传递给正在订阅匹配模式的订阅者. 另一个模 ...
- 自动化kolla-ansible部署ubuntu20.04+openstack-victoria之镜像制作centos6.5-14
自动化kolla-ansible部署ubuntu20.04+openstack-victoria之镜像制作centos6.5-14 欢迎加QQ群:1026880196 进行交流学习 制作OpenSta ...