創(chuàng)建時(shí)間:2003-03-21
文章屬性:原創(chuàng)
文章來(lái)源:http://www.whitecell.org
文章提交:sinister (jiasys_at_21cn.com)

編寫進(jìn)程/線程監(jiān)視器


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

(首先說(shuō)明一下。有不少朋友來(lái)信問(wèn)一些進(jìn)程/線程監(jiān)視工具是如何實(shí)現(xiàn)的。
我寫出來(lái)是為了讓那些朋友有進(jìn)一步的了解,也省的我一封封的回MAIL。如果您
是 NT DRIVER熟手,那么此文提到的方法您可能早已掌握,完全可以略過(guò)不看。)

?? 有時(shí)候我們希望能夠動(dòng)態(tài)監(jiān)視系統(tǒng)中任意進(jìn)程/線程的創(chuàng)建與銷毀。為了達(dá)
到此目的我翻閱了 DDK 手冊(cè),發(fā)現(xiàn)其提供的 PsSetCreateProcessNotifyRoutine(),
PsSetCreateThreadNotifyRoutine(),等函數(shù)可以實(shí)現(xiàn)此功能。這兩個(gè)函數(shù)可以
通過(guò)向系統(tǒng)注冊(cè)一個(gè) CALLBALCK 函數(shù)來(lái)監(jiān)視進(jìn)程/線程等操作。函數(shù)原形如下:

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
???? );


通過(guò)原形可以看出,其 CALLBACK 函數(shù)只提供了進(jìn)程ID/線程ID。并沒(méi)有提供
進(jìn)程名。那么我們要進(jìn)一步通過(guò)進(jìn)程ID來(lái)獲取進(jìn)程名。這需要用到一個(gè)未公開(kāi)
的函數(shù) PsLookupProcessByProcessId()。函數(shù)原形如下:

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

函數(shù)輸出的 EPROCESS 結(jié)構(gòu)也是未公開(kāi)的內(nèi)核進(jìn)程結(jié)構(gòu),很多人稱其為 KPEB。
EPROCESS 結(jié)構(gòu)中的偏移 0x1FC 指向當(dāng)前進(jìn)程名的偏移。(這個(gè)結(jié)構(gòu)雖然可以在
驅(qū)動(dòng)程序中直接使用。但沒(méi)有公布其結(jié)構(gòu),網(wǎng)上有不少高手已將其結(jié)構(gòu)給出。有
興趣可以自行搜索,或去 IFS DDK 中獲取,這里因?yàn)榻Y(jié)構(gòu)太長(zhǎng),就不貼出來(lái)了)
有了這個(gè)結(jié)構(gòu)我們就可以從中得到進(jìn)程名。NT系統(tǒng)還提供了一個(gè)函數(shù)可以動(dòng)態(tài)監(jiān)
視進(jìn)程裝載映像。此函數(shù)可以得到進(jìn)程加栽時(shí)所調(diào)用的 DLL 名稱與全路徑,還有
一些映像信息。為我們獲得更詳細(xì)的進(jìn)程裝載信息提供了更好的幫助。

函數(shù)原形如下:

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;

利用以上提供的函數(shù)與結(jié)構(gòu),我們便能實(shí)現(xiàn)一個(gè)進(jìn)程/線程監(jiān)視器。下面這段
代碼演示了如何實(shí)現(xiàn)此功能。


/*****************************************************************
文件名???????? : WssProcMon.c
描述?????????? : 進(jìn)程/線程監(jiān)視器
作者?????????? : 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 );


// 驅(qū)動(dòng)入口
NTSTATUS?? DriverEntry( IN PDRIVER_OBJECT DriverObject,?? IN PUNICODE_STRING RegistryPath )
{
????
???? UNICODE_STRING?? nameString, linkString;
???? PDEVICE_OBJECT?? deviceObject;
???? NTSTATUS???????? status;
???? int???????????????? i;
????

???? //建立設(shè)備
???? 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;

}



//處理設(shè)備對(duì)象操作

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);

}