|
글 수 163
ZwQueryInformationFile을 비동기 파일핸들로 호출 시 STATUS_PENDING을 리턴할까?Windows Research 조회 수 5993 추천 수 0 2010.09.03 17:32:38( 주의 : 이 글에서 디스어셈블리되는 커널은 Windows XP SP2 이며 . ZwQueryInformationFile호출시
FileStandardInformation를 사용하였으므로 다른 인자를 사용하였다면 결과가 다르게 나타날 수 있습니다. ) ZwCreateFile을 이용해 파일 핸들을 열 때 비동기적으로 열어야 하는 경우가 생겼습니다. 이러한 경우 ZwReadFile로 파일을 읽을 때 두 번째 인자인 Event객체를 사용하여 WaitForSingleObject로 대기해야 하는 것으로 알고 있습니다. 그 러나 ZwQueryInformationFile에 경우에는 Event객체가 존재하지 않습니다. 그렇다면 윈도우즈 내부에서KeWaitForSingleObject을 호출 할 수도 있고 ( 만약에 비동기 모드로 파일의 핸들을 열었다면.. ),KeWaitForSingleObject 호출하지 않고 STATUS_PENDING을 리턴 할수도 있습니다. 내부적인 부분이라 알 수가 없고 STATUS_PENDING 리턴여부를 확실히 알아야 하기 때문에 WinDbg로 디버깅을 해보았습니다. 우선 파일을 비동기 모드로 연 후 ZwQueryInformationFile을 호출하기 바로 전에 브레이크 포인트를 걸어둡니다. ZwQueryInformationFile은 내부적으로 NtQueryInformationFile 파일을 호출할 것이므로 다음과 같은 WinDbg명령줄을 이용해 브레이크 포인트를 겁니다. bp nt!NtQueryInformationFile 그리고 F5를 눌러서 한 번 실행시킵니다. 위에 그림에서 보는 위치에서 멈추게 됩니다. 중요한건 콜스택을 잘 확인하여 내 드라이버에서 호출한 것이 맞는지 반드시 확인해보아야 합니다. ( 간혹 내 드라이버에서 호출하지 않은 경우가 있을 수 있습니다. ) F11를 눌르거나 계속해서 디버깅을 해보면 결국엔 IRP를 전송하기 위해 nt!IofCallDriver를 호출하게 되므로 bp nt!IofCallDriver 를 이용하여 다시 브레이크 포인트를 겁니다. 그리고 다시 F5를 누릅니다. 위와 마찬가지로 반드시 콜스택을 확인하여 내 드라이버에서 호출했는지 확인을 합니다. 이 상태에서 콜 스택을 보게 되면 이 함수를 호출 후 리턴되는 주소를 확인 할 수 있습니다. 그림에서 하이라이트 된 부분이 리턴되는 주소이며 해당 주소에 디스어셈블리 된 코드를 보면 다음과 같습니다. 위에서 보시면 KeWaitForSingleObject라는 함수를 어떠한 조건의 의해서 호출한다는 것을 알 수 있습니다. 8057bc3c 8b4dd4 mov ecx,dword ptr [ebp-2Ch] 8057bc3f e87452f7ff call nt!IofCallDriver (804f0eb8) 8057bc44 8945d8 mov dword ptr [ebp-28h],eax 8057bc47 817dd803010000 cmp dword ptr [ebp-28h],103h 8057bc4e 0f85cc000000 jne nt!NtQueryInformationFile+0x528 (8057bd20) 8057bc54 807de700 cmp byte ptr [ebp-19h],0 8057bc58 745e je nt!NtQueryInformationFile+0x4c0 (8057bcb8) 8057bc5a 33ff xor edi,edi 8057bc5c 57 push edi 8057bc5d 8b45dc mov eax,dword ptr [ebp-24h] 8057bc60 8b482c mov ecx,dword ptr [eax+2Ch] 8057bc63 c1e902 shr ecx,2 8057bc66 81e101ffffff and ecx,0FFFFFF01h 8057bc6c 51 push ecx 8057bc6d ff75cc push dword ptr [ebp-34h] 8057bc70 57 push edi 8057bc71 83c05c add eax,5Ch 8057bc74 50 push eax 8057bc75 e8300ff8ff call nt!KeWaitForSingleObject (804fcbaa) 이 부분은 IofCallDriver에 리턴값을 넣는 부분입니다. 리턴값은 NTSTATUS일 것 입니다. 8057bc44 8945d8 mov dword ptr [ebp-28h],eax 그 후에 다음과 같이 0x103값과 비교하는데 이 값은 8057bc47 817dd803010000 cmp dword ptr [ebp-28h],103h 다음과 같이 정의되어 있습니다. #define STATUS_PENDING ((NTSTATUS)0x00000103L) // winnt 즉, Pending여부를 체크한다는 것을 알 수 있습니다. Pending이 아니라면 8057bd20주소로 점프하게 됩니다. Pedning이라면 다시 밑에서 무언가를 비교하게 되는데 byte ptr [ebp-19h]에 있는 이 값에 따라서 KeWaitForSingleObject를 호출할지 말지를 결정하게 됩니다. 중요한 것은 제 경우 테스트할 때 이 값은 0이 아니었으며 따라서 KeWaitForSingleObject를 호출하는 코드를 실행하게 됩니다. 또한 IofCallDriver호출 후 리턴한 후 강제적으로 eax레지스터에 STATUS_PENDING를 넣게 되면 KeWaitForSingleObject를 호출하게 됩니다. 참고로 만약 파일핸들을 동기화 모드로 열었다면 위에서 말한 코드 부분이 실행되지 않습니다. 결론은 ZwQueryInformationFile를 비동기 파일핸들로 호출 시에 내부적으로 STATUS_PENDING 여부를 체크하여 KeWaitForSingleObject로 대기합니다. 또한 ReactOS소스코드를 보시면 위와 비슷하게 구현되어 있는 것을 볼 수 있습니다. 물론 실제 윈도우즈 코드와 ReactOS소스코드가 완전히 같지는 않다는 것에 주의해야 할 것입니다. |


