심플스 - 프로그램과 책 이야기로 가득한 곳, (Simples.Kr)

  


   심플스 배너



IRP Hook

Windows Research 조회 수 3985 추천 수 0 2010.09.04 10:02:46
 

간단한 IRP Hook 코드입니다.
해당 코드에 일부를 수정하여 다른 IRP를 손쉽게 훅킹할 수 있습니다.
보통 저에 경우에는 다른 드라이버에 대한 값을 모니터링 할 때 많이 사용합니다.

예제코드는 ATAPI.sys에 IRP_MJ_SCSI를 훅킹하고 있고 Cdb를 출력합니다.
Cdb와 SCSI에 대한 설명은 IRP Hook 범위를 넘어가므로 이에 대한 설명을 하지 않겠습니다.

개인적으로 만든 코드라서 개인적인 루틴도 추가되었습니다.
예를 들어 IRP 핸들러 시작부분과 끝부분에 g_IRPEnterCount변수 사용 및
IRPUnhook 시 이 변수를 체크합니다.
이는 드라이버 동적 언로드 시 극악의 확률로 발생가능한 동기화문제를 막기 위해서입니다.



#include <Wdm.h>
#include <Scsi.h>

PDEVICE_OBJECT g_HookDeviceObject = NULL;
PDRIVER_DISPATCH g_OrgHandler = NULL;
UCHAR g_HookMajorFunctionIndex = 0xFF;

LONG g_IRPEnterCount = 0;

PDEVICE_OBJECT MyIoGetDeviceObjectPointer(__in WCHAR *DeviceObjectName, __in BOOLEAN bRelated);

BOOLEAN IrpHook(__in PDEVICE_OBJECT DeviceObject, __in UCHAR MajorFunctionIndex, __out PDRIVER_DISPATCH *pOrgHandler, PDRIVER_DISPATCH pNewHandler);
BOOLEAN IrpHookFormName(__in WCHAR *DeviceObjectName, __in UCHAR MajorFunctionIndex, __out PDRIVER_DISPATCH *pOrgHandler, PDRIVER_DISPATCH pNewHandler);

VOID IrpUnhook();

NTSTATUS NewIrpHandler(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp);

PDEVICE_OBJECT MyIoGetDeviceObjectPointer(__in WCHAR *DeviceObjectName, __in BOOLEAN bRelated)
{
    NTSTATUS ntStatus;
    PFILE_OBJECT FileObject;
    PDEVICE_OBJECT DeviceObject;
    UNICODE_STRING Name;

    OBJECT_ATTRIBUTES ObjectAttributes;
    HANDLE FileHandle;
    IO_STATUS_BLOCK IoStatus;

    DeviceObject = NULL;

    RtlInitUnicodeString(&Name, DeviceObjectName);
    if (bRelated == TRUE)
    {
        // IoGetDeviceObjectPointer는 내부적으로 IoGetRelatedDeviceObject 함수를 호출합니다.
        // 따라서 DeviceObjectName 에 해당하는 디바이스 오브젝트 포인터를 얻어오는게 아니라
        // 해당 디바이스 오브젝트에 대한 최상위 디바이스 오브젝트를 얻어옵니다.
        ntStatus = IoGetDeviceObjectPointer(&Name, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject);
        if (NT_SUCCESS(ntStatus) == TRUE)
        {
            return DeviceObject;
        }
        else
        {
            return NULL;
        }
    }
    else
    {
        // 실제 해당 이름을 가진 디바이스 오브젝트를 얻옵니다.
        InitializeObjectAttributes(&ObjectAttributes,
                                    &Name,
                                    0,
                                    (HANDLE) NULL,
                                    (PSECURITY_DESCRIPTOR)NULL);

        ntStatus = ZwOpenFile(&FileHandle,
                             FILE_READ_ATTRIBUTES,
                             &ObjectAttributes,
                             &IoStatus,
                             0,
                             FILE_NON_DIRECTORY_FILE);

        if (NT_SUCCESS(ntStatus) == FALSE)
        {
            // 해당 디바이스 오브젝트를 열 수 없습니다.
            return NULL;
        }

        ntStatus = ObReferenceObjectByHandle(FileHandle,
                                                                0,
                                                                *IoFileObjectType,
                                                                KernelMode,
                                                                (PVOID *)&FileObject,
                                                                NULL);

        if (NT_SUCCESS(ntStatus) == TRUE)
        {
            // Windows 2000 소스코드 참고
            // 실제 내부 구현도 이와 비슷하게 되어 있습니다.

            //
            // If the file object was taken out against the mounted file system, it
            // will have a Vpb. Traverse it to get to the DeviceObject. Note that in
            // this case we should never follow FileObject->DeviceObject, as that
            // mapping may be invalid after a forced dismount.
            //
            if (FileObject->Vpb != NULL && FileObject->Vpb->DeviceObject != NULL)
            {
                DeviceObject = FileObject->Vpb->DeviceObject;
                //
                // If a driver opened a disk device using direct device open and
                // later on it uses IoGetRelatedTargetDeviceObject to find the
                // device object it wants to send an IRP then it should not get the
                // filesystem device object. This is so that if the device object is in the
                // process of being mounted then vpb is not stable.
                //

            }
            else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) &&
                       FileObject->DeviceObject->Vpb != NULL &&
                       FileObject->DeviceObject->Vpb->DeviceObject != NULL)
            {

                DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject;
                //
                // This is a direct open against the device stack (and there is no mounted
                // file system to strain the IRPs through).
                //

            }
            else
            {
                DeviceObject = FileObject->DeviceObject;
            }
            ZwClose(FileHandle);

            return DeviceObject;
        }
        else
        {
            ZwClose(FileHandle);

            return NULL;
        }
    }
}

