现在的位置: 首页 > 综合 > 正文

编写进程/线程监视器

2013年09月29日 ⁄ 综合 ⁄ 共 8145字 ⁄ 字号 评论关闭

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

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

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

The  code:
  1. NTSTATUS   
  2.   PsSetCreateProcessNotifyRoutine(   
  3.   IN PCREATE_PROCESS_NOTIFY_ROUTINE  NotifyRoutine,   
  4.   IN BOOLEAN  Remove   
  5.   );   
  6.   
  7. VOID   
  8. (*PCREATE_PROCESS_NOTIFY_ROUTINE) (   
  9.     IN HANDLE  ParentId,   
  10.     IN HANDLE  ProcessId,   
  11.     IN BOOLEAN  Create   
  12.     );   
  13.   
  14.   
  15. NTSTATUS   
  16.   PsSetCreateThreadNotifyRoutine(   
  17.   IN PCREATE_THREAD_NOTIFY_ROUTINE  NotifyRoutine   
  18.   );   
  19.   
  20. VOID   
  21. (*PCREATE_THREAD_NOTIFY_ROUTINE) (   
  22.     IN HANDLE  ProcessId,   
  23.     IN HANDLE  ThreadId,   
  24.     IN BOOLEAN  Create   
  25.     );  

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

The  code:
  1. NTSTATUS PsLookupProcessByProcessId(   
  2.      IN ULONG ulProcId,    
  3.      OUT PEPROCESS * pEProcess   
  4.      );  

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

函数原形如下:

The  code:
  1. NTSTATUS   
  2.   PsSetLoadImageNotifyRoutine(   
  3.   IN PLOAD_IMAGE_NOTIFY_ROUTINE  NotifyRoutine   
  4.   );   
  5.   
  6. VOID   
  7. (*PLOAD_IMAGE_NOTIFY_ROUTINE) (   
  8.     IN PUNICODE_STRING  FullImageName,   
  9.     IN HANDLE  ProcessId, // where image is mapped   
  10.     IN PIMAGE_INFO  ImageInfo   
  11.     );   
  12.   
  13. typedef struct  _IMAGE_INFO {   
  14.     union {   
  15.         ULONG  Properties;   
  16.         struct {   
  17.             ULONG ImageAddressingMode  : 8; //code addressing mode   
  18.             ULONG SystemModeImage      : 1; //system mode image   
  19.             ULONG ImageMappedToAllPids : 1; //mapped in all processes   
  20.             ULONG Reserved             : 22;   
  21.         };   
  22.     };   
  23.     PVOID  ImageBase;   
  24.     ULONG  ImageSelector;   
  25.     ULONG  ImageSize;   
  26.     ULONG  ImageSectionNumber;   
  27. } IMAGE_INFO, *PIMAGE_INFO;  

利用以上提供的函数与结构,我们便能实现一个进程/线程监视器。下面这段
代码演示了如何实现此功能。

