【我的】文件系统微过滤驱动Minifilter——获取进程信息
作者:zcr214 时间:2016/4/22
在编写文件系统微过滤驱动minifilter的时候,除了绑定指定的磁盘分卷,对于指定的文件很可能还会有指定的应用程序,例如txt文件可以有很多编辑器可以使用,如wordpad,notepad,sublime,vim,notepad+等,doc文档可以使用office word或WPS,图片文件就更多了。虽然仅靠过滤进程名来筛选出指定程序的方式不太安全,黑客可以通过伪装进程名的方式绕过,但是获取进程信息(进程ID,进程名等)对于minifilter驱动所需的基本功能的开发有着重要的作用。
可以使用PsSetCreateProcessNotifyRoutine()来设置一个通知回调函数。每当操作系统创建或者关闭一个进程的时候,回调都会被调用。
NTSTATUS
PsSetCreateProcessNotifyRoutine(
_In_PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,
_In_BOOLEAN Remove );
返回状态值,表示设置通知回调是否成功,参数中包含一个设置的通知回调函数的指针和是否移除的标记,移除标记设为false表示设置通知回调,true表示卸载通知回调,当驱动启动时在DriverEntry中需要设置通知回调,驱动停止时当然也要在FilterUnload中卸载这个通知回调。
通知回调函数的原型为:
VOID
(*PCREATE_PROCESS_NOTIFY_ROUTINE)(
_In_HANDLE ParentId,
_In_HANDLE ProcessId,
_In_BOOLEAN Create );
显而易见的,可以在通知回调函数中获取到这个进程的ID和父进程ID,以及创建或关闭的标记。
可以使用PsSetLoadImageNotifyRoutine()设置一个通知回调函数,每当操作系统新加载一个映像文件的时候,设置的回调函数就会被调用。
PsSetLoadImageNotifyRoutine()函数原型如下:
NTSTATUS
PsSetLoadImageNotifyRoutine(
_In_PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine
);
返回一个状态值,表示设置通知回调函数是否成功,参数只有一个,即通知回调函数的指针。在驱动启动时在DriverEntry设置通知回调,驱动停止时也需要在FilterUnload中卸载通知回调,使用另一个相对应的函数PsRemoveLoadImageNotifyRoutine(),函数原型和Set函数类似。
加载映像的通知回调函数的原型如下:
VOID
(*PLOAD_IMAGE_NOTIFY_ROUTINE)(
_In_PUNICODE_STRING FullImageName,
_In_HANDLE ProcessId,// pid into which image is being mapped
_In_PIMAGE_INFO ImageInfo
);
显而易见的,可以在通知回调函数中得到完整的映像名称,进程ID,和其他的映像相关信息。
(1) DriverEntry中,启动过滤之前,设置通知回调。
//启动获取进程,映像信息的回调
PsSetCreateProcessNotifyRoutine(ProcessNotify,FALSE);
PsSetLoadImageNotifyRoutine(LoadImageNotify);
// Start filtering i/o
(2) FilterUnload中,停止过滤之前,取消通知回调。
// 驱动关闭,移除进程和映像信息获取的回调
PsSetCreateProcessNotifyRoutine(ProcessNotify,TRUE);
PsRemoveLoadImageNotifyRoutine(LoadImageNotify);
// Unregister from FLT mgr
(3) 编写进程通知回调函数,打印进程信息。
VOID
ProcessNotify(
INHANDLE ParentId,
INHANDLE ProcessId,
INBOOLEAN Create)
{
DbgPrint("FilterProcessNotify,pid: %d, tid: %d, create: %d\n",ParentId,ProcessId,Create);
}
(4) 编写映像通知回调函数,保存进程ID和映像名称信息(这里事先已经定义了一个全局的ProcessList数组用于保存映像名)。
VOID
LoadImageNotify(
__in_optPUNICODE_STRINGFullImageName,
__inHANDLEProcessId,
__inPIMAGE_INFOImageInfo)
{
UNREFERENCED_PARAMETER(ImageInfo);
__try{
ProcessList[(int)ProcessId]=FullImageName;
DbgPrint("image name :%wZ pid is:%d",ProcessList[(int)ProcessId],ProcessId);
}
__except(EXCEPTION_EXECUTE_HANDLER){
DbgPrint("pid:%d,cannot insert to ProcessList",ProcessId);
}
}
当然上述的保存方法相对简单,在具体应用中应该视具体的需求而定,也可自定义一个表,将所有进程信息都保存起来,需要检查的时候再利用进程ID将具体信息取出来。