VOID DriverUnload(__in PDRIVER_OBJECT DriverObject)
{
    KdPrint(("Driver unload.\n"));

    // 드라이버 언로드 루틴에서 호출됩니다.
    IrpUnhook(TRUE);
}

BOOLEAN IrpHook(__in PDEVICE_OBJECT DeviceObject, __in UCHAR MajorFunctionIndex, __out PDRIVER_DISPATCH *pOrgHandler, PDRIVER_DISPATCH pNewHandler)
{
    g_IRPEnterCount = 0;

    *pOrgHandler = DeviceObject->DriverObject->MajorFunction[MajorFunctionIndex];
    if (*pOrgHandler == NULL)
    {
        return FALSE;
    }

    g_HookDeviceObject = DeviceObject;
    g_HookMajorFunctionIndex = MajorFunctionIndex;

    InterlockedExchangePointer(&(DeviceObject->DriverObject->MajorFunction[MajorFunctionIndex]), pNewHandler);

    return TRUE;
}

BOOLEAN IrpHookFormName(__in WCHAR *DeviceObjectName, __in UCHAR MajorFunctionIndex, __out PDRIVER_DISPATCH *pOrgHandler, PDRIVER_DISPATCH pNewHandler)
{
    PDEVICE_OBJECT DeviceObject;

    DeviceObject = MyIoGetDeviceObjectPointer(DeviceObjectName, FALSE);
    if (DeviceObject != NULL)
    {
        return (IrpHook(DeviceObject, MajorFunctionIndex, pOrgHandler, pNewHandler));
    }
    else
    {
        return FALSE;
    }
}

VOID IrpUnhook(BOOLEAN DriverUnloadRoutine)
{
    if ((g_HookDeviceObject == NULL)
        || (g_OrgHandler == NULL))
    {
        KdPrint(("Not hooked.\n"));
    }
    else
    {
        // IRP 핸들러를 원래의 핸들러로 되돌려줍니다.
        InterlockedExchangePointer(&(g_HookDeviceObject->DriverObject->MajorFunction[g_HookMajorFunctionIndex]), g_OrgHandler);

        if (DriverUnloadRoutine == TRUE)
        {
            LARGE_INTEGER WaitTime;

            WaitTime.QuadPart = -1 * 10 * 1000 * 1000;

            //
            // 드라이버 언로드 루틴에서 이 함수가 호출되었다면
            // InterlockedExchangePointer 후에 바로 드라이버가 언로드 되므로
            // 이 때 InterlockedExchangePointer를 하기전에 훅킹 핸들러가 실행되었고
            // 그 후에 InterlockedExchangePointer함수가 리턴하게 되면
            // 훅킹 핸들러를 원래대로 되돌려주었지만 현재 루틴이 실행중일 수 있으므로 이에 대한 동기화 처리를
            // 진행합니다.
            //

            while (g_IRPEnterCount > 0)
            {
                // 현재 훅킹루틴이 실행중에 있으므로 잠시 대기합니다.
                KeDelayExecutionThread(KernelMode ,FALSE, &WaitTime);
            }
            // 마지막으로 한 번 더 대기합니다.
            KeDelayExecutionThread(KernelMode ,FALSE, &WaitTime);
        }
    }
}

