首页
社区
课程
招聘
[原创]监控进程的启动的一种方法利用
发表于: 2009-12-3 16:17 16410

[原创]监控进程的启动的一种方法利用

2009-12-3 16:17
16410

想监控进程,有好几种方式,有Hook NTCreatProcess,但是有很多进程并不是通过NTCreatProcess创建,还有hook NTCreatSection等。但是我想介绍的就是利用到的函数PsSetCreateProcessNotifyRoutine,这是一个回调函数,当就进程创建和销毁时,就会告诉这个函数那,这里就不多介绍其函数原型。但是它的参数会传入父进程的ID,进程的ID和是否创建。
   所以我设置一个结构用来保存以上参数的值,并且将该结构传给应用层显示出来。
   typedef struct _CallbackInfo
   {
       HANDLE  hParentId;
       HANDLE  hProcessId;
       CHAR    ProcFullPath[256];          //进程路径
       BOOLEAN bCreate;
   }CALLBACK_INFO, *PCALLBACK_INFO;
其中ProcFullPath用来保存进程的完整路径。还需要定义一个为设备扩展结构如下
struct _DEVICE_EXTENSION
{
    HANDLE             hProcessHandle;        // 事件对象句柄
    PKEVENT            ProcessEvent;          // 用户和内核通信的事件对象指针
    HANDLE             hParentId;             // 在回调函数中保存进程信息
    HANDLE             hProcessId;
    PCHAR              ProcFullPath;         //进程路径
        BOOLEAN            bCreate;
}DEVICE_EXTENSION, *PDEVICE_EXTENSION;
这是驱动设备留给用户自己可以定义的结构,这个结构用来保存回调函数的信息。主要代码如下

// 驱动入口
NTSTATUS  DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath )
{
    UNICODE_STRING  nameString, linkString,ProcessEventString;
        PDEVICE_OBJECT      deviceObject;
    PDEVICE_EXTENSION        deviceExtension;
        NTSTATUS            status;
        IO_STATUS_BLOCK     ioStatus;
        PIRP                                pIrp;
    int                 i;
   
        status=STATUS_SUCCESS;
    DriverObject->MajorFunction[IRP_MJ_CREATE]=DispatchCreate;   
    DriverObject->MajorFunction[IRP_MJ_CLOSE]=DispatchClose;
        DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=DispatchIoctl;   
    DriverObject->DriverUnload=DriverUnload;  

    //建立设备
    RtlInitUnicodeString(&nameString,L"\\Device\\WssProcMon");
    // 创建设备对象
   
        status=IoCreateDevice(DriverObject,
                             sizeof(DEVICE_EXTENSION), // 为设备扩展结构申请空间
                             &nameString,
                             FILE_DEVICE_UNKNOWN,
                             0,
                             FALSE,
                             &deviceObject);
                                                
    if (!NT_SUCCESS(status))
        { return status;
        }
   
    deviceExtension=(PDEVICE_EXTENSION)deviceObject->DeviceExtension;

    RtlInitUnicodeString(&linkString,L"\\DosDevices\\WssProcMon");
    status = IoCreateSymbolicLink (&linkString, &nameString);

    if (!NT_SUCCESS(status))
    {
        //删除上面的设备对象
                IoDeleteDevice(deviceObject);
        return status;
    }
  

           
   //保存到设备对象的指针,下面在进程回调函数中还要使用
    g_pDriverObject=deviceObject;

    RtlInitUnicodeString(&ProcessEventString,EVENT_NAME);  
        //这里是创建事件对象用来与应用层交流
        deviceExtension->ProcessEvent=IoCreateNotificationEvent(&ProcessEventString,&deviceExtension->hProcessHandle);
    这里需要说明一下事件的作用,是为了达到两个对象同步,其实达到互斥还可以利用信号灯、互斥体,首先设置为非受信状态,这里注意事件对象只有两种状态:非受信和受信状态,非受信状态指的是没激活,受信状态指的是激活,也就是说建立事件对象后,先不激活,当有进程创建时,就激活,激活的话,由于应用层一直打开这个事件对象,并且用WaitForSingleObject一直等待,直到有事件激活,它在返回给内核,然后内核有设置为非受信状态。
        //设置为非受信状态
        KeClearEvent(deviceExtension->ProcessEvent);
    //设置回调例程
    status = PsSetCreateProcessNotifyRoutine(ProcessCreateMon,FALSE);

    if (!NT_SUCCESS(status))
    {
        DbgPrint("PsSetCreateProcessNotifyRoutine()\n");
        return status;
    }   
   
   return status;
}

