//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
下面是具體的代碼:
#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 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;
}
其他派遣例程:
{
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;
}
回調函數如下:
{
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);
}
}
引入一個頭文件,聲明驅動程序中使用的的信息返回結構(回調函數傳出來的信息),以及設備控制代碼的聲明。
#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服務管理函數,創建服務,打開服務,然後在打開驅動程序的句柄,啓動線程訪問。
#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();
}