Table of Contents

Introduction

Windows Device Driver 작성에 대한 내용을 정리하였다.


FileSystem Filter Driver

미니필터 드라이버를 작성하여 파일에 접근하는 프로세스를 알아낼 수 있다.

Basic Example

typedef PCHAR(*GET_PROCESS_IMAGE_NAME)(PEPROCESS Process);
GET_PROCESS_IMAGE_NAME PsGetProcessImageFileName;

// 어떤 Major Functon 에 대한 콜백함수라 치자.
FLT_PREOP_CALLBACK_STATUS FsFilterPreOperation(
       _Inout_ PFLT_CALLBACK_DATA Data,
       _In_ PCFLT_RELATED_OBJECTS FltObjects,
       _Flt_CompletionContext_Outptr_ PVOID *CompletionContext)
{
       /********************************************************************
       * PsGetProcessImageFileName() 함수는 숨겨져 있다. 아래와 같이 찾아보자
       ********************************************************************/
       UNICODE_STRING funtion_str = RTL_CONSTANT_STRING(L"PsGetProcessImageFileName");
#pragma warning(push)
#pragma warning(disable : 4055) // type cast warning
       PsGetProcessImageFileName = (GET_PROCESS_IMAGE_NAME)MmGetSystemRoutineAddress(&funtion_str);
#pragma warning(pop)
       if (NULL != PsGetProcessImageFileName)
       {
              PCHAR pImageName = PsGetProcessImageFileName(IoThreadToProcess(Data->Thread));
              if (NULL != pImageName)
              {
                     DbgPrint("Process Image Name : %s\n", pImageName); // cmd.exe 이렇게 나온다.
              }
       }


       /********************************************************************
       * 접근하려 했던 파일 정보에 대해 찾아보자
       * 다만, 언제 이 콜백이 호출되었느냐에 따라 파일 정보를 볼 수 없기도 하다.
       * 게다가 BSOD 를 유발하기도 한다.
       ********************************************************************/
       PFLT_FILE_NAME_INFORMATION nameInfo;
       NTSTATUS status;
       status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED, &nameInfo);
       if (NT_SUCCESS(status))
       {
              // 아래 함수로 파싱하지 않으면 보이지 않는 필드가 몇개 있다. 필수적인 사항은 아니다.
              FltParseFileNameInformation(nameInfo);
              // FLT_FILE_NAME_SHORT 일 때는 안 보이는가? 글쎄?
              if (nameInfo->Format != FLT_FILE_NAME_SHORT)
              {
                     DbgPrint("%wZ\n", nameInfo->Name);
                     DbgPrint("%wZ\n", nameInfo->Volume);    // same as FltObjects->Volume
                     DbgPrint("%wZ\n", nameInfo->Extension); // Only available after FltParseFileNameInformation()
              }
              FltReleaseFileNameInformation(nameInfo);
       }


       /********************************************************************
       * 위의 PsGetProcessImageFileName() 에서 이미 나왔지만...
       * Process 관련 정보를 찾는 함수들을 몇가지 살펴보자.
       * Mini-filter 의 경우 FltXXX() 이고 일반 Filter 는 IoGetXXX() 이렇게 되는 듯
       ********************************************************************/
       ULONG pid = FltGetRequestorProcessId(Data);
       PEPROCESS objProcess = IoThreadToProcess(Data->Thread);
       HANDLE hPid = PsGetProcessId(objProcess); // 이 return 값(HANDLE)과 FltGetRequestorProcessId() 의 return 값(ULONG)은 같다

       return FLT_PREOP_SUCCESS_WITH_CALLBACK;
}

참고할 함수들

PsLookupProcessByProcessId();
IoGetRequestorProcess();
IoGetRequestorProcessId();
IoGetRequestorSessionId();
IoQueryFileDosDeviceName();
RtlVolumeDeviceToDosName();


Table of Contents