NTSTATUS NewIrpHandler(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp)
{
    NTSTATUS ntStatus;

    // 동기화를 위한 전역 카운트를 증가시킵니다.
    InterlockedIncrement(&g_IRPEnterCount);

    // 디바이스 오브젝트에 대한 필터링을 하였지만 상황에 따라 하지 않아야 할 수도 있습니다.
    if (DeviceObject == g_HookDeviceObject)
    {
        // 우리가 원하는 DeviceObject에서 발생한 Irp입니다.
        PIO_STACK_LOCATION pIoStackLocation;

        pIoStackLocation = IoGetCurrentIrpStackLocation(Irp);
        if (pIoStackLocation->MajorFunction == g_HookMajorFunctionIndex)
        {
            //
            // 이곳에 원하는 코드를 작성합니다.
            // 예제코드에서는 간단히 CDB에 대해서 출력하겠습니다.
            //
            KdPrint(("DeviceObject : %p, Cdb : %#x\n", DeviceObject, pIoStackLocation->Parameters.Scsi.Srb->Cdb[0]));
        }
    }
    ntStatus = g_OrgHandler(DeviceObject, Irp);

    // 동기화를 위한 전역 카운트를 감소합니다.
    InterlockedDecrement(&g_IRPEnterCount);

    return (ntStatus);
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
    NTSTATUS ntStatus;
    PDEVICE_OBJECT DeviceObject;

    // 드라이버가 언로드 될 수 있도록 합니다.
    DriverObject->DriverUnload = DriverUnload;

    // 예제로 훅킹하는 디바이스는 하드 디스크입니다.
    // ( 실제 하드 디스크에 섹터를 읽어주는 디바이스입니다. )
    //
    // 해당 디바이스 이름은 시스템에 따라서 다릅니다.
    // IRP_MJ_SCSI 를 훅킹합니다.
    if (IrpHookFormName(L"\\Device\\Ide\\IdeDeviceP1T0L0-17", IRP_MJ_SCSI, &g_OrgHandler, NewIrpHandler) == TRUE)
    {
        KdPrint(("IrpHookFormName successed.\n"));
    }
    else
    {
        KdPrint(("IrpHookFormName failed.\n"));
    }

    return STATUS_SUCCESS;
}

List of Articles
번호 제목 글쓴이 날짜 조회 수
162 Windows Research SCSI Miniport - IOCTL_SCSI_PASS_THROUGH_DIRECT ( ... [레벨:6]lain 2011-06-11 3340
161 Windows Research 커널레벨에서 IAT Hook [레벨:6]lain 2011-06-11 3997
160 Windows Research DEVICE_OBJECT에 대한 보안 디스크립터 변경 [레벨:6]lain 2011-06-11 2919
159 Windows Research IE Cache 경로 변경하기 [레벨:6]lain 2011-06-09 3017
158 Windows Research 32Bit 윈도우즈에서 실제 물리메모리크기 얻어오기 [레벨:6]lain 2011-06-09 3174
157 Windows Research VMWare 탐지 기법 우회 - 2 [2] [레벨:6]lain 2011-04-04 8345
156 Linux Tip 우분투에 IRC서버 설치후 닉네임 길이와 동접자 조절. [1] [레벨:0]오랑캐꽃 2010-11-26 5566
155 Linux Tip VirtualBox에 우분투 설치 후에 내부 네트워크 접속 설정하기 file [레벨:8]esniper 2010-09-10 11574
154 Linux Tip VirtualBox에서 오른쪽 CTRL키 사용하기(VitualBox 호스트키) file [2] [레벨:8]esniper 2010-09-10 5805
153 Linux Tip 우분투 설치 후 putty에서 한글 안 깨지도록 설정하기 file [레벨:8]esniper 2010-09-10 6070
152 Linux Tip 우분투 ssh or mysql 서버 접속지연이 있는 경우 해결책 [레벨:8]esniper 2010-09-10 5948
151 문서자료 고품질의 무료 아이콘들 [3] [레벨:8]esniper 2010-09-08 7079
150 Windows Research Sysinternals - Filemon source code file [5] [레벨:6]lain 2010-09-04 5602
149 Windows Research Sysinternals - Regmon source code file [1] [레벨:6]lain 2010-09-04 5271
148 Windows Research PostQueuedCompletionStatus 함수에 실패 여부도 고려해야 할까... [레벨:6]lain 2010-09-04 4442
147 Windows Research SetEvent 함수는 언제 실패할까? [레벨:6]lain 2010-09-04 5244
146 Windows Research 커널모드 드라이버에서 사용하는 시간관련 매크로 [레벨:6]lain 2010-09-04 4257
145 Windows Research 화면캡쳐방지는 어떻게 구현될까? [3] [레벨:6]lain 2010-09-04 8199
144 Windows Research IRP Completion Hook file [레벨:6]lain 2010-09-04 3770
» Windows Research IRP Hook [레벨:6]lain 2010-09-04 3985

  • 이용약관
  • 개인정보취급방침
  • 사이트맵