//write by jingzhongrong
最近在论坛上看到很多人都在问这个问题,花了一些时间写了这个程序,原理很简单,主要功能通过一个内核驱动中使用PsSetCreateProcessNotifyRoutine 函数来实现。效果也不错
首先新建一个驱动程序工程,在DriverEntry例程中调用PsSetCreateProcessNotifyRoutine函数向系统添加一个回调函数,并创建一个系统事件对象,当系统中有进程新建或者进程终止,回调函数将会被调用,而在进程回调函数中,保存信息并出发系统事件,通知用户态的应用程序。
PsSetCreateProcessNotifyRoutine函数的原型声明如下:
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 );
创建系统事件的函数:IoCreateNotificationEvent
下面是具体的代码:
#ifndef CPN_DRIVER_H#define CPN_DRIVER_H #include <ntddk.h> #include <devioctl.h> //自定义函数声明 NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);NTSTATUS CPNDispatchCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);VOID CPNUnload(IN PDRIVER_OBJECT DriverObject); NTSTATUS CPNDispatchIoctl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);VOID ProcessCallback(IN HANDLE hParentId, IN HANDLE hProcessId, IN BOOLEAN bCreate);#define DEVICE_NAME L"/Device/CPNDriver" #define LINK_NAME L"/DosDevices/CPNDriverLink" #define EVENT_NAME L"/BaseNamedObjects/CPNDriverEvent" typedef struct _DEVICE_EXTENSION{ HANDLE hProcessHandle; PKEVENT pProcessEvent; HANDLE hParentID; HANDLE hProcessID; BOOLEAN bCreate;}DEVICE_EXTENSION,* PDEVICE_EXTENSION;typedef struct _CALLBACK_INFO{ HANDLE hParentId; HANDLE hProcessId; BOOLEAN bCreate;}CALLBACK_INFO, * PCALLBACK_INFO;#define IOCTL_CPNDRIVER_GET_PROCESSINFO CTL_CODE(FILE_DEVICE_UNKNOWN,0x0800,METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)#endif
下面是C文件实现:
#include <ntddk.h> #include <devioctl.h> #include "CPNDriver.h" PDEVICE_OBJECT g_pDeviceObject; //声明全局变量
DriverEntry例程:
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath){ NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING usDevName; PDEVICE_OBJECT pDevObj; PDEVICE_EXTENSION pDevExt; UNICODE_STRING usLinkName; UNICODE_STRING usEventName; // DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverObject ->MajorFunction[IRP_MJ_CLOSE] = CPNDispatchCreateClose; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = CPNDispatchIoctl; DriverObject->DriverUnload = CPNUnload; // RtlInitUnicodeString(& usDevName,DEVICE_NAME); // status = IoCreateDevice(DriverObject, sizeof (DEVICE_EXTENSION), & usDevName, FILE_DEVICE_UNKNOWN, 0 , FALSE, & pDevObj); if(! NT_SUCCESS(status)) { return status; } // pDevExt = (PDEVICE_EXTENSION)pDevObj-> DeviceExtension; // RtlInitUnicodeString(& usLinkName,LINK_NAME); status = IoCreateSymbolicLink(&usLinkName,&usDevName); //创建关联 if(! NT_SUCCESS(status)) { IoDeleteDevice(pDevObj); return status; } // g_pDeviceObject = pDevObj; // RtlInitUnicodeString(& usEventName,EVENT_NAME); pDevExt->pProcessEvent = IoCreateNotificationEvent(&usEventName,&pDevExt-> hProcessHandle); KeClearEvent(pDevExt-> pProcessEvent); // status = PsSetCreateProcessNotifyRoutine(ProcessCallback,FALSE); return status;}
其他派遣例程:
VOID CPNUnload(IN PDRIVER_OBJECT DriverObject){ UNICODE_STRING usLink; PsSetCreateProcessNotifyRoutine(ProcessCallback,TRUE); //移除 RtlInitUnicodeString(& usLink,LINK_NAME); IoDeleteSymbolicLink(& usLink); IoDeleteDevice(DriverObject-> DeviceObject);}NTSTATUS CPNDispatchCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){ Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp,IO_NO_INCREMENT); return STATUS_SUCCESS;}NTSTATUS CPNDispatchIoctl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){ NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp); PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)DeviceObject-> DeviceExtension; ULONG uIoControlCode = pIrpStack-> Parameters.DeviceIoControl.IoControlCode; PCALLBACK_INFO pCallbackInfo = (PCALLBACK_INFO)Irp-> AssociatedIrp.SystemBuffer; ULONG uInSize = pIrpStack-> Parameters.DeviceIoControl.InputBufferLength; ULONG uOutSize = pIrpStack-> Parameters.DeviceIoControl.OutputBufferLength; switch (uIoControlCode) { case IOCTL_CPNDRIVER_GET_PROCESSINFO: { if(uOutSize >= sizeof (CALLBACK_INFO)) { pCallbackInfo->hParentId = pDevExt-> hParentID; pCallbackInfo->hProcessId = pDevExt-> hProcessID; pCallbackInfo->bCreate = pDevExt-> bCreate; status = STATUS_SUCCESS; } } break ; } if(status == STATUS_SUCCESS) { Irp->IoStatus.Information = uOutSize; } else { Irp ->IoStatus.Information = 0 ; } Irp->IoStatus.Status = status; IoCompleteRequest(Irp,IO_NO_INCREMENT); return status;}
回调函数如下:
VOID ProcessCallback(IN HANDLE hParentId, IN HANDLE hProcessId, IN BOOLEAN bCreate){ PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)g_pDeviceObject-> DeviceExtension; pDevExt->hParentID = hParentId; pDevExt->hProcessID = hProcessId; pDevExt->bCreate = bCreate; //触发事件 KeSetEvent(pDevExt->pProcessEvent,0 ,FALSE); KeClearEvent(pDevExt-> pProcessEvent);}
编译成sys后,创建一个Windows程序,下面用BCB来实现:
使用一个线程类来从驱动程序等待并获得信息,使用DeviceIoControl。
下面是线程类的具体实现以及声明:
//头文件声明 class GetInformationThread : public TThread{public : __fastcall GetInformationThread(bool CreateSuspended, TListView* tv); protected : void __fastcall Execute(); void __fastcall ReflashListView(); AnsiString __fastcall GetProcessNameFromID(DWORD dwProcessID); private : HANDLE hhParentId; HANDLE hhProcessId; BOOLEAN bbCreate; TListView * lv;};//cpp实现 __fastcall GetInformationThread::GetInformationThread(bool CreateSuspended, TListView* tv) :TThread(CreateSuspended){ lv = tv;}void __fastcall GetInformationThread::Execute(){ CALLBACK_INFO CallbackInfo = { 0 }; CALLBACK_INFO CallbackTemp = { 0 }; while(!this-> Terminated) { while(WaitForSingleObject(hProcessEvent,INFINITE)== WAIT_OBJECT_0) { DWORD BytesReturn; BOOL bRet = DeviceIoControl(hDriver,IOCTL_CPNDRIVER_GET_PROCESSINFO,NULL,0,& CallbackInfo, sizeof(CallbackInfo),& BytesReturn,NULL); if (bRet) { if(CallbackInfo.hParentId != CallbackTemp.hParentId || CallbackInfo.hProcessId != CallbackTemp.hProcessId || CallbackInfo.bCreate != CallbackTemp.bCreate) { hhParentId = CallbackInfo.hParentId; hhProcessId = CallbackInfo.hProcessId; bbCreate = CallbackInfo.bCreate; CallbackTemp = CallbackInfo; Synchronize(ReflashListView); } } else { ShowMessage( "获取进程信息失败." ); break ; } } }}AnsiString __fastcall GetInformationThread::GetProcessNameFromID(DWORD dwProcessID){ //HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); PROCESSENTRY32 pe; ZeroMemory(&pe,sizeof (pe)); pe.dwSize = sizeof (pe); AnsiString temp = "Unknown" ; BOOL bMore = Process32First(hSnapshot,& pe); while (bMore) { if(pe.th32ProcessID == dwProcessID) { temp = AnsiString(pe.szExeFile); break ; } else { bMore = Process32Next(hSnapshot,& pe); } } return temp;}void __fastcall GetInformationThread::ReflashListView(){ AnsiString parentProcessName; AnsiString ProcessName; parentProcessName = this->GetProcessNameFromID((DWORD)this-> hhParentId); ProcessName = this->GetProcessNameFromID((DWORD)this-> hhProcessId); if(this-> bbCreate) { hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0 ); parentProcessName = this->GetProcessNameFromID((DWORD)this-> hhParentId); ProcessName = this->GetProcessNameFromID((DWORD)this-> hhProcessId); } else { parentProcessName = this->GetProcessNameFromID((DWORD)this-> hhParentId); ProcessName = this->GetProcessNameFromID((DWORD)this-> hhProcessId); hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0 ); } TListItem *temp = lv->Items-> Add(); temp->Caption = AnsiString((int)this-> hhProcessId); temp->SubItems->Add(AnsiString((int)this-> hhParentId)); if(this-> bbCreate) { temp->SubItems->Add("Create" ); temp->SubItems-> Add(parentProcessName); temp->SubItems-> Add(ProcessName); } else { temp ->SubItems->Add("Close" ); temp->SubItems-> Add(parentProcessName); temp->SubItems-> Add(ProcessName); }}
引入一个头文件,声明驱动程序中使用的的信息返回结构(回调函数传出来的信息),以及设备控制代码的声明。
#ifndef DRIVERINFOSTRUCT_H#define DRIVERINFOSTRUCT_H #include <windows.h> #include <winioctl.h> #define IOCTL_CPNDRIVER_GET_PROCESSINFO CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0800, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)//用户与内核交互的缓冲区格式,这个结构向用户程序返回进程信息 typedef struct _CALLBACK_INFO{ HANDLE hParentId; HANDLE hProcessId; BOOLEAN bCreate;}CALLBACK_INFO, * PCALLBACK_INFO;#endif下面就是使用SCM服务管理函数,创建服务,打开服务,然后在打开驱动程序的句柄,启动线程访问。
//h头文件实现 #ifndef Unit1H#define Unit1H //--------------------------------------------------------------------------- #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <ComCtrls.hpp> class TForm1 : public TForm{__published: // IDE-managed Components TButton * Button1; TButton * Button2; TButton * Button3; TListView * ListView1; TGroupBox * GroupBox1; TLabel * Label1; void __fastcall Button1Click(TObject * Sender); void __fastcall Button2Click(TObject * Sender); void __fastcall Button3Click(TObject * Sender); private: // User declarations bool notifying; char szDriverPath[256 ]; GetInformationThread * th;public: // User declarations __fastcall TForm1(TComponent* Owner);};//--------------------------------------------------------------------------- extern PACKAGE TForm1 * Form1;//--------------------------------------------------------------------------- #endif // cpp文件实现//--------------------------------------------------------------------------- #include <windows.h> #include <tlhelp32.h> #include <vcl.h> #pragma hdrstop #include "Unit1.h" #include "DriverInfoStruct.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 * Form1;SC_HANDLE hSCM;SC_HANDLE hService;HANDLE hDriver;HANDLE hProcessEvent;char szLinkName[] = "CPNDriverLink" ;HANDLE hSnapshot;//--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner){ notifying = false ; Button1->Enabled = true ; Button2->Enabled = false ; Button3->Enabled = true ;this->szDriverPath[0] = '/0';
}//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender){ char *p; ::GetFullPathName("CPNDriver.sys",256,szDriverPath,&p); if(notifying==false) { hSCM = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); if(hSCM==NULL) { ShowMessage("打开服务控制管理器失败."); notifying = false; Button1->Enabled = true; Button2->Enabled = false; Button3->Enabled = true; return; } hService = CreateService(hSCM,szLinkName,szLinkName,SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER,SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,szDriverPath, NULL,0,NULL,NULL,NULL); if(hService==NULL) { int nError = GetLastError(); if(nError==ERROR_SERVICE_EXISTS || nError==ERROR_SERVICE_MARKED_FOR_DELETE) { hService = OpenService(hSCM,szLinkName,SERVICE_ALL_ACCESS); } } if(hService==NULL) { ShowMessage("创建服务出错."); CloseServiceHandle(hSCM); notifying = false; Button1->Enabled = true; Button2->Enabled = false; Button3->Enabled = true; return; } if(!StartService(hService,0,NULL)) { int nError = GetLastError(); if(nError != ERROR_SERVICE_ALREADY_RUNNING) { ShowMessage("启动服务出错."); DeleteService(hService); CloseServiceHandle(hService); CloseServiceHandle(hSCM); notifying = false; Button1->Enabled = true; Button2->Enabled = false; Button3->Enabled = true; return; } } char szDriverFile[256] = ""; wsprintf(szDriverFile,".//%s",szLinkName); hDriver = CreateFile(szDriverFile,GENERIC_READ|GENERIC_WRITE, 0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if(hDriver==INVALID_HANDLE_VALUE) { ShowMessage("打开设备失败."); DeleteService(hService); CloseServiceHandle(hService); CloseServiceHandle(hSCM); notifying = false; Button1->Enabled = true; Button2->Enabled = false; Button3->Enabled = true; return; } hProcessEvent = OpenEvent(SYNCHRONIZE,FALSE,"CPNDriverEvent"); th = new GetInformationThread(true,ListView1); th->Resume(); notifying = true; Button1->Enabled = false; Button2->Enabled = true; Button3->Enabled = false; }}
void __fastcall TForm1::Button2Click(TObject *Sender){ th->Terminate(); CloseHandle(hDriver); SERVICE_STATUS ss; ControlService(hService,SERVICE_CONTROL_STOP,&ss); DeleteService(hService); CloseServiceHandle(hService); CloseServiceHandle(hSCM); notifying = false; Button1->Enabled = true; Button2->Enabled = false; Button3->Enabled = true;}//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender){ this->Close(); }