Lesson 12 64-bit kernel development, process monitoring, ring3 sync with ring0 event.

A Dian Detailed synchronization and mutual exclusion, and implement a process monitoring software.

1. KEVENT for thread synchronization

Events are divided into simple event status. And event category.

Event Status:
There are signals Signaled
no signal Non-signaled
Event Category
automatic recovery Synchronization automatically set
does not automatically restore Notification manually.

Create a function of events

** IoCreateNotificationEvent () **

** KeClearEvent () ** non-signal state is set to

** KeResetEvent () ** No signal is set to return to the previous status and state
** KeSetEvent () ** set the event to signaled.

In fact, understanding the signal with no signal on it. There are a signal. I wait function can wait.
No signal will block where.

After waiting for an event category is based on your settings. Is automatically set to No Signal is not set.
If no signal is automatically set. So the next thread will be blocked until we set for the event to signaled. Can.

In the kernel typically use the event is to use anonymous kernel event. Instead of using IoCreateNotificationEvent

code show as below:

KEVENT myKevent;
KeInitializeEvent(&myKevent, NotificationEvent,FALSE);

//设置事件为有信号

KeSetEvent(&myKevent,IO_NO_INCREMENT,FALSE);

//等待事件
KeWaitForSingleObject(&myEvent,Executive,KernerMode,False,NULL);

//因为设置的类别是手动设置类别.所以我们自己要把事件信号设置为无信号

//调用两个都可以
KeResetEvent(&myEvent);
KeClearEvent(&myEvent);

2. Process Monitoring and ring3 ring0 simultaneous use Event

If ring0 ring3 communication with said we should use the above
ring0 -> ring3 communications naming the function.

IoCreateNotificationEvent
using Ring0 -.> Ring3 communication when we have to understand this function and other related knowledge

1.ring0 create a named event -> ring3 then you need to use this event name to create a name as follows;..
** L"\\BaseNamedObjects\\你自定义的名字
2. Revisited
role IoCreateDevice ** function.

IoCreateDevice .. Well-known function is to create a device object.
Defined as follows:

NTSTATUS IoCreateDevice(
  PDRIVER_OBJECT  DriverObject,
  ULONG           DeviceExtensionSize,   //设备扩展大小
  PUNICODE_STRING DeviceName,
  DEVICE_TYPE     DeviceType,
  ULONG           DeviceCharacteristics,
  BOOLEAN         Exclusive,
  PDEVICE_OBJECT  *DeviceObject
);

We said earlier device object is created when the second argument is the size of the expansion device..
We have been to 0. But now because ring0 -... Ring3 communication we need to customize the data structure for data storage so you can use this ring0 equipment expanded.
such as:
we create a structure the size of this structure will be passed to the second argument.
when used in the device object that we have created is a member of the S.. the DeviceExtension this is our device. the expansion of that memory for our application
we may be converted to our custom size structure.
code is simple as follows:

typedef struct _MYDEVICE_EXTENSION
{
  //自定义数据
}MYDEVICE_EXTENSION,*PMYDEVICE_EXTENSION;

IoCreateDevice(DriverObject,sizeof(MYDEVICE_EXTENSION),....);
主要就是第二个参数.

使用:
PMYDEVICE_EXTENSION pMyDevice = (PMYDEVICE_EXTENSION)Device->DeviceExtension; 这个成员就指向我们扩展的内存.
强转为我们的指针即可.

pMyDevice->xxx = xxx;
pMyDevice->xxx = xxx;

Finally, use the kernel can create an event created. IoCreateNotificationEvent

ring3 want to use under ring0 defined Event is simple.
as follows:

#define EVENT_NAME L"\\Global\\xxx"

HANDLE hEvent = OpenEventW(SYNCHRONIZE,FASE,EVENT_NAME);

while(WaitForSingleObject(hEvent,INFINITE))
{
  发送 DeviceIoControl读取内核层的数据即可.(上面说的设备扩展数据)

}

Event ring3 wait ring0 is very simple. Directly open the event. Simply wait.

3. Process Monitoring code.

Process Monitoring First will use the above mentioned content and then divided into the following steps

