1. 程式人生 > >寒江獨釣-Windows核心安全程式設計筆記-第4章程式碼

寒江獨釣-Windows核心安全程式設計筆記-第4章程式碼

#ifndef __CTRL2CAP_H__
#define __CTRL2CAP_H__
#pragma once

typedef struct _C2P_DEV_EXT 
{ 
    // 結構的大小
    ULONG NodeSize; 
    // 過濾裝置物件
    PDEVICE_OBJECT pFilterDeviceObject;
    // 同時呼叫時的保護鎖
    KSPIN_LOCK IoRequestsSpinLock;
    // 程序間同步處理  
    KEVENT IoInProgressEvent; 
    // 繫結的裝置物件
    PDEVICE_OBJECT TargetDeviceObject; 
    // 繫結前底層裝置物件
    PDEVICE_OBJECT LowerDeviceObject; 
} C2P_DEV_EXT, *PC2P_DEV_EXT;

// Kbdclass驅動的名字
#define KBD_DRIVER_NAME  L"\\Driver\\kbdclass"
#define  DELAY_ONE_MICROSECOND  (-10)
#define  DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND*1000)
#define  DELAY_ONE_SECOND (DELAY_ONE_MILLISECOND*1000)

NTSTATUS c2pDevExtInit(IN PC2P_DEV_EXT devExt
    , IN PDEVICE_OBJECT pFilterDeviceObject
    , IN PDEVICE_OBJECT pTargetDeviceObject
    , IN PDEVICE_OBJECT pLowerDeviceObject);
// 這個函式是事實存在的,只是文件中沒有公開。宣告一下
// 就可以直接使用了。
NTSTATUS ObReferenceObjectByName(
    PUNICODE_STRING ObjectName
    , ULONG Attributes
    , PACCESS_STATE AccessState
    , ACCESS_MASK DesiredAccess
    , POBJECT_TYPE ObjectType
    , KPROCESSOR_MODE AccessMode
    , PVOID ParseContext
    , PVOID *Object);

NTSTATUS c2pDispatchGeneral(IN PDEVICE_OBJECT DeviceObject
    , IN PIRP irp);

NTSTATUS c2pPower(IN PDEVICE_OBJECT DeviceObject
    , IN PIRP Irp);

NTSTATUS c2pDispatchRead(IN PDEVICE_OBJECT DeviceObject
    , IN PIRP Irp);

NTSTATUS c2pReadComplete(IN PDEVICE_OBJECT DeviceObject
    , IN PIRP Irp
    , IN PVOID Context);
NTSTATUS c2pPnp(IN PDEVICE_OBJECT DeviceObject
    , IN PIRP Irp);
VOID c2pDetach(IN PDEVICE_OBJECT pDeviceObject);
VOID c2pUnload(IN PDRIVER_OBJECT DriverObject);

NTSTATUS c2pDevExtInit(IN PC2P_DEV_EXT devExt
    , IN PDEVICE_OBJECT pFilterDeviceObject
    , IN PDEVICE_OBJECT pTargetDeviceObject
    , IN PDEVICE_OBJECT pLowerDeviceObject);
// 開啟驅動物件Kbdclass,然後繫結它下面的所有的裝置:
NTSTATUS c2pAttachDevices(IN PDRIVER_OBJECT DriverObject
	, IN PUNICODE_STRING RegistryPath);
	
#endif // __CTRL2CAP_H__#include 
#include "ctrl2cap.h"

// IoDriverObjectType
extern POBJECT_TYPE *IoDriverObjectType;
ULONG gC2pKeyCount = 0;
PDRIVER_OBJECT gDriverObject = NULL;

NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
    ULONG i;
    NTSTATUS status;
    KdPrint(("MyAttach: enter DriverEntry!\n"));
    for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; ++i)
    {
        DriverObject->MajorFunction[i] = c2pDispatchGeneral;
    }

    DriverObject->MajorFunction[IRP_MJ_READ] = c2pDispatchRead;

    DriverObject->MajorFunction[IRP_MJ_POWER] = c2pPower;

    DriverObject->MajorFunction[IRP_MJ_PNP] = c2pPnp;

    DriverObject->DriverUnload = c2pUnload;

    gDriverObject = DriverObject;

    status = c2pAttachDevices (DriverObject, RegistryPath);

    return status;
}


