Windows OS2011. 6. 20. 00:16
반응형
얼마전 경험한 황당한 일입니다.

파일시스템 필터 드라이버에서 IRP_MJ_CLEANUP 시점에 Irp->RequestorMode를 확인하는데 항상 KernelMode만 들어있는 것이었습니다. (Windows XP부터 Windows 7까지 모두 확인했는데도...)

콜스택은 아래와 같이 틀림없이 유저모드에서 CloseHandle()이 호출된 상황입니다.

1: kd> k
ChildEBP RetAddr  
f70d59f8 f73ef888 MyFilter!PreCleanup 
f70d5a58 f73f12a0 fltmgr!FltpPerformPreCallbacks+0x2d4
f70d5a6c f73f1c48 fltmgr!FltpPassThroughInternal+0x32
f70d5a88 f73f2059 fltmgr!FltpPassThrough+0x1c2
f70d5ab8 804f118f fltmgr!FltpDispatch+0x10d
f70d5ac8 f52b72b1 nt!IopfCallDriver+0x31
f70d5b48 805bea0a nt!IopCloseFile+0x26b
f70d5b7c 805be333 nt!ObpDecrementHandleCount+0xd8
f70d5ba4 805be3d1 nt!ObpCloseHandleTableEntry+0x14d
f70d5bec 805be509 nt!ObpCloseHandle+0x87
f70d5c00 f7772d8c nt!NtClose+0x1d
f70d5d58 7c93e4f4 nt!KiFastCallEntry+0xfc
00129638 7c93cfdc ntdll!KiFastSystemCallRet
0012963c 7c809c1b ntdll!ZwClose+0xc
00129648 01cf4ec8 kernel32!CloseHandle+0x51


전달된 Irp 내부를 들여다 봐도 명확히 RequestorMode가 0 (KernelMode)로 되어 있습니다.

1: kd> !irp 8621fa68 3
Irp is active with 10 stacks 10 is current (= 0x8621fc1c)
 No Mdl: No System Buffer: Thread 862e3650:  Irp stack trace.  
Flags = 00000404
ThreadListEntry.Flink = 862e3860
ThreadListEntry.Blink = 862e3860
IoStatus.Status = 00000000
IoStatus.Information = 00000000
RequestorMode = 00000000
...


어째서 RequestorMode가 KernelMode인 걸까요?

실제로 커널에서 어떤 요청이 있었던걸까요?
하지만 이때 ExGetPreviousMode()를 호출해 보면 UserMode가 나옵니다.

ExGetPreviousMode()함수의 구현을 보면 스레드 정보에서 PreviousMode를 구해 오는 것을 볼 수 있습니다.

1: kd> u ExGetPreviousMode
nt!ExGetPreviousMode:
8052d324 64a124010000    mov     eax,dword ptr fs:[00000124h]
8052d32a 8a8040010000    mov     al,byte ptr [eax+140h]
8052d330 c3              ret


그래서 현재 스레드를 구해서 실제로 확인해 보면

1: kd> .thread
Implicit thread is now 862e3650
 
1: kd> dt _KTHREAD PreviousMode 862e3650
ntdll!_KTHREAD
   +0x140 PreviousMode : 1 ''


0x140 옵셋에 있는 PreviousMode가 정확히 1 (UserMode)로 되어 있음을 확인할 수 있습니다.

도대체 이 무슨 해괴망측한 경우란 말입니까?

스레드에 저장된 PreviousMode는 UserMode인데 이 스레드에서 첫 번째로 처리되고 있는 Irp->RequestorMode는 KernelMode라니...

유저모드에서 CreateFile()을 호출해 필터 드라이버에서 IRP_MJ_CREATE를 받은 경우는 PreviousMode, Irp->RequestorMode 모두 UserMode로 정확히 나옵니다.
 
일단 여기서 알아둬야 할 점은 Thread의 PreviousMode와 Irp의 RequestorMode가 우리의 예상과 다를 수 있다는 점입니다.

IRP_MJ_CLEANUP(CLOSE)시의 Irp->RequestorMode는 항상 KernelMode라는 것은 이번에 확실히 알았으니 앞으로 주의해서 사용해야 하겠습니다.

반응형
Posted by GreeMate