//处理设备对象操作
NTSTATUS DispatchCreate(IN PDEVICE_OBJECT DeviceObject,IN PIRP         Irp)
{
  DbgPrint("IRP_MJ_Create\n");

  Irp->IoStatus.Information=0;
  Irp->IoStatus.Status=STATUS_SUCCESS;
  IoCompleteRequest(Irp,IO_NO_INCREMENT);
  return STATUS_SUCCESS;
}

这里省略(.......)

// I/O控制派遣例程
NTSTATUS DispatchIoctl(IN PDEVICE_OBJECT DeviceObject,IN PIRP        Irp)
{
  PDEVICE_EXTENSION  deviceExtension;
  ULONG IoControlCode,InBufLength,outBufLength;
  PCALLBACK_INFO pCallbackInfo;

  NTSTATUS status=STATUS_INVALID_DEVICE_REQUEST;

  // 取得此IRP(pIrp)的I/O堆栈指针
   PIO_STACK_LOCATION  irpStack = IoGetCurrentIrpStackLocation(Irp);
// 取得设备扩展结构指针
  deviceExtension=(PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
                                       
  // 取得I/O控制代码
  IoControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
  pCallbackInfo=(PCALLBACK_INFO)Irp->AssociatedIrp.SystemBuffer;
  InBufLength  =irpStack->Parameters.DeviceIoControl.InputBufferLength;
  outBufLength =irpStack->Parameters.DeviceIoControl.OutputBufferLength;

  switch(IoControlCode)
  {
   case IOCTL_NTPROCDRV_GET_PROCINFO:
           {
         KdPrint(("[ProcMon] IOCTL: 0x%X", IoControlCode));
       if(outBufLength>=sizeof(CALLBACK_INFO))
           {
        pCallbackInfo->hParentId   = deviceExtension->hParentId;
        pCallbackInfo->hProcessId  = deviceExtension->hProcessId;
                strcpy(pCallbackInfo->ProcFullPath,deviceExtension->ProcFullPath);
                pCallbackInfo->bCreate     = deviceExtension->bCreate;
                status=STATUS_SUCCESS;
           }
      
           }
     break;
  }
  /*这里如果直接将Irp->IoStatus.Information=0,那么ring3就读不出CallbackInfo结构体的值,也就是如果收到IOCTL_NTPROCDRV_GET_PROCINFO
  必须设置Irp->IoStatus.Information=outBufLength的大小*/

  if(status==STATUS_SUCCESS)
        Irp->IoStatus.Information=outBufLength;
   else
    Irp->IoStatus.Information=0;
  
  //必须完成i/0回复
  Irp->IoStatus.Status=status;
  IoCompleteRequest(Irp,IO_NO_INCREMENT);
  return status;
}

VOID ProcessCreateMon(IN HANDLE hParentId,IN HANDLE PId,IN BOOLEAN bCreate)
{

    PEPROCESS    EProcess;
    ULONG        ulCurrentProcessId;
    LPTSTR       lpCurProc; //进程名
    NTSTATUS     status;
        PDEVICE_EXTENSION        deviceExtension;
        HANDLE hProcess=NULL;
    ANSI_STRING pImageName;
    PCHAR outbuf;
        ULONG outlen;
   

    status = PsLookupProcessByProcessId((ULONG)PId, &EProcess);
    if (!NT_SUCCESS( status ))
    {
        DbgPrint("PsLookupProcessByProcessId()\n");
        return;
    }
   

    if ( bCreate )
    {
          lpCurProc = (LPTSTR)EProcess;
          lpCurProc = lpCurProc + ProcessNameOffset;
         
      RtlInitAnsiString(&pImageName,"test");
          GetProcPath(PId,&pImageName);
       
          outbuf=(PCHAR)pImageName.Buffer;
      outlen=pImageName.Length+1;

   
        // 得到设备扩展结构的指针
    deviceExtension=(PDEVICE_EXTENSION)g_pDriverObject->DeviceExtension;
   
        // 安排当前值到设备扩展结构
    // 用户模式应用程序将使用DeviceIoControl调用把它取出
    deviceExtension->hParentId=hParentId;
    deviceExtension->hProcessId=PId;
    deviceExtension->ProcFullPath=(PCHAR)outbuf;
        deviceExtension->bCreate=bCreate;   
        //触发事件,通知应用程序
        // 用户模式下的应用程序不能重置KM事件,所以我们要在这里触发它
        KeSetEvent(deviceExtension->ProcessEvent,0,FALSE);
    KeClearEvent(deviceExtension->ProcessEvent);
   

        DbgPrint( "CREATE PROCESS = PROCESS NAME: %s , PROCESS PARENTID: %d, PROCESS ID: %d, PROCESS ADDRESS %x:\n",
                              deviceExtension->ProcFullPath,
                              deviceExtension->hParentId,
                              deviceExtension->hProcessId,
                              EProcess);
       
        //DbgPrint("[ProcMon] IOCTL: 0x%X", IOCTL_NTPROCDRV_GET_PROCINFO);
       
        }
     
    else
    {

        DbgPrint( "TERMINATED == PROCESS ID: %d\n", PId);

    }

}

先运行加载驱动,在运行应用程序


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (16)
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
2
好厉害,学习了
2009-12-3 16:19
0
雪    币: 300
活跃值: (2477)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
比较适合我,标记一下。顶lz
2009-12-3 17:21
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
5
看我的DIY无限多开版 ~  http://bbs.pediy.com/showthread.php?t=80109
2009-12-3 17:34
0
雪    币: 1312
活跃值: (5164)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
好厉害!!!
2009-12-3 19:38
0
雪    币: 379
活跃值: (152)
能力值: ( LV12,RANK:330 )
在线值:
发帖
回帖
粉丝
7
早期写的,一点体会吧,没有太深奥的技术,交流交流
2009-12-3 19:57
0
雪    币: 622
活跃值: (65)
能力值: ( LV13,RANK:290 )
在线值:
发帖
回帖
粉丝
8
挺好的,从简单到复杂慢慢来,不过对于驱动我只玩过简单的,最后因为工作所以心思就不在这上边了,多少有点遗憾吧。
多一点坚持的确很重要,尤其对于自己喜欢的东西。
2009-12-4 11:05
0
雪    币: 224
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
这样做貌似不能够在进程起来之前直接拦截掉
2009-12-4 15:59
0
雪    币: 70
活跃值: (74)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
没有时间深入做自己喜欢的驱动,很遗憾
2009-12-4 16:06
0
雪    币: 351
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
正在努力中。。。
2009-12-5 22:46
0
雪    币: 102
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
无语.
我是想学习驱动.
2009-12-23 00:24
0
雪    币: 246
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
不是 虽然我不是搞驱动的,但是我感觉你的这个方法是从网上荡的吧,看雪上有的是啊
2009-12-25 16:16
0
雪    币: 379
活跃值: (152)
能力值: ( LV12,RANK:330 )
在线值:
发帖
回帖
粉丝
14
誰都是站在巨人的肩膀,我承认我参考了部分代码,但是里面也有我自己的学习和一些改进,你不懂可以不看,但是我看你根本不懂编程吧!
2009-12-27 16:50
0
雪    币: 492
活跃值: (53)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
15
请问可以在进程起来之前把这个进程拦截掉吗?
2010-1-12 17:08
0
雪    币: 109
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
16
先记下来。学习键盘过滤之后再看这文章。
2010-1-12 17:19
0
雪    币: 750
活跃值: (228)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
17
它的参数会传入父进程的ID,进程的ID和是否创建
2010-1-14 02:49
0
雪    币: 492
活跃值: (53)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
18
[QUOTE=非安全;745359]它的参数会传入父进程的ID,进程的ID和是否创建。[/QUOTE]

确实可以监控是创建进程还是结束进程,
不过不是用来阻止进程的创建的吧?
2010-1-14 10:01
0
游客
登录 | 注册 方可回帖
返回
//