NTSTATUS c2pDispatchGeneral(IN PDEVICE_OBJECT DeviceObject
                            , IN PIRP Irp)
{
    KdPrint(("Other Dispath!"));
    IoSkipCurrentIrpStackLocation (Irp);
    return IoCallDriver(((PC2P_DEV_EXT)DeviceObject->DeviceExtension)->LowerDeviceObject, Irp);
}

NTSTATUS c2pDispatchRead(IN PDEVICE_OBJECT DeviceObject
    , IN PIRP Irp)
{
    NTSTATUS status = STATUS_SUCCESS;
    PC2P_DEV_EXT devExt; 
    PIO_STACK_LOCATION currentIrpStack;
    KEVENT waitEvent;
    KeInitializeEvent (&waitEvent, NotificationEvent, FALSE);
    if (Irp->CurrentLocation == 1)
    {
        ULONG Returnedinformation = 0;
        KdPrint(("Dispatch encountered bogus current location \n"));
        status = STATUS_INVALID_DEVICE_REQUEST;
        Irp->IoStatus.Status = status;
        Irp->IoStatus.Information = Returnedinformation;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        return status;
    }
    gC2pKeyCount++;
    devExt = (PC2P_DEV_EXT)DeviceObject->DeviceExtension;
    currentIrpStack = IoGetCurrentIrpStackLocation (Irp);
    IoCopyCurrentIrpStackLocationToNext (Irp);
    IoSetCompletionRoutine (Irp, c2pReadComplete, DeviceObject, TRUE, TRUE, TRUE);
    return IoCallDriver(devExt->LowerDeviceObject, Irp);
}


NTSTATUS c2pPower(IN PDEVICE_OBJECT DeviceObject
    , IN PIRP Irp)
{
    PC2P_DEV_EXT devExt;
    devExt = (PC2P_DEV_EXT)DeviceObject->DeviceExtension;
    PoStartNextPowerIrp (Irp);
    IoSkipCurrentIrpStackLocation (Irp);
    return PoCallDriver (devExt->LowerDeviceObject, Irp);
}

NTSTATUS c2pPnp(IN PDEVICE_OBJECT DeviceObject
    , IN PIRP Irp)
{
    PC2P_DEV_EXT devExt;
    PIO_STACK_LOCATION irpStack;
    NTSTATUS status = STATUS_SUCCESS;
    KIRQL oldIrql;
    KEVENT event;

    devExt = (PC2P_DEV_EXT)DeviceObject->DeviceExtension;
    irpStack = IoGetCurrentIrpStackLocation (Irp);

    switch (irpStack->MinorFunction)
    {
    case IRP_MN_REMOVE_DEVICE:
        KdPrint(("IRP_MN_REMOVE_DEVICE\n"));
        IoSkipCurrentIrpStackLocation (Irp);
        IoCallDriver(devExt->LowerDeviceObject, Irp);
        IoDetachDevice (devExt->LowerDeviceObject);
        IoDeleteDevice (DeviceObject);
        return STATUS_SUCCESS;
    default: 
        // 對於其他型別的IRP,全部都直接下發即可。 
        IoSkipCurrentIrpStackLocation(Irp); 
        status = IoCallDriver(devExt->LowerDeviceObject, Irp); 
    }
    return status;
}