The  code:
  1. /*****************************************************************   
  2. 文件名        : WssProcMon.c   
  3. 描述          : 进程/线程监视器   
  4. 作者          : sinister   
  5. 最后修改日期  : 2002-11-02   
  6.   
  7. *****************************************************************/   
  8.   
  9. #include "ntddk.h"  
  10. #include "string.h"  
  11.   
  12. #define ProcessNameOffset  0x1fc   
  13.   
  14. static NTSTATUS  MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);   
  15. NTSTATUS PsLookupProcessByProcessId(IN ULONG ulProcId, OUT PEPROCESS * pEProcess);   
  16. VOID ProcessCreateMon ( IN HANDLE  hParentId, IN HANDLE PId,IN BOOLEAN bCreate);   
  17. VOID ThreadCreateMon (IN HANDLE  PId, IN HANDLE TId, IN BOOLEAN  bCreate);   
  18. VOID ImageCreateMon (IN PUNICODE_STRING  FullImageName, IN HANDLE  ProcessId, IN PIMAGE_INFO  ImageInfo );   
  19.   
  20.   
  21. // 驱动入口   
  22. NTSTATUS  DriverEntry( IN PDRIVER_OBJECT DriverObject,  IN PUNICODE_STRING RegistryPath )    
  23. {   
  24.        
  25.     UNICODE_STRING  nameString, linkString;   
  26.     PDEVICE_OBJECT  deviceObject;   
  27.     NTSTATUS        status;   
  28.     int                i;   
  29.        
  30.   
  31.     //建立设备   
  32.     RtlInitUnicodeString( &nameString, L"//Device//WssProcMon" );   
  33.        
  34.     status = IoCreateDevice( DriverObject,   
  35.                              0,   
  36.                              &nameString,   
  37.                              FILE_DEVICE_UNKNOWN,   
  38.                              0,   
  39.                              TRUE,   
  40.                              &deviceObject   
  41.                            );   
  42.                               
  43.   
  44.     if (!NT_SUCCESS( status ))   
  45.         return status;   
  46.        
  47.   
  48.     RtlInitUnicodeString( &linkString, L"//DosDevices//WssProcMon" );   
  49.   
  50.     status = IoCreateSymbolicLink (&linkString, &nameString);   
  51.   
  52.     if (!NT_SUCCESS( status ))   
  53.     {   
  54.         IoDeleteDevice (DriverObject->DeviceObject);   
  55.         return status;   
  56.     }       
  57.        
  58.     status = PsSetLoadImageNotifyRoutine(ImageCreateMon);   
  59.     if (!NT_SUCCESS( status ))   
  60.     {   
  61.         DbgPrint("PsSetLoadImageNotifyRoutine()/n");   
  62.         return status;   
  63.     }       
  64.   
  65.     status = PsSetCreateThreadNotifyRoutine(ThreadCreateMon);   
  66.     if (!NT_SUCCESS( status ))   
  67.     {   
  68.         DbgPrint("PsSetCreateThreadNotifyRoutine()/n");   
  69.         return status;   
  70.     }       
  71.   
  72.     status = PsSetCreateProcessNotifyRoutine(ProcessCreateMon, FALSE);   
  73.     if (!NT_SUCCESS( status ))   
  74.     {   
  75.         DbgPrint("PsSetCreateProcessNotifyRoutine()/n");   
  76.         return status;   
  77.     }       
  78.        
  79.   
  80.     for ( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)    {   
  81.   
  82.           DriverObject->MajorFunction[i] = MydrvDispatch;   
  83.     }   
  84.         
  85.   return STATUS_SUCCESS;    
  86.   
  87. }    
  88.   
  89.   
  90.   
  91. //处理设备对象操作   
  92.   
  93. static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)   
  94. {    
  95.     Irp->IoStatus.Status = STATUS_SUCCESS;   
  96.     Irp->IoStatus.Information = 0L;   
  97.     IoCompleteRequest( Irp, 0 );   
  98.     return Irp->IoStatus.Status;   
  99.        
  100. }   
  101.   
  102.   
  103. VOID ProcessCreateMon ( IN HANDLE hParentId, IN HANDLE PId,IN BOOLEAN bCreate )   
  104. {   
  105.   
  106.     PEPROCESS  EProcess;   
  107.     ULONG      ulCurrentProcessId;   
  108.     LPTSTR       lpCurProc;   
  109.     NTSTATUS   status;   
  110.   
  111.     status = PsLookupProcessByProcessId( (ULONG)PId, &EProcess);   
  112.     if (!NT_SUCCESS( status ))   
  113.     {   
  114.         DbgPrint("PsLookupProcessByProcessId()/n");   
  115.         return ;   
  116.     }   
  117.        
  118.   
  119.     if ( bCreate )   
  120.     {   
  121.           lpCurProc = (LPTSTR)EProcess;   
  122.         lpCurProc = lpCurProc + ProcessNameOffset;   
  123.   
  124.         DbgPrint( "CREATE PROCESS = PROCESS NAME: %s , PROCESS PARENTID: %d, PROCESS ID: %d, PROCESS ADDRESS %x:/n",    
  125.                               lpCurProc,   
  126.                               hParentId,   
  127.                               PId,   
  128.                               EProcess );   
  129.     }   
  130.         
  131.     else  
  132.     {   
  133.   
  134.         DbgPrint( "TERMINATED == PROCESS ID: %d/n", PId);   
  135.   
  136.     }   
  137.   
  138. }   
  139.   
  140. VOID ThreadCreateMon (IN HANDLE PId, IN HANDLE TId, IN BOOLEAN  bCreate)   
  141. {   
  142.   
  143.     PEPROCESS   EProcess;   
  144.     ULONG        ulCurrentProcessId;   
  145.     LPTSTR        lpCurProc;   
  146.     NTSTATUS    status;   
  147.   
  148.     status = PsLookupProcessByProcessId( (ULONG)PId, &EProcess);   
  149.     if (!NT_SUCCESS( status ))   
  150.     {   
  151.         DbgPrint("PsLookupProcessByProcessId()/n");   
  152.         return ;   
  153.     }       
  154.   
  155.     if ( bCreate )   
  156.     {   
  157.           lpCurProc    = (LPTSTR)EProcess;   
  158.         lpCurProc    = lpCurProc + ProcessNameOffset;   
  159.   
  160.         DbgPrint( "CREATE THREAD = PROCESS NAME: %s PROCESS ID: %d, THREAD ID: %d/n", lpCurProc, PId, TId );   
  161.                                  
  162.     }   
  163.         
  164.     else  
  165.     {   
  166.   
  167.         DbgPrint( "TERMINATED == THREAD ID: %d/n", TId);   
  168.   
  169.     }   
  170.   
  171. }   
  172.   
  173. VOID ImageCreateMon (IN PUNICODE_STRING  FullImageName, IN HANDLE  ProcessId, IN PIMAGE_INFO  ImageInfo )   
  174. {   
  175.     DbgPrint("FullImageName: %S,Process ID: %d/n",FullImageName->Buffer,ProcessId);   
  176.     DbgPrint("ImageBase: %x,ImageSize: %d/n",ImageInfo->ImageBase,ImageInfo->ImageSize);   
  177.   
  178. }  

抱歉!评论已关闭.