编写进程/线程监视器

本文详细介绍了如何使用NTDDK手册中的PsSetCreateProcessNotifyRoutine(), PsSetCreateThreadNotifyRoutine()等函数,实现动态监视NT系统中任意进程/线程的创建与销毁,并通过未公开函数PsLookupProcessByProcessId()获取进程名,以及动态监视进程装载映像,提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Author : sinister
Email : sinister@whitecell.org
HomePage: http://www.whitecell.org

(首先说明一下。有不少朋友来信问一些进程/线程监视工具是如何实现的。
我写出来是为了让那些朋友有进一步的了解,也省的我一封封的回MAIL。如果您
是 NT DRIVER熟手,那么此文提到的方法您可能早已掌握,完全可以略过不看。)

有时候我们希望能够动态监视系统中任意进程/线程的创建与销毁。为了达
到此目的我翻阅了 DDK 手册,发现其提供的 PsSetCreateProcessNotifyRoutine(),
PsSetCreateThreadNotifyRoutine(),等函数可以实现此功能。这两个函数可以

通过向系统注册一个 CALLBALCK 函数来监视进程/线程等操作。函数原形如下:

NTSTATUS
    PsSetCreateProcessNotifyRoutine(
    IN PCREATE_PROCESS_NOTIFY_ROUTINE   NotifyRoutine,
    IN BOOLEAN   Remove
    );

 VOID
 (*PCREATE_PROCESS_NOTIFY_ROUTINE) (
      IN HANDLE   ParentId,
      IN HANDLE   ProcessId,
      IN BOOLEAN   Create
      );


 NTSTATUS
    PsSetCreateThreadNotifyRoutine(
    IN PCREATE_THREAD_NOTIFY_ROUTINE   NotifyRoutine
    );

 VOID
 (*PCREATE_THREAD_NOTIFY_ROUTINE) (
      IN HANDLE   ProcessId,
      IN HANDLE   ThreadId,
      IN BOOLEAN   Create
      );
通过原形可以看出,其 CALLBACK 函数只提供了进程ID/线程ID。并没有提供
进程名。那么我们要进一步通过进程ID来获取进程名。这需要用到一个未公开
的函数 PsLookupProcessByProcessId()。函数原形如下:

NTSTATUS PsLookupProcessByProcessId(
       IN ULONG ulProcId, 
       OUT PEPROCESS * pEProcess
       );

函数输出的 EPROCESS 结构也是未公开的内核进程结构,很多人称其为 KPEB。
EPROCESS 结构中的偏移 0x1FC 指向当前进程名的偏移。(这个结构虽然可以在
驱动程序中直接使用。但没有公布其结构,网上有不少高手已将其结构给出。有
兴趣可以自行搜索,或去 IFS DDK 中获取,这里因为结构太长,就不贴出来了)
有了这个结构我们就可以从中得到进程名。NT系统还提供了一个函数可以动态监
视进程装载映像。此函数可以得到进程加栽时所调用的 DLL 名称与全路径,还有
一些映像信息。为我们获得更详细的进程装载信息提供了更好的帮助。

函数原形如下:

NTSTATUS
    PsSetLoadImageNotifyRoutine(
    IN PLOAD_IMAGE_NOTIFY_ROUTINE   NotifyRoutine
    );

 VOID
 (*PLOAD_IMAGE_NOTIFY_ROUTINE) (
      IN PUNICODE_STRING   FullImageName,
      IN HANDLE   ProcessId, // where image is mapped
      IN PIMAGE_INFO   ImageInfo
      );

 typedef struct   _IMAGE_INFO {
      union {
          ULONG   Properties;
          struct {
              ULONG ImageAddressingMode   : 8; //code addressing mode
              ULONG SystemModeImage       : 1; //system mode image
              ULONG ImageMappedToAllPids : 1; //mapped in all processes
              ULONG Reserved              : 22;
          };
      };
      PVOID   ImageBase;
      ULONG   ImageSelector;
      ULONG   ImageSize;
      ULONG   ImageSectionNumber;
 } IMAGE_INFO, *PIMAGE_INFO;
利用以上提供的函数与结构,我们便能实现一个进程/线程监视器。下面这段
代码演示了如何实现此功能。

