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 DbgPrintBOOLEAN 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 ...
最新文章
- 怎么看懂别人写的单片机项目代码?
- DeepStream开发日志
- java中skip的用法,Java PushbackReader skip(long)用法及代码示例
- Java正则表达式匹配、替换HTML内容
- SAP CRM产品主数据应用里value node和model node的转换
- jquery 获取鼠标和元素的坐标点
- linux开发板 杭州迈冲,杭州迈冲科技MC9G20-DK评估开发板
- php+apache 和 php+nginx的区别
- 怎么禁用计算机的可信执行,英特尔®融合安全和管理引擎、英特尔®服务器平台服务、英特尔®可信执行引擎和英特尔®主动管理技术咨询 (intela-sa-00185)...
- 提升访问github.com网址的速度
- doc88、道客巴巴 文库文档下载
- maven插件安装与使用
- 虚拟机共享服务器设置,虚拟机共享网络设置教程
- SPN线性密码分析【附code】
- CF446C DZY Loves Fibonacci Numbers 万能的线段树
- 二级页表如何节省内存
- Android 支付宝 resultStatus=4000, result=, memo=系统繁忙,请稍后再试
- 泰科 | 高压连接革命!CSJ高压连接器与您共赢电动汽车新时代
- 修改sep客户端服务器地址,SEP服务更改IP地址操作手册
- oracle10G 数据泵技术
热门文章
- 搭建 LNMP 环境
- SpringMVC 类扫描原理解析
- 将Mongodb部分数据导入mysql数据库
- enum类型被intent所携带时需要注意的地方
- 栈(Stack) 任何程序执行前,预先分配一固定长度的内存空间
- 键盘控制事件应用教程大全
- 解决vuex页面刷新导致数据丢失问题
- Makefile:160: recipe for target 'all' failed (Ubuntu 16.06 + Opencv3.2)解决办法
- 红黑树(一)之 原理和算法详细介绍---转帖
- linux下使用DBCA(database configuration assistant)创建oracle数据库