1. Create a device object. Extended attributes our custom device object structure. Incoming structure size can be.
2. Create a global variable device object pointer saving device object created

3. Create a symbolic link, ring3 communicate with the ring 0

4. Create dispatch control function. Ring3 issued by the receiving control it.

5. Use IoCreateNotificationEvent create an event object. Ring3 with Ring0 for the event synchronization.

6. Registration process control callback function. When a process is created. The callback is invoked or destroyed

7. callback function, sub-member of the global device object pointer. Point to our custom structure.
Change if the assignment parameters and set the event object

8.ring3 data when the read data control function callback function to copy out the assignment
ring3 can.

9.ring3 be open event. Waiting for the event. Send DeviceIoControl control it. Read the data display data.

code show as below:

ring0:


#include <ntddk.h>
#include <ntstrsafe.h>





/*
符号连接名
设备对象名
事件等待名
*/


#define  IBINARY_LINKNAME L"\\DosDevices\\IBinarySymboliclnk"
#define  IBINARY_DEVICENAME  L"\\Device\\IBinaryProcLook"
#define  IBINARY_EVENTNAME       L"\\BaseNamedObjects\\ProcLook"

//定义 ring0 ring3控制码
#define CTRLCODE_BASE 0x8000
#define MYCTRL_CODE(i) \
CTL_CODE(FILE_DEVICE_UNKNOWN,CTRLCODE_BASE +i,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define IOCTL_PROCESS_LOCK_READ MYCTRL_CODE(1)
UNICODE_STRING g_uSymbolicLinkName = { 0 };
//控制派遣函数.以及卸载函数.

void DriverUnLoad(PDRIVER_OBJECT pDriverObject);
NTSTATUS InitDeviceAnSymbolicLink(
    PDRIVER_OBJECT pDriverObj,
    UNICODE_STRING uDeviceName, 
    UNICODE_STRING uSymbolicLinkName,
    UNICODE_STRING uEventName);

NTSTATUS DisPatchComd(PDEVICE_OBJECT pDeviceObject, PIRP pIrp);
NTSTATUS DisPatchIoControl(PDEVICE_OBJECT pDeviceObject,PIRP pIrp);
VOID pMyCreateRoutine (IN HANDLE pParentId,HANDLE hProcessId,BOOLEAN bisCreate);

//自定义设备扩展.以及全局变量指针.进行保存的.
typedef struct _Device_Exten
{
    /*
    自定义数据.比如保存
    进程PID 父PID
    进程事件对象
    全局事件对象
    */
    HANDLE  hProcess;         //进程句柄
    PKEVENT pkProcessEvent;   //全局事件对象,ring3使用
    HANDLE  hProcessId;       //进程的PID
    HANDLE  hpParProcessId;   //父进程ID.当前你也可以有进程名字
    BOOLEAN bIsCreateMark;    //表示是创建进程还是销毁.创建进程回调可以看到

}DEVICE_EXTEN,* PDEVICE_EXTEN;
PDEVICE_OBJECT g_PDeviceObject;

//定义ring3->读取ring0的数据
typedef struct _PROCESS_LONNK_READDATA
{
    HANDLE hProcessId;
    HANDLE hpParProcessId;
    BOOLEAN bIsCreateMark;
}PROCESS_LONNK_READDATA,*PPROCESS_LONNK_READDATA;

NTSTATUS
DriverEntry(
    _In_ PDRIVER_OBJECT  pDriverObject,
    _In_ PUNICODE_STRING RegistryPath
    )
{
    NTSTATUS ntStatus;
    UNICODE_STRING uDeviceName = { 0 };
    
    UNICODE_STRING uEventName = { 0 };


    //setp 1注册卸载函数,以及设置通讯方式
    pDriverObject->DriverUnload = DriverUnLoad;
    

    //setp 2 初始化符号链接名.设备名. 以及事件对象名字,并且检验一下
    ntStatus = RtlUnicodeStringInit(&uDeviceName, IBINARY_DEVICENAME);
    if (!NT_SUCCESS(ntStatus))
    {
        KdPrint(("初始化设备名称失败"));
        return ntStatus;
    }
    KdPrint(("初始化设备名称成功"));

    ntStatus = RtlUnicodeStringInit(&g_uSymbolicLinkName, IBINARY_LINKNAME);
    if (!NT_SUCCESS(ntStatus))
    {
        KdPrint(("初始化符号链接名字失败"));
        return ntStatus;
    }
    KdPrint(("初始化符号链接名字成功"));
    ntStatus = RtlUnicodeStringInit(&uEventName, IBINARY_EVENTNAME);
    if (!NT_SUCCESS(ntStatus))
    {
        KdPrint(("初始化全局事件对象失败"));
        return ntStatus;
    }
    KdPrint(("初始化全局事件对象成功"));

    //setp 3建立一个函数.函数内部进行初始化设备对象.初始化符号链接.初始化全局事件对象.
    ntStatus = InitDeviceAnSymbolicLink(
        pDriverObject,
        uDeviceName,
        g_uSymbolicLinkName,
        uEventName);
    return ntStatus;
}

//卸载驱动.关闭符号链接
void DriverUnLoad(PDRIVER_OBJECT pDriverObject)
{
    NTSTATUS ntStatus;
    UNICODE_STRING SymboLicLinkStr = { 0 };
    ntStatus = RtlUnicodeStringInit(&SymboLicLinkStr, IBINARY_LINKNAME);
    if (NT_SUCCESS(ntStatus))
    {
        ntStatus = IoDeleteSymbolicLink(&SymboLicLinkStr);
        if (!NT_SUCCESS(ntStatus))
        {
            KdPrint(("删除符号链接失败"));
        }
    }
    
    IoDeleteDevice(pDriverObject->DeviceObject);
    PsSetCreateProcessNotifyRoutine(pMyCreateRoutine, TRUE);
    KdPrint(("驱动已卸载"));
}

NTSTATUS InitDeviceAnSymbolicLink(
    PDRIVER_OBJECT pDriverObj,
    UNICODE_STRING uDeviceName,
    UNICODE_STRING uSymbolicLinkName,
    UNICODE_STRING uEventName)
{
    NTSTATUS ntStatus;
    PDEVICE_OBJECT pDeviceObject = NULL;
    //使用自定义结构
    ULONG i = 0;

    
    ntStatus = IoCreateDevice(
        pDriverObj,
        sizeof(DEVICE_EXTEN),//使用设备扩展.指定大小.那么设备对象中成员就会指向这块内存
        &uDeviceName,
        FILE_DEVICE_UNKNOWN,
        FILE_DEVICE_SECURE_OPEN,
        FALSE,                //独占设备
        &pDeviceObject);
    if (!NT_SUCCESS(ntStatus))
    {
        KdPrint(("创建设备对象失败"));
        IoDeleteDevice(pDeviceObject);
        return ntStatus;
    }
    pDriverObj->Flags |= DO_BUFFERED_IO;
    //成功之后保存到全局变量中
    KdPrint(("创建设备对象成功"));
    g_PDeviceObject = pDeviceObject;


    //创建事件.ring3->ring0的事件
    PDEVICE_EXTEN pDeviceExten = (PDEVICE_EXTEN)pDeviceObject->DeviceExtension;
    pDeviceExten->pkProcessEvent = IoCreateNotificationEvent(&uEventName, &pDeviceExten->hProcess);
    KeClearEvent(pDeviceExten->pkProcessEvent);

    //创建符号链接

    ntStatus = IoCreateSymbolicLink(&g_uSymbolicLinkName, &uDeviceName);
    if (!NT_SUCCESS(ntStatus))
    {
        KdPrint(("创建符号链接失败"));
        IoDeleteDevice(pDeviceObject);
        return ntStatus;
    }
    KdPrint(("创建符号链接成功"));

    
    
    
    /*
    因为设备对象扩展我们传入了DEVICE_EXTEN大小.所以在调用IoCreateDevice的时候.返回的
    设备对象中.设备对象会根据我们传入的大小创建一块内存.这块内存就保存在DeviceExtension
    这个字段中.
    下面调用IoCreateNotificationEvent是创建了一个命名事件.我们将事件放到我们结构体中.
    这个函数创建的事件必须手工设置事件状态.所以我们首先初始化为无信号状态.
    总的来说.IoCreateNotificationEvent创建的时候需要一个HANDLE以及一个PKEVENT.
    */


    //注册回调控制函数.当进程来了会通知.
    //  PsSetCreateProcessNotifyRoutine
    ntStatus = PsSetCreateProcessNotifyRoutine(pMyCreateRoutine,FALSE); //FASLE为注册
    if (!NT_SUCCESS(ntStatus))
    {
        KdPrint(("注册系统回调失败"));
        IoDeleteDevice(pDeviceObject);
        return ntStatus;
    }
    KdPrint(("注册系统回调成功"));


    //初始化派遣函数
    for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
    {
        pDriverObj->MajorFunction[i] = DisPatchComd;
    }
    pDriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DisPatchIoControl;

    return STATUS_SUCCESS;
}

//当进程来的时候.会通知你.
VOID pMyCreateRoutine(
    IN HANDLE pParentId,
    HANDLE hProcessId,
    BOOLEAN bisCreate)
{
    /*
    进程来的时候会通知我们.所以我们给设备扩展进行赋值.赋值进程ID以及是否创建
    */
    PDEVICE_EXTEN pDeviceExten =(PDEVICE_EXTEN)g_PDeviceObject->DeviceExtension;
    pDeviceExten->hProcessId = hProcessId;
    pDeviceExten->hpParProcessId = pParentId;
    pDeviceExten->bIsCreateMark = bisCreate;
    //赋值完毕之后.设置信号状态为有信号. 这样Ring3就会等待到事件了.
    KeSetEvent(pDeviceExten->pkProcessEvent,0,FALSE);
    //通知ring3可以读取了.那么还要设置为ring0的事件为无信号.用来保持同步
    //KeClearEvent(pDeviceExten->pkProcessEvent);
    KeResetEvent(pDeviceExten->pkProcessEvent); //跟ClearEvent一样.上面的快.这个会返回上一个设置的信号状态.都用一次

}

NTSTATUS DisPatchComd(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
    pIrp->IoStatus.Information = 0;
    pIrp->IoStatus.Status = STATUS_SUCCESS;
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);

    return pIrp->IoStatus.Status;
}
NTSTATUS DisPatchIoControl(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
    /*
    Ring3 -> ring0通讯的控制派遣函数.自定义控制码.获取Irp堆栈.获取缓冲区.

    */
    NTSTATUS ntStatus;
    PIO_STACK_LOCATION pIrpStack;
    PVOID pUserOutPutBuffer;
    PPROCESS_LONNK_READDATA pReadData;
    ULONG uIoControl = 0;
    ULONG uReadLength;
    ULONG uWriteLeng;
    PDEVICE_EXTEN pDeviceExten;
    /*
    开始解析用户操作
    */
    KdPrint(("解析用户控制码"));
    pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
    //从堆栈中获取用户控制数据
    pUserOutPutBuffer = pIrp->AssociatedIrp.SystemBuffer; //如果控制码是缓冲区方式.就使用这个.

    //定义读取的数据
    pReadData = (PPROCESS_LONNK_READDATA)pUserOutPutBuffer;
    //获取控制码.长度.进行读取
    uIoControl = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
    uReadLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
    uWriteLeng = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
    
    switch (uIoControl)
    {
    case IOCTL_PROCESS_LOCK_READ:
        //拷贝数据即可.
        pDeviceExten = (PDEVICE_EXTEN)g_PDeviceObject->DeviceExtension;
        pReadData->hProcessId = pDeviceExten->hProcessId;
        pReadData->hpParProcessId = pDeviceExten->hpParProcessId;
        pReadData->bIsCreateMark = pDeviceExten->bIsCreateMark;
        KdPrint(("内核读取 父ID = %d,子Id = %d,是否创建 = %d", (ULONG)pDeviceExten->hpParProcessId, (ULONG)pDeviceExten->hProcessId, (ULONG)pDeviceExten->bIsCreateMark));

        break;
    default:
        KdPrint(("其它控制码"));
        ntStatus = STATUS_INVALID_PARAMETER;
        uWriteLeng = 0;
        break;
    }

    pIrp->IoStatus.Information = uWriteLeng; //读取的字节数
    pIrp->IoStatus.Status = ntStatus;
    IoCompleteRequest(pIrp,IO_NO_INCREMENT);
    return ntStatus;
}

