ZwCreateFile() 이 실패하는 이유.. 시스템 프로그래밍

오늘 참... 어이없는 삽질을 했습니다. (사실 요즘 삽질의 연속이긴합니다만 ㅠ.ㅠ )
아주 간단한 드라이버를 두개를 작성하고, 하나의 드라이버에서 다른 드라이버를 오픈하는 코드를 작성했지요.

오픈의 대상이 되는 드라이버의 코드는 아래와 같고요.. 빌드해서 로드하면 \Device\Callee 오브젝트를 만듭니다.
참고로.. 아래 코드에서 "중간생략" 된 코드는 없고, 컴파일 되는 코드 그대로입니다. :-)

extern "C"
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
KdPrint( (CALLEE_CALLEE_DRIVER_NAME" %s \n", __FUNCTION__) );

// device 생성
//
PDEVICE_OBJECT DeviceObject = NULL;
UNICODE_STRING DeviceName;
RtlInitUnicodeString(&DeviceName, L"\\Device\\Callee");
NTSTATUS status = IoCreateDevice(
DriverObject,
sizeof(DEVICE_EXTENSION),
&DeviceName,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
TRUE,
&DeviceObject
);
if (FALSE == NT_SUCCESS(status))
{
KdPrint( (CALLEE_CALLEE_DRIVER_NAME" IoCreateDevice(), status=0x%08x \n", status) );
return status;
}

// initialize MajorFunctions
//
DriverObject->DriverUnload = Unload;

return STATUS_SUCCESS;
}


Callee 드라이버를 오픈하는 드라이버의 코드는 아래와 같습니다.


extern "C"
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
KdPrint( (CALLER_CALLEE_DRIVER_NAME" %s \n", __FUNCTION__) );

NTSTATUS status=STATUS_UNSUCCESSFUL;

DriverObject->DriverUnload = Unload;

// Open Callee device
//
HANDLE hCallee = NULL;
IO_STATUS_BLOCK iostatus;
OBJECT_ATTRIBUTES oa;
UNICODE_STRING uCalleeDeviceName;
RtlInitUnicodeString(&uCalleeDeviceName, L"\\Device\\Callee");
InitializeObjectAttributes(
&oa,
&uCalleeDeviceName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
status = ZwCreateFile(
&hCallee,
GENERIC_ALL,
&oa,
&iostatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE/*| FILE_SHARE_DELETE*/,
FILE_OPEN_IF,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
if(!NT_SUCCESS(status))
{
KdPrint((
"%s, ZwCreateFile(%wZ) failed, status=0x%08x \n",
__FUNCTION__, &uCalleeDeviceName, status
));
return status;
}

// Close Callee device
//
ZwClose(hCallee);

return STATUS_SUCCESS;
}
당연히 잘 되겠지 했는데 계속 ZwCreateFile() 함수가 오류를 뱉어내더군요.ㅜㅜ
WinObj 로 봐도 분명히 \Device\Callee 가 만들어져 있는데도요..
별의 별짓을 다 하다.. 갑자기 아차차~!!! 싶더군요.

대체 왜 ZwCreateFile() 이 에러를 뱉어냈을까요?? 퀴즈입니다!!~!

답은 아래에 있습니다.




































정답 나갑니다. :-)
ZwCreateFile()  이 실패했던 이유는 Create 핸들러가 없어서 그렇습니다. -_-;;
이러니 Open 이 안되는것이겠죠. ㅎㅎ 간단하죠?
코드를 작성할때 대부분 기존 사용하던 템플릿 코드를 그대로 재사용하기 때문에 이런 어처구니 없는 실수를 하게 만드는것 같습니다. 




NTSTATUS __stdcall DispatchCreateClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);

/** ---------------------------------------------------------------------------
\brief

\param
\return
\code
\endcode
-----------------------------------------------------------------------------*/
extern "C"
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
KdPrint( (CALLEE_CALLEE_DRIVER_NAME" %s \n", __FUNCTION__) );

// device 생성
//
PDEVICE_OBJECT DeviceObject = NULL;
UNICODE_STRING DeviceName;
RtlInitUnicodeString(&DeviceName, L"\\Device\\Callee");
NTSTATUS status = IoCreateDevice(
DriverObject,
sizeof(DEVICE_EXTENSION),
&DeviceName,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
TRUE,
&DeviceObject
);
if (FALSE == NT_SUCCESS(status))
{
KdPrint( (CALLEE_CALLEE_DRIVER_NAME" IoCreateDevice(), status=0x%08x \n", status) );
return status;
}

// initialize MajorFunctions
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchCreateClose;
DriverObject->DriverUnload = Unload;

return STATUS_SUCCESS;
}

