回调监控模块加载

模块加载包括用户层模块(.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.回调监控模块加载的更多相关文章

  1. Win64 驱动内核编程-11.回调监控进线程句柄操作

    无HOOK监控进线程句柄操作 在 NT5 平台下,要监控进线程句柄的操作. 通常要挂钩三个API:NtOpenProcess.NtOpenThread.NtDuplicateObject.但是在 VI ...

  2. Win64 驱动内核编程-14.回调监控文件

    回调监控文件 使用 ObRegisterCallbacks 实现保护进程,其实稍微 PATCH 下内核,这个函数还能实现文件操作监视.但可惜只能在 WIN7X64 上用.因为在 WIN7X64 上 P ...

  3. Win64 驱动内核编程-15.回调监控注册表

    回调监控注册表 在 WIN32 平台上,监控注册表的手段通常是 SSDT HOOK.不过用 SSDT HOOK 的方式监控注册表实在是太麻烦了,要 HOOK 一大堆函数,还要处理一些 NT6 系统有而 ...

  4. Win64 驱动内核编程-12.回调监控进线程创建和退出

    回调监控进线程创建和退出 两个注册回调的函数:PsSetCreateProcessNotifyRoutine   进程回调PsSetCreateThreadNotifyRoutine    线程回调分 ...

  5. Win64 驱动内核编程-10.突破WIN7的PatchGuard

    突破WIN7的PatchGuard WIN64 有两个内核保护机制,KPP 和 DSE.KPP 阻止我们 PATCH 内核,DSE 拦截我们加载驱动.当然 KPP 和 DSE 并不是不可战胜的,WIN ...

  6. Win64 驱动内核编程-2.基本框架(安装.通讯.HelloWorld)

    驱动安装,通讯,Hello World 开发驱动的简单流程是这样,开发驱动安装程序,开发驱动程序,然后安装程序(或者其他程序)通过通讯给驱动传命令,驱动接到之后进行解析并且执行,然后把执行结果返回. ...

  7. Win64 驱动内核编程-32.枚举与删除注册表回调

    枚举与删除注册表回调 注册表回调是一个监控注册表读写的回调,它的效果非常明显,一个回调能实现在SSDT 上 HOOK 十几个 API 的效果.部分游戏保护还会在注册表回调上做功夫,监控 service ...

  8. Win64 驱动内核编程-31.枚举与删除映像回调

    枚举与删除映像回调 映像回调可以拦截 RING3 和 RING0 的映像加载.某些游戏保护会用此来拦截黑名单中的驱动加载,比如 XUETR.WIN64AST 的驱动.同理,在反游戏保护的过程中,也可以 ...

  9. Win64 驱动内核编程-23.Ring0 InLineHook 和UnHook

    Ring0 InLineHook 和UnHook 如果是要在R0里hook,作者的建议是InLine HOOK,毕竟SSDT HOOK 和 SHADOW SSDT HOOK比较麻烦,不好修改.目前R3 ...

随机推荐

  1. 关于ORACLE数据库跨库调用序列的解决办法

    问题  ORACLE  数据库   用户1   xscg  有序列      seq_S_ATTACHMENT_INFO.nextval         我要在  用户2   xsds   里面调用 ...

  2. 【Git】敏感信息保护

    保护Git仓库敏感信息 代码中无可避免有一些敏感信息,包含但不限于,数据库信息,密钥,账号信息等等.通常我们会把这些信息放在配置文件,这些信息若泄露会造成安全问题. 以前我们做法,是把配置文件通过.g ...

  3. Activiti工作流学习笔记(三)——自动生成28张数据库表的底层原理分析

    原创/朱季谦 我接触工作流引擎Activiti已有两年之久,但一直都只限于熟悉其各类API的使用,对底层的实现,则存在较大的盲区. Activiti这个开源框架在设计上,其实存在不少值得学习和思考的地 ...

  4. 在swoole中制作一款仿制laravel的框架

    首先需要确定一下思路:我希望基于swoole的扩展开发的代码在run起来的时候,在接收到ws或是tcp等消息时,自动路由到某个类上,同时类可以实现加载类的依赖注入功能.目前市面上占据主流的一款框架La ...

  5. 攻防世界 reverse Guess-the-Number

    Guess-the-Number  su-ctf-quals-2014 使用jd-gui 反编译jar import java.math.BigInteger; public class guess ...

  6. java例题_37 有 n 个人围成一圈,顺序排号。从第一个人开始报数(从 1 到 3 报数),凡报到 3 的人退出圈子, 3 问最后留下的是原来第几号的那位。

    1 /*37 [程序 37 报数] 2 题目:有 n 个人围成一圈,顺序排号.从第一个人开始报数(从 1 到 3 报数),凡报到 3 的人退出圈子, 3 问最后留下的是原来第几号的那位. 4 */ 5 ...

  7. 一文带大家彻底搞懂Hystrix!

    前言? Netflix Hystrix断路器是什么? Netflix Hystrix是SOA/微服务架构中提供服务隔离.熔断.降级机制的工具/框架.Netflix Hystrix是断路器的一种实现,用 ...

  8. 强大的 Guava 工具类

    Java 开发的同学应该都使用或者听说过 Google 提供的 Guava 工具包.日常使用最多的肯定是集合相关的工具类,还有 Guava cache,除了这些之外 Guava 还提供了很多有用的功能 ...

  9. 电梯也能无为而治——oo第二单元作业总结

    oo第二单元作业总结 一.设计策略与质量分析 第一次作业 设计策略 在第一次作业之前,我首先确定了生产者--消费者模式的大体架构,即由输入线程(可与主线程合并)充当生产者,电梯线程充当消费者,二者不直 ...

  10. Java(265-278)【Map】

    1.Map集合概述 是一个接口 键是唯一的 java.util.Map<k,v>集合 Map集合的特点:      1.Map集合是一个双列集合,一个元素包含两个值(一个key,一个val ...