返回列表 发帖

[转帖]编写进程/线程监视器

编写进程/线程监视器


(首先说明一下。有不少朋友来信问一些进程/线程监视工具是如何实现的。
我写出来是为了让那些朋友有进一步的了解,也省的我一封封的回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 = 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);


返回列表 回复 发帖