NTSTATUS c2pAttachDevices(
    IN PDRIVER_OBJECT DriverObject
    , IN PUNICODE_STRING RegistryPath)
{
    NTSTATUS status = 0;
    UNICODE_STRING uniNtNameString;
    PC2P_DEV_EXT devExt;
    PDEVICE_OBJECT pFilterDeviceObject = NULL;
    PDEVICE_OBJECT pTargetDeviceObject = NULL;
    PDEVICE_OBJECT pLowerDeviceObject = NULL;

    PDRIVER_OBJECT KbdDriverObject = NULL;

    KdPrint(("MyAttach!\n"));
    // 初始化Kdbclass驅動的名字。
    RtlInitUnicodeString (&uniNtNameString, KBD_DRIVER_NAME);
	// 開啟驅動物件
    status = ObReferenceObjectByName(&uniNtNameString
        , OBJ_CASE_INSENSITIVE
        , NULL
        , 0
        , *IoDriverObjectType
        , KernelMode
        , NULL
        , &KbdDriverObject);
	// 如果失敗了就直接返回
    if (!NT_SUCCESS(status))
    {
        KdPrint(("MyAttach: couldn't get the MyTest Device Object\n"));
        return status;
    }
    else
    {
		// 這個開啟需要解引用。早點解除了免得之後忘記。
        ObDereferenceObject(DriverObject);
    }
	// 裝置鏈中的第一個裝置	
    pTargetDeviceObject = KbdDriverObject->DeviceObject;
	// 遍歷這個裝置鏈
    while (pTargetDeviceObject)
    {
		// 生成一個過濾裝置
        status = IoCreateDevice (DriverObject
            , sizeof(C2P_DEV_EXT)
            , NULL
            , pTargetDeviceObject->DeviceType
            , pTargetDeviceObject->Characteristics
            , FALSE
            , &pFilterDeviceObject);
		// 如果失敗了就直接退出。
        if (!NT_SUCCESS(status))
        {
            KdPrint(("MyAttach: couldn't create the MyFilter Filter Device Object!\n"));
            return status;
        }
		// 繫結。pLowerDeviceObject是繫結之後得到的下一個裝置。
        // 也就是所謂真實裝置。
        pLowerDeviceObject = IoAttachDeviceToDeviceStack (pFilterDeviceObject, pTargetDeviceObject);
         // 如果繫結失敗了,放棄之前的操作,退出。
		if (!pLowerDeviceObject)
        {
            KdPrint(("MyAttach: couldn't attach to MyTest Device Object!\n"));
            IoDeleteDevice(pFilterDeviceObject);
            pFilterDeviceObject = NULL;
            return status;
        }
		// 取到裝置擴充套件
        devExt = (PC2P_DEV_EXT)(pFilterDeviceObject->DeviceExtension);
        c2pDevExtInit (devExt
            , pFilterDeviceObject
            , pTargetDeviceObject
            , pLowerDeviceObject);
        pFilterDeviceObject->DeviceType = pLowerDeviceObject->DeviceType;
        pFilterDeviceObject->Characteristics = pLowerDeviceObject->Characteristics;
        pFilterDeviceObject->StackSize = pLowerDeviceObject->StackSize+1;

        pFilterDeviceObject->Flags |= pLowerDeviceObject->Flags 
            & (DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_PAGABLE);
        pTargetDeviceObject = pTargetDeviceObject->NextDevice;

    }

    return status;
}

NTSTATUS c2pDevExtInit(IN PC2P_DEV_EXT devExt
    , IN PDEVICE_OBJECT pFilterDeviceObject
    , IN PDEVICE_OBJECT pTargetDeviceObject
    , IN PDEVICE_OBJECT pLowerDeviceObject)
{
    memset (devExt, 0, sizeof(C2P_DEV_EXT));
    devExt->NodeSize = sizeof(C2P_DEV_EXT);
    devExt->pFilterDeviceObject = pFilterDeviceObject;
    devExt->TargetDeviceObject = pTargetDeviceObject;
    devExt->LowerDeviceObject = pLowerDeviceObject;
    KeInitializeSpinLock (&(devExt->IoRequestsSpinLock));
    KeInitializeEvent(&(devExt->IoInProgressEvent), NotificationEvent, FALSE); 
    return STATUS_SUCCESS;
}

