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 #include #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.sysDenyLoadDriver(pDrvEntry);}}}} 加载:PsSetLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)LoadImageNotifyRoutine);注销:PsRemoveLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)LoadImageNotifyRoutine);
执行结果,通过Pchunter看监控当前驱动信息,PowerTool驱动被拒绝加载之后不但自己没有提示,而且还在桌面上留下了自己的驱动文件,这相当于是你双击了一个exe,结果在exe入口函数的地方内存编程不可操作了,这种很难检测出问题来:
禁止加载驱动的方式也可以用来禁止加载dll。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
暂时没有评论,来抢沙发吧~