제 12과 64 비트 커널 개발, 프로세스 모니터링, ring0 이벤트와 동기화 링 3.

다이애나 자세한 동기화 및 상호 배제, 및 프로세스 모니터링 소프트웨어를 구현합니다.

스레드 동기화 1. KEVENT

이벤트는 단순 이벤트 상태. 그리고 이벤트 범주로 구분된다.

이벤트 상태 :
신호가 신호를하지 있습니다
어떤 신호 이외의 신호
이벤트 범주
자동으로 설정 자동 복구 동기화
자동 수동 알림을 복원하지 않습니다.

이벤트의 함수를 만듭니다

** IoCreateNotificationEvent () **

** KeClearEvent () ** 비 신호 상태로 설정된

** KeResetEvent () ** 어떤 신호가 이전의 상태와 상태로 돌아갑니다 설정되어 있지 않은
신호에 ** KeSetEvent () ** 이벤트 세트.

사실,에 신호가 없으면 신호를 이해. 신호가 있습니다. 나는. 함수가 대기 할 수있는 대기
신호 없음 어디 차단하지 않습니다.

이벤트 범주 대기 한 후 설정을 기반으로합니다. 자동으로 설정되지 않은 신호 없음으로 설정됩니다.
신호가 자동으로 설정하지 않으면 우리가 신호에 이벤트를 설정까지. 그래서 다음 스레드가 차단됩니다. 수 있습니다.

커널에서 일반적으로 이벤트가 익명 커널 이벤트를 사용하는 것입니다 사용합니다. 대신 사용하는 IoCreateNotificationEvent를

다음과 같이 코드입니다 :

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

//设置事件为有信号

KeSetEvent(&myKevent,IO_NO_INCREMENT,FALSE);

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

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

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

2. 프로세스 모니터링 및 링 3의 ring0 동시에 사용 이벤트

와 ring0의 링 3 통신은 우리가 위의 사용한다고 말했다 경우
ring0를 -> 링 3의 통신 기능을 이름.

IoCreateNotificationEvent는
Ring0를 사용하여 -.> 링 3의 통신을 우리는이 기능 및 기타 관련 지식을 이해해야 할 때

1.ring0 명명 된 이벤트를 만들 -> 링 3는 다음과 같이 이름을 만들려면이 이벤트 이름을 사용해야합니다; ..
** L"\\BaseNamedObjects\\你自定义的名字
2. 재 방문
역할 IoCreateDevice ** 기능.

이 IoCreateDevice . .. 잘 알려진 기능은 장치 개체 생성하는
다음과 같이 정의를 :

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

우리는 이전 장치 개체가 두 번째 인수가 확장 장치 ..의 크기 때 생성되는 것을
우리는 0이었다가하지만 지금 ring0 -... 링 3 통신 때문에 우리가이 ring0를 사용할 수 있도록 데이터 저장을위한 데이터 구조를 정의해야 설비 확장이.
예를 들면 :
. 우리는이 구조의 크기는 두 번째 인수로 전달하는 구조를 만들
우리가 생성 한 디바이스 객체에서 사용되는 경우, S ..의 구성원 DeviceExtension 이 우리의 장치이다. 우리의 응용 프로그램이 메모리의 확장
. 우리는 우리의 사용자 정의 크기의 구조로 변환 할 수 있습니다
다음과 같은 코드는 간단하다 :

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;

마지막으로, 생성 된 이벤트를 만들 수있는 커널을 사용합니다. IoCreateNotificationEvent

링 3는 정의 된 이벤트가 간단 ring0에서 사용하려고합니다.
다음과 같이 :

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

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

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

}

이벤트 링 3 대기 ring0은 매우 간단합니다. 직접 이벤트를 엽니 다. 간단하게 기다립니다.

3. 프로세스 모니터링 코드입니다.

프로세스 모니터링 첫 번째는 위에서 언급 한 콘텐츠를 사용하고 다음 단계로 구분됩니다

1. 장치 개체를 만듭니다. 확장은 우리의 사용자 정의 장치 개체 구조를 속성. 수신 구조의 크기가 될 수 있습니다.
2. 장치 개체가 생성 절약 전역 변수 장치 개체 포인터 만들기

3. 링 3, 심볼릭 링크를 만듭니다 링 0와 통신

4. 파견 제어 기능을 만듭니다. 링 3는 수신 제어 그것에 의해 발표했다.

5. IoCreateNotificationEvent은 이벤트 동기화를 위해 Ring0와 이벤트 객체입니다. 링 3를 만들 수 있습니다.

프로세스가 생성되면 제 등록 프로세스 제어 콜백 함수.. 콜백이 호출되거나 파괴

7. 콜백 함수, 전역 장치 개체 포인터 우리의 사용자 정의 구조. 포인트.의 하위 멤버
지정 매개 변수 경우 변경하고 이벤트 객체를 설정

판독 데이터 제어 기능 콜백 함수가 할당 아웃 복사 8.ring3 데이터
링 3을 수있다.

이벤트에 대한 대기 open 이벤트. 수 9.ring3. DeviceIoControl을 그것을 제어 보냅니다. 데이터 표시 데이터를 읽습니다.

다음과 같이 코드입니다 :

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

이벤트 객체는 다음 링 3를 엽니 다. 내가되는 글로벌 이벤트 객체를 열 수 있습니다 쓰기합니다 다음 제어 코드 .ring0 할당에 보냈다.\\Global

링 3 코드.

// 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;
}

ring0 콜백에서 설정 한 시스템의 프로세스를 사용하는 것에주의 된 PsSetCreateProcessNotifyRoutine에게 만을 모니터링 할 수있는 커널 함수를
프로세스 ID와 부모 프로세스 ID 또는 닫는 태그를 생성합니다. 우리는 전 시리즈를 사용할 수 있습니다.이 경우 프로세스의 이름 등등 감시. 그리고 할 수 있습니다.

표시

추천

출처www.cnblogs.com/iBinary/p/10993899.html