/*****************************************************************
 文件名         : WssProcMon.c
 描述           : 进程/线程监视器
 作者           : sinister
 最后修改日期   : 2002-11-02

 *****************************************************************/

 #include "ntddk.h"
 #include "string.h"

 #define ProcessNameOffset   0x1fc

 static NTSTATUS   MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
 NTSTATUS PsLookupProcessByProcessId(IN ULONG ulProcId, OUT PEPROCESS * pEProcess);
 VOID ProcessCreateMon ( IN HANDLE   hParentId, IN HANDLE PId,IN BOOLEAN bCreate);
 VOID ThreadCreateMon (IN HANDLE   PId, IN HANDLE TId, IN BOOLEAN   bCreate);
 VOID ImageCreateMon (IN PUNICODE_STRING   FullImageName, IN HANDLE   ProcessId, IN PIMAGE_INFO   ImageInfo );


 // 驱动入口
 NTSTATUS   DriverEntry( IN PDRIVER_OBJECT DriverObject,   IN PUNICODE_STRING RegistryPath ) 
 {
     
      UNICODE_STRING   nameString, linkString;
      PDEVICE_OBJECT   deviceObject;
      NTSTATUS         status;
      int                 i;
     

      //建立设备
      RtlInitUnicodeString( &nameString, L"\\Device\\WssProcMon" );
     
      status = IoCreateDevice( DriverObject,
                               0,
                               &nameString,
                               FILE_DEVICE_UNKNOWN,
                               0,
                               TRUE,
                               &deviceObject
                             );
                            

      if (!NT_SUCCESS( status ))
          return status;
     

      RtlInitUnicodeString( &linkString, L"\\DosDevices\\WssProcMon" );

      status = IoCreateSymbolicLink (&linkString, &nameString);

      if (!NT_SUCCESS( status ))
      {
          IoDeleteDevice (DriverObject->DeviceObject);
          return status;
      }    
     
      status = PsSetLoadImageNotifyRoutine(ImageCreateMon);
      if (!NT_SUCCESS( status ))
      {
          DbgPrint("PsSetLoadImageNotifyRoutine()\n");
          return status;
      }    

      status = PsSetCreateThreadNotifyRoutine(ThreadCreateMon);
      if (!NT_SUCCESS( status ))
      {
          DbgPrint("PsSetCreateThreadNotifyRoutine()\n");
          return status;
      }    

      status = PsSetCreateProcessNotifyRoutine(ProcessCreateMon, FALSE);
      if (!NT_SUCCESS( status ))
      {
          DbgPrint("PsSetCreateProcessNotifyRoutine()\n");
          return status;
      }    
     

      for ( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)     {

            DriverObject->MajorFunction[i] = MydrvDispatch;
      }
      
    return STATUS_SUCCESS; 

 } 



 //处理设备对象操作

 static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
 { 
      Irp->IoStatus.Status = STATUS_SUCCESS;
      Irp->IoStatus.Information = 0L;
      IoCompleteRequest( Irp, 0 );
      return Irp->IoStatus.Status;
     
 }


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

      PEPROCESS   EProcess;
      ULONG       ulCurrentProcessId;
      LPTSTR        lpCurProc;
      NTSTATUS    status;

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

      if ( bCreate )
      {
            lpCurProc = (LPTSTR)EProcess;
          lpCurProc = lpCurProc + ProcessNameOffset;

          DbgPrint( "CREATE PROCESS = PROCESS NAME: %s , PROCESS PARENTID: %d, PROCESS ID: %d, PROCESS ADDRESS %x:\n", 
                                lpCurProc,
                                hParentId,
                                PId,
                                EProcess );
      }
      
      else
      {

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

      }

 }

 VOID ThreadCreateMon (IN HANDLE PId, IN HANDLE TId, IN BOOLEAN   bCreate)
 {

      PEPROCESS    EProcess;
      ULONG         ulCurrentProcessId;
      LPTSTR         lpCurProc;
      NTSTATUS     status;

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

      if ( bCreate )
      {
            lpCurProc     = (LPTSTR)EProcess;
          lpCurProc     = lpCurProc + ProcessNameOffset;

          DbgPrint( "CREATE THREAD = PROCESS NAME: %s PROCESS ID: %d, THREAD ID: %d\n", lpCurProc, PId, TId );
                               
      }
      
      else
      {

          DbgPrint( "TERMINATED == THREAD ID: %d\n", TId);

      }

 }

 VOID ImageCreateMon (IN PUNICODE_STRING   FullImageName, IN HANDLE   ProcessId, IN PIMAGE_INFO   ImageInfo )
 {
      DbgPrint("FullImageName: %S,Process ID: %d\n",FullImageName->Buffer,ProcessId);
      DbgPrint("ImageBase: %x,ImageSize: %d\n",ImageInfo->ImageBase,ImageInfo->ImageSize);

 }



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值