編寫程式/執行緒監視器
有時候我們希望能夠動態監視系統中任意程式/執行緒的建立與銷燬。為了達
到此目的我翻閱了 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);
}
到此目的我翻閱了 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);
}
相關文章
- 編碼:執行緒執行監控執行緒
- 編寫執行緒安全的JSP應用程式執行緒JS
- 編寫高效的執行緒安全類執行緒
- 使用 C++11 編寫 Linux 多執行緒程式C++Linux執行緒
- 使用 C++ 11 編寫 Linux 多執行緒程式C++Linux執行緒
- 用VB編寫非同步多執行緒下載程式 (轉)非同步執行緒
- 最簡單的編寫基於執行緒的程式碼的方法之一:派生執行緒類(轉)執行緒
- 認識執行緒、建立執行緒寫法執行緒
- 配置監聽器,建立執行緒定時執行業務邏輯執行緒行業
- 多執行緒------執行緒與程式/執行緒排程/建立執行緒執行緒
- linux 檢視 程式 執行緒數Linux執行緒
- Java利用執行緒工廠監控執行緒池Java執行緒
- 程式執行緒篇——程式執行緒基礎執行緒
- VC編寫多執行緒sql盲注工具.doc執行緒SQL
- 請教一個多執行緒編寫的題!執行緒
- Linux中檢視程式的多執行緒Linux執行緒
- Centos檢視程式的執行緒數量CentOS執行緒
- 程式-程式-執行緒執行緒
- 瀏覽器渲染程式多執行緒瀏覽器執行緒
- 基於MFC的編寫執行緒快速入門 (轉)執行緒
- 利用多執行緒寫一個賣票程式執行緒
- 在LINUX下編寫程式並執行Linux
- Java併發(三)----建立執行緒的三種方式及檢視程式執行緒Java執行緒
- [短文速讀 -5] 多執行緒程式設計引子:程式、執行緒、執行緒安全執行緒程式設計
- 編寫多執行緒應用程式,模擬多個人通過一個山洞:執行緒
- 程式執行緒篇——執行緒切換(下)執行緒
- 執行緒、執行緒與程式、ULT與KLT執行緒
- 程式執行緒篇——執行緒切換(上)執行緒
- 多執行緒-程式和執行緒的概述執行緒
- 【從0開始編寫webserver·基礎篇#01】為什麼需要執行緒池?寫一個執行緒池吧WebServer執行緒
- 執行緒(一)——執行緒,執行緒池,Task概念+程式碼實踐執行緒
- Java 併發:執行緒、執行緒池和執行器全面教程Java執行緒
- Java中命名執行器服務執行緒和執行緒池Java執行緒
- 執行緒池監控2-監控執行緒池狀態、執行緒數量和佇列任務數量等執行緒佇列
- Android程式框架:執行緒與執行緒池Android框架執行緒
- Java多執行緒1:程式與執行緒概述Java執行緒
- 程式與執行緒執行緒
- 執行緒與程式執行緒