The event object to open next ring3. Note that I write is to open the global event object is then sent to the control code .ring0 assignment.\\Global

ring3 code.

// ProcWatchClientConsole.cpp : Defines the entry point for the console application.
//



#include "windows.h"
#include "winioctl.h"
#include "stdio.h"




#define EVENT_NAME    L"Global\\ProcLook"




#define CTRLCODE_BASE 0x8000
#define MYCTRL_CODE(i) \
CTL_CODE(FILE_DEVICE_UNKNOWN,CTRLCODE_BASE +i,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define IOCTL_PROCESS_LOCK_READ MYCTRL_CODE(1)

#define     IOCTL_PROCESS_LOCK_READ     MYCTRL_CODE(1)

typedef struct _PROCESS_LONNK_READDATA
{
    HANDLE hProcessId;
    HANDLE hpParProcessId;
    BOOLEAN bIsCreateMark;
}PROCESS_LONNK_READDATA, *PPROCESS_LONNK_READDATA;



int main(int argc, char* argv[])
{

    PROCESS_LONNK_READDATA pmdInfoNow = { 0 };
    PROCESS_LONNK_READDATA pmdInfoBefore = { 0 };

    
    // 打开驱动设备对象
    HANDLE hDriver = ::CreateFile(
        "\\\\.\\IBinarySymboliclnk",
        GENERIC_READ | GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
    if (hDriver == INVALID_HANDLE_VALUE)
    {
        printf("Open device failed:%x\n", GetLastError());
        return -1;
    }
    // 打开内核事件对象
    HANDLE hProcessEvent = ::OpenEventW(SYNCHRONIZE, FALSE, EVENT_NAME);

    if (NULL == hProcessEvent)
    {
        OutputDebugString("打开事件对象失败");
        system("pause");
        return 0;
    }
    OutputDebugString("打开事件对象成功");
    
    while (TRUE)
    {
        ::WaitForSingleObject(hProcessEvent, INFINITE); //等待事件
        DWORD    dwRet = 0;
        BOOL     bRet = FALSE;

        bRet = ::DeviceIoControl(
            hDriver,
            IOCTL_PROCESS_LOCK_READ,
            NULL,
            0,
            &pmdInfoNow,
            sizeof(pmdInfoNow),
            &dwRet,
            NULL);
        if (!bRet)
        {
            OutputDebugString("发送控制码失败");
            system("pause");
            return 0;
        }

        OutputDebugString("Ring3发送控制码成功");

        if (bRet)
        {
            if (pmdInfoNow.hpParProcessId != pmdInfoBefore.hpParProcessId || \
                pmdInfoNow.hProcessId != pmdInfoBefore.hProcessId || \
                pmdInfoNow.bIsCreateMark != pmdInfoBefore.bIsCreateMark)
            {
                if (pmdInfoNow.bIsCreateMark)
                {
                    printf("进程创建 PID = %d\n", pmdInfoNow.hProcessId);
                }
                else
                {
                    printf("进程退出,PID = %d\n", pmdInfoNow.hProcessId);
                }
                pmdInfoBefore = pmdInfoNow;
            }
        }
        else
        {
            printf("Get Proc Info Failed!\n");
            break;
        }
    }

    ::CloseHandle(hDriver);
    system("pause");

    return 0;
}

Note that the processes in the system set up under ring0 callback is used PsSetCreateProcessNotifyRoutine the kernel function can only monitor the
process ID and parent process ID or create a closing tag. We can use the Ex series. In this case the name of the process can be monitored. And so on.

Show

Guess you like

Origin www.cnblogs.com/iBinary/p/10993899.html