// WIN7解除安裝的時候會導致電腦藍屏重啟。新手不知道什麼原因。
VOID c2pUnload(IN PDRIVER_OBJECT DriverObject)
{
    PDEVICE_OBJECT DeviceObject;
    PDEVICE_OBJECT OldDeviceObject;
    PC2P_DEV_EXT devExt;
    LARGE_INTEGER lDelay;
    PRKTHREAD Currentthread;

    lDelay = RtlConvertLongToLargeInteger (100* DELAY_ONE_MILLISECOND);
    Currentthread = KeGetCurrentThread ();

    KeSetPriorityThread (Currentthread, LOW_REALTIME_PRIORITY);

    UNREFERENCED_PARAMETER(DeviceObject);
    KdPrint(("DriverEntry unLoading...\n"));

    DeviceObject = DriverObject->DeviceObject;
    while (DeviceObject)
    {
        c2pDetach(DeviceObject);
        DeviceObject = DeviceObject->NextDevice;
    }
    ASSERT(NULL == DriverObject->DeviceObject);
    while (gC2pKeyCount)
    {
        KeDelayExecutionThread (KernelMode, FALSE, &lDelay);
    }
    KdPrint(("DriverEntry unLoad Ok!\n"));
    return ;
}



NTSTATUS c2pReadComplete(IN PDEVICE_OBJECT DeviceObject
    , IN PIRP Irp
    , IN PVOID Context)
{
    PIO_STACK_LOCATION Irpsp;
    ULONG buf_len = 0;
    PUCHAR buf = NULL;
    size_t i;
    Irpsp = IoGetCurrentIrpStackLocation (Irp);

    if (NT_SUCCESS(Irp->IoStatus.Status))
    {
        buf = Irp->AssociatedIrp.SystemBuffer;
        buf_len = Irp->IoStatus.Information;
        for (i =0; i < buf_len; ++i)
        {
            DbgPrint("ctrl2cap: %2x\r\n", buf[i]);
        }
    }
    gC2pKeyCount--;
    if (Irp->PendingReturned)
    {
        IoMarkIrpPending (Irp);
    }
    return Irp->IoStatus.Status;
}

VOID c2pDetach(IN PDEVICE_OBJECT pDeviceObject) 
{ 
    PC2P_DEV_EXT devExt; 
    BOOLEAN NoRequestsOutstanding = FALSE; 
    devExt = (PC2P_DEV_EXT)pDeviceObject->DeviceExtension; 
    __try 
    { 
        __try 
        { 
            IoDetachDevice(devExt->TargetDeviceObject);
            devExt->TargetDeviceObject = NULL; 
            IoDeleteDevice(pDeviceObject); 
            devExt->pFilterDeviceObject = NULL; 
            DbgPrint(("Detach Finished\n")); 
        } 
        __except (EXCEPTION_EXECUTE_HANDLER){} 
    } 
    __finally{} 
    return; 
}!IF 0

Copyright (C) Microsoft Corporation, 1997 - 1999

Module Name:

    sources.

!ENDIF

TARGETNAME=ctrl2cap
TARGETPATH=obj
TARGETTYPE=DRIVER

SOURCES =ctrl2cap.c!IF 0

Copyright (C) Microsoft Corporation, 1997 - 1998

Module Name:

    makefile.

!ENDIF

#
# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source
# file to this component.  This file merely indirects to the real make file
# that is shared by all the components of Windows NT
#

#
# if building in a DDK environment
#
!IF defined(DDK_TARGET_OS)

#
# ensure that said build environment is at least Windows XP
# 0x500 == Windows 2000
# 0x501 == Windows XP
# 0x502 == Windows .NET
#
!    IF defined(_NT_TARGET_VERSION) && $(_NT_TARGET_VERSION)>=0x501
!        INCLUDE $(NTMAKEENV)\makefile.def
!    ELSE
!        message BUILDMSG: Warning : The sample "$(MAKEDIR)" is not valid for the current OS target.
!    ENDIF

!ELSE

#
# not a DDK environment, probably RAZZLE, so build
#
!    INCLUDE $(NTMAKEENV)\makefile.def

!ENDIF