/** ---------------------------------------------------------------------------
\brief 제가 범인이랍니다. ^^

\param
\return
\code
\endcode
-----------------------------------------------------------------------------*/
NTSTATUS __stdcall DispatchCreateClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
UNREFERENCED_PARAMETER(DeviceObject);
KdPrint( (CALLEE_CALLEE_DRIVER_NAME" %s \n", __FUNCTION__) );


// complete this irp !
//
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}




덧글

  • 이재홍 2009/08/13 23:12 # 삭제 답글

    IoCreateDevice의 6번째 매개변수 Exclusive가 TRUE이기 때문.
  • 멍멍이 2009/08/19 19:24 # 삭제 답글

    음..ㅋㅋ 드라이버가 만든 DACL에 부합하는 접근권한이
    app에는 없던걸까요? 위에분이 말씀하신건 뭐죠? 'ㅁ')?!
  • somma 2009/08/20 07:53 #

    권한문제는 아니고요.. ^^
    이재홍님께서 말씀하신 것은 exclusive 로 만들어진 device 의 경우 하나의 app 에서 핸들을 획득하면 다른 녀석이 오픈하지 못하게합니다.
    의도된 답은 아닙니다. :-)
  • 멍멍이 2009/08/20 13:05 # 삭제 답글

    아하 그것에 대해서 말한 것이군요,
    예전 부터 궁금했던 것중에 하나인데,
    exclusive flag와 Inherit flag를 같이 가지고 있는 securable object에
    handle을 child process 가 DuplicateHandle()을 하면 쓸 수 있을까요?
    기본적으로는, DulplicateHandle()을 하면, 특정 Object를 자신의 handle table로
    포인터 떙겨주고 레퍼런스 카운터를 올리는 것일텐데요,
    exclusive 속성 상 다른 한 프로세스에서 핸들을 획득하면,
    다른 녀석이 오픈하지 못한다 라는 말은 어쩌면 레퍼런스를 못하게 한다 일수도 있으니,
    DuplicateHandle()이 안된다면, 그냥 그 inherit 된 handle 그 자체는 쓸 수 있을테니
    되려나요? ㅎㅎ
  • somma 2009/08/20 23:28 # 삭제

    으흠.. 해보시고 알려주세요. ^^; 헤헤~
  • 양군 2009/09/22 01:04 # 답글

    지만이네나 여기나 역시나 여려분 얘기들뿐..^^;;
    술은 언제 마시는거래요?
  • somma 2009/09/25 11:59 # 삭제

    그러게 술한잔 해야 하는데...당췌 시간이 안나는 구만.. -_-;;
    추석 지나고 봅시다.~ ^^
  • 김종호 2009/09/22 17:58 # 삭제 답글

    안녕하세요 잘 지내시죠? ㅋㅋ

    한글을 보고 무슨말인지 모를때도 종종있는데 보안하시는 분들 코드가 딱 그런거 같아요

    분명 C 코드인데 이해가 안간다눈..;;;;
  • somma 2009/09/25 11:58 # 삭제

    쫑호~ 잘 지내고 있는감?
    난 그냥 정신없이 바쁘게 지내고 있어..
    뭐 나도 저 코드 보고 이해 잘 못하고 있으니..피장 파장이지..ㅋㅋㅋ
  • 2010/01/28 14:10 # 삭제 답글

    아핫~ 찾았당~
  • Ezbeat 2010/12/17 21:32 # 삭제 답글

    예전에 저도 유저어플과 드라이버간 통신을 하기위해 유저어플에서 드라이버 핸들을 얻어오는 작업 도중 이러한 현상을 겪었습니다..;
    몇 시간 삽질 후 책을 보니 핸들러 등록 하지 않은 IRP는 디폴트로 IO관리자에게 STATUS_INVALID_DEVICE_REQUEST 값을 주더군요;; 그 문제를 해결하고 나서 인터넷을 찾아보니 ... =_= 여기 딱 글이 있더군요;; 킁.. ㅠ

    아... 하나만 질문 드려봐도 될까요?? ^^;
    IRQL DISPATCH_LEVEL에서 동작하는 모듈이 있는데.. 그 모듈에서 ZwCreateFile ( IRQL = PASSIVE_LEVEL )을 호출할 수 있는 방법이 있을까요..?;; 제 생각엔 DISPATCH_LEVEL에서 스케쥴링 가능한 함수를 호출해버려서 안되는거 같은데...ㅠㅠ
    도움 부탁드려볼께요.. : )
  • somma 2010/12/20 09:16 #

    일반적으로 그런경우에는 work item 이나 thread 를 만들어서 처리하죠.
    직접적으로 어떻게 해 볼 수 있는 방법은 제가 알기론 없습니다. :-)
댓글 입력 영역