디스크 볼륨이 ReadOnly인지 확인할 필요가 있어 찾다보니 FltIsVolumeWritable()이라는 함수를 발견했다.
기쁨도 잠시...
Vista 이상만 지원하기 때문에 XP에서는 사용할 수가 없었다.
그래서...
XP에서도 동작하게 하기 위해 FltIsVolumeWritable() 함수를 구현하기로 했다.
FltIsVolumeWritable() 내부를 보니 생각보다 복잡하지 않았기 때문이다.
Windows 7 SP1
kd> uf fltmgr!FltIsVolumeWritable
fltmgr!FltIsVolumeWritable:
8489a398 8bff mov edi,edi
8489a39a 55 push ebp
8489a39b 8bec mov ebp,esp
8489a39d 83ec18 sub esp,18h
8489a3a0 53 push ebx
8489a3a1 56 push esi
8489a3a2 8b7508 mov esi,dword ptr [ebp+8] ; FltObject(Volume)
8489a3a5 57 push edi
8489a3a6 8b7d0c mov edi,dword ptr [ebp+0Ch] ; IsWritable(Ptr)
8489a3a9 c60701 mov byte ptr [edi],1 ; IsWritable=1
8489a3ac 8b06 mov eax,dword ptr [esi] ; Volume.Base.Flags
8489a3ae 8bc8 mov ecx,eax
8489a3b0 c1e918 shr ecx,18h ; Check bit 0x18
8489a3b3 f6c101 test cl,1
8489a3b6 7405 je fltmgr!FltIsVolumeWritable+0x25 (8489a3bd) ; No bit 0x18
fltmgr!FltIsVolumeWritable+0x20: ; bit 0x18
8489a3b8 8b7618 mov esi,dword ptr [esi+18h]
8489a3bb eb07 jmp fltmgr!FltIsVolumeWritable+0x2c (8489a3c4)
fltmgr!FltIsVolumeWritable+0x25:
8489a3bd c1e81a shr eax,1Ah ; Check bit 0x1A
8489a3c0 a801 test al,1
8489a3c2 7470 je fltmgr!FltIsVolumeWritable+0x9c (8489a434) ; No bit 0x1A
fltmgr!FltIsVolumeWritable+0x2c: ; bit 0x1A
8489a3c4 33db xor ebx,ebx ; ebx=0
8489a3c6 395e20 cmp dword ptr [esi+20h],ebx ; Volume.DiskDeviceObject
8489a3c9 7507 jne fltmgr!FltIsVolumeWritable+0x3a (8489a3d2) ; jmp if exist
fltmgr!FltIsVolumeWritable+0x33:
8489a3cb b819001cc0 mov eax,0C01C0019h ; STATUS_FLT_NO_DEVICE_OBJECT
8489a3d0 eb67 jmp fltmgr!FltIsVolumeWritable+0xa1 (8489a439)
fltmgr!FltIsVolumeWritable+0x3a:
8489a3d2 53 push ebx
8489a3d3 53 push ebx
8489a3d4 8d45e8 lea eax,[ebp-18h] ; KEVENT
8489a3d7 50 push eax
8489a3d8 ff1528208884 call dword ptr [fltmgr!_imp__KeInitializeEvent (84882028)]
8489a3de 8d45f8 lea eax,[ebp-8]
8489a3e1 50 push eax
8489a3e2 8d45e8 lea eax,[ebp-18h] ; KEVENT
8489a3e5 50 push eax
8489a3e6 53 push ebx ; 0
8489a3e7 53 push ebx ; 0
8489a3e8 53 push ebx ; 0
8489a3e9 53 push ebx ; 0
8489a3ea 53 push ebx ; 0
8489a3eb ff7620 push dword ptr [esi+20h] ; Volume.DiskDeviceObject
8489a3ee 6824000700 push 70024h ; IOCTL_DISK_IS_WRITABLE
8489a3f3 ff15b8238884 call dword ptr [fltmgr!_imp__IoBuildDeviceIoControlRequest (848823b8)]
8489a3f9 3bc3 cmp eax,ebx ; Irp
8489a3fb 7507 jne fltmgr!FltIsVolumeWritable+0x6c (8489a404)
fltmgr!FltIsVolumeWritable+0x65:
8489a3fd b89a0000c0 mov eax,0C000009Ah
8489a402 eb35 jmp fltmgr!FltIsVolumeWritable+0xa1 (8489a439)
fltmgr!FltIsVolumeWritable+0x6c:
8489a404 8b4e20 mov ecx,dword ptr [esi+20h] ; Volume.DiskDeviceObject
8489a407 8bd0 mov edx,eax ; Irp
8489a409 ff15b4218884 call dword ptr [fltmgr!_imp_IofCallDriver (848821b4)]
8489a40f 3d03010000 cmp eax,103h ; STATUS_PENDING
8489a414 7511 jne fltmgr!FltIsVolumeWritable+0x8f (8489a427) ; jmp if not
fltmgr!FltIsVolumeWritable+0x7e: ; STATUS_PENDING
8489a416 53 push ebx ; 0
8489a417 53 push ebx ; 0
8489a418 53 push ebx ; 0
8489a419 53 push ebx ; 0
8489a41a 8d45e8 lea eax,[ebp-18h] ; KEVENT
8489a41d 50 push eax
8489a41e ff1504248884 call dword ptr [fltmgr!_imp__KeWaitForSingleObject (84882404)]
8489a424 8b45f8 mov eax,dword ptr [ebp-8]
fltmgr!FltIsVolumeWritable+0x8f:
8489a427 3da20000c0 cmp eax,0C00000A2h ; STATUS_MEDIA_WRITE_PROTECTED
8489a42c 7502 jne fltmgr!FltIsVolumeWritable+0x98 (8489a430) ; jmp if not
fltmgr!FltIsVolumeWritable+0x96: ; STATUS_MEDIA_WRITE_PROTECTED
8489a42e 881f mov byte ptr [edi],bl ; IsWritable=0
fltmgr!FltIsVolumeWritable+0x98:
8489a430 33c0 xor eax,eax ; STATUS_SUCCESS
8489a432 eb05 jmp fltmgr!FltIsVolumeWritable+0xa1 (8489a439)
fltmgr!FltIsVolumeWritable+0x9c:
8489a434 b80d0000c0 mov eax,0C000000Dh
fltmgr!FltIsVolumeWritable+0xa1:
8489a439 5f pop edi
8489a43a 5e pop esi
8489a43b 5b pop ebx
8489a43c c9 leave
8489a43d c20800 ret 8
이렇게 보고 나서 대충 비슷하게 C로 구현하니 다음과 같이 나왔다.
NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
*pbWritable = TRUE;
ObDereferenceObject( pDiskDevObj );