编写进程/线程监视器

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情
创建时间:2003-03-21
文章属性:原创
文章来源: http://www.whitecell.org
文章提交: sinister (jiasys_at_21cn.com)

编写进程/线程监视器


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

}


关于我们:

WSS(Whitecell Security Systems),一个非营利性民间技术组织,致力于各种系统安全技术的研究。坚持传统的hacker精神,追求技术的精纯。
WSS 主页: http://www.whitecell.org/
Windows使用进程监视器查看进程读写的文件名 进程监视器(Process Monitor)是用于Windows的高级监视工具,用于显示实时文件系统、注册表进程/线程活动。 进程监视器包括强大的监视筛选功能,包括: 为操作输入输出参数捕获的更多数据 使用非破坏性筛选器可以设置筛选器而不丢失数据 捕获每个操作的线程堆栈使得在许多情况下能够识别操作的根本原因 可靠捕获进程详细信息,包括映像路径、命令行、用户会话 ID 任何事件属性的可配置可移动列 可以为任何数据字段设置筛选器,包括未配置为列的字段 高级日志记录体系结构可扩展到数千万 阅读详情

相关推荐

线程/进程同步操作的监视器:管程

我们通过信号量解决同步问题,而信号量存在程序编写困难或效率低下的问题。于是发明了管程,将信号量的这些组织工作交给一个专门的构造来管。管程(monitor)意为监视器,它监视的是进程线程的同步操作。 管程就是一组子程序,变量数据的组合,即你把需要同步的代码用一个管程的构造框起来。 注意:进程只能互斥的使用管程,即当一个进程使用管程时,另一个进程必须等待。当一个进程使用完管程后,它必须释放管程...

shimadear的博客 853

精选_枚举并删除系统上PsSetCreateThreadNotifyRoutine回调_源码打包

枚举并删除系统上PsSetCreateThreadNotifyRoutine回调

SQL Server活动监视器

什么是SQL Server活动监视器? (What is SQL Server Activity Monitor?) SQL Server Activity Monitor is a feature in SQL Server Management Studio that displays information about the SQL Server processes and their ...

culuo4781的博客 5301

在VS2008中配置WDK7600驱动开发环境

网上这类资料多如牛毛,也许很多人都是转来转去,却很有人去真正的测试,有时候感觉确实对他人也是一种误导。 这里是我自己在VS2008 + WDK7600.16385.0 + DDKWizard配置自己的IDE开发环境的设置过程: 1、首先安装DDKWizard 官方网页:http://ddkwizard.assarbad.net/ 从官方网页下载这三个

Koma的主页 7255

64位下使用回调函数实现监控(下)

线程监控使用到的API相对于进程监控简单,使用到,而这个值并不能像进程操作的API一样进行操作,这里我们首先先使用这个API来进行线程监控指向的结构如下,第一个参数为PID,第二个参数为TID,第三个参数表示是创建线程还是删除线程,创建线程则为TRUE,删除线程则为FALSE那么我们这里就可以写出函数这里如果要将函数摘除,就需要用到函数,定义如下我们如果想让进行线程保护该如何操作呢?

星星我啊,已经很努力在学习了, 有人一起学习吗?Ziansec-1 1024

[原创]通过PsSetCreateProcessNotifyRoutineExPsSetCreateThreadNotifyRoutine实现进程线程监控

PsSetCreateProcessNotifyRoutineEx是Windows提供得一个可以通过设置回调函数实现进程监控的内核API。其在文档的定义如下: 1 2 3 4 5 NTSTATUS PsSetCreateProcessNotifyRoutineEx( INPCREATE_PROCESS_NOTIFY_ROUTINE_EXNotifyRoutine, INBOOLEAN...

追逐光芒,追随内心 2349

驱动开发:内核监控进程线程创建

监控进程的启动与退出可以使用 `PsSetCreateProcessNotifyRoutineEx` 来创建回调,当新进程产生时,回调函数会被率先执行,然后执行我们自己的`MyCreateProcessNotifyEx`函数,并在内部进行打印输出。而检测线程操作与检测进程差不多,检测线程需要调用`PsSetCreateThreadNotifyRoutine` 创建回调函数,然后就可以检测线程的创建了。

微软技术分享 1万+

线程任务监视器

本文介绍了Java线程池任务超时控制的几种实现方案。首先分析了线程池中任务阻塞导致线程无法释放的问题,提出通过设置最大执行时长来强制终止超时任务。然后详细比较了三种实现方式:1)在子线程中再创建线程并利用join()方法监控;2)使用ScheduledExecutorService定时检查任务状态;3)结合CompletableFutureScheduledExecutorService实现更精确的监控。重点阐述了第三种方案的工作原理:通过CompletableFuture作为监控器,当任务正常完成或异常

纯洁的小魔鬼 1464

(转载)编写进程/线程监视器

编写进程/线程监视器创建时间:2003-03-21文章属性:原创文章来源:http://www.whitecell.org文章提交:sinister (jiasys_at_21cn.com)编写进程/线程监视器Author  : sinisterEmail   : sinister@whitecell.org HomePage: http://www.whitecell.org (首先说明一下。有

Kendiv's Box 2125

DDK版本的进程/线程监视器

编写进程/线程监视器Author  : sinisterEmail   : sinister@whitecell.org HomePage: http://www.whitecell.org (首先说明一下。有不少朋友来信问一些进程/线程监视工具是如何实现的。我写出来是为了让那些朋友有进一步的了解,也省的我一封封的回MAIL。如果您是 NT DRIVER熟手,那么此文提到的方法您可能早已掌握,完全

rageliu的专栏 3877

VC++6.0网络进程监视器的开发与实现

VC++6.0,即Visual C++ 6.0,是微软公司发布的一款集成开发环境(IDE),在1998年正式推出。它广泛应用于Windows平台下的C/C++语言开发,具有强大的编译器、调试器、资源编辑器等工具。至今,尽管已有数个版本的Visual Studio相继推出,VC++6.0由于其稳定性易用性,仍被许多开发者所钟爱。Microsoft Foundation Classes(MFC)是一套C++类库,封装了Windows API,使得开发Windows应用程序变得相对容易。

weixin_42298164的博客 923
上一篇: 怎样在vc、delphi中使用mysql(mysql odbc驱动的使用)
下一篇: 怎样用程序生成access数据库文件(*.mdb)
y0617
博客等级 码龄22年 0粉丝 12原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值