在IRP_MJ_READ的处理函数filemonread中,调用了获得当前用户名方法:
NTSTATUS
GetUserName(
char* a
)
{
NTSTATUS status = STATUS_SUCCESS;
HANDLE TokenHandle;
ULONG ReturnLength;
ULONG size;
UNICODE_STRING SidString;
PTOKEN_USER TokenInformation = NULL;
char SidStringBuffer[MAXPATHLEN];
ANSI_STRING sid_a;
if(PASSIVE_LEVEL != KeGetCurrentIrql())
{
return status;
}
status = ZwOpenThreadTokenEx (NtCurrentThread(),
TOKEN_READ,
TRUE,
OBJ_KERNEL_HANDLE,
&TokenHandle);
if ( !NT_SUCCESS( status ) ) {
status = ZwOpenProcessTokenEx (NtCurrentProcess(),
TOKEN_READ,
OBJ_KERNEL_HANDLE,
&TokenHandle);
if ( !NT_SUCCESS( status )) {
return status;
}
}
// 获取token信息
size = 0x1000;
TokenInformation = ExAllocatePool( NonPagedPool, size );
do {
status = ZwQueryInformationToken( TokenHandle,
TokenUser,
TokenInformation,
size,
&ReturnLength );
if (status == STATUS_BUFFER_TOO_SMALL) {
ExFreePool( TokenInformation );
size *= 2;
TokenInformation = ExAllocatePool( NonPagedPool, size );
} else if ( !NT_SUCCESS (status) ) {
DbgPrint(" ZwQueryInformationToken error\n");
if(NULL!=TokenInformation)
ExFreePool( TokenInformation );
ZwClose( TokenHandle );
return STATUS_UNSUCCESSFUL;
}
} while (status == STATUS_BUFFER_TOO_SMALL);
ZwClose( TokenHandle );
RtlZeroMemory( SidStringBuffer, sizeof(SidStringBuffer) );
SidString.Buffer = (PWCHAR)SidStringBuffer;
SidString.MaximumLength = sizeof( SidStringBuffer );
status = RtlConvertSidToUnicodeString( &SidString,
((PTOKEN_USER)TokenInformation)->User.Sid,
FALSE );
if(NULL!=TokenInformation)
ExFreePool( TokenInformation );
// KdPrint(("sudami's PC Name: %ws\n", SidStringBuffer));
status = RtlUnicodeStringToAnsiString(&sid_a,&SidString,TRUE);
if(NT_SUCCESS(status))
{
strcpy(a,sid_a.Buffer);
RtlFreeAnsiString(&sid_a);
}
// a = SidStringBuffer;
return STATUS_SUCCESS;
}
运行几天以后蓝屏重启,用windbg看dump文件,堆栈如下
STACK_TEXT:
8f885234 915b4f3c 8f885790 00000000 00000000 mmdogflps!GetUserName+0x15 [d:\´©É½¼×\´úÂë¹ÜÀí\code\process.c @ 315]8f8858a0 81878976 83bd7a70 83f911f0 00000000 mmdogflps!FilemonRead+0x12c [d:\´©É½¼×\´úÂë¹ÜÀí\code\sfilter.c @ 8078]
8f8858b8 8186d74e 83dab1f0 82f0903c 82f09008 nt!IofCallDriver+0x63
8f8858d4 818abf07 00000043 83dab1f0 82f09048 nt!IoPageRead+0x172
8f885990 818cd325 90033228 00000000 00000000 nt!MiDispatchFault+0xd14
8f885a0c 81881db4 00000000 90033228 00000000 nt!MmAccessFault+0x10c6
8f885a0c 81a65dcf 00000000 90033228 00000000 nt!KiTrap0E+0xdc
8f885aa8 81a65db4 90033230 00000001 8f885ae4 nt!ObDereferenceSecurityDescriptor+0x12
8f885ab8 81a65fb9 90033230 00000000 82db29a8 nt!ObReleaseObjectSecurity+0x26
8f885ae4 81a631c3 901c0440 8f885c01 00000001 nt!ObCheckObjectAccess+0xde
8f885b5c 81a62a15 00000001 82dd3860 901c0440 nt!ObpIncrementHandleCount+0x2c6
8f885bd0 81a4adec 00000001 901c0440 862000b0 nt!ObpCreateHandle+0x182
8f885cc4 81a324d6 901c0440 00000200 00000000 nt!ObOpenObjectByPointer+0xbc
8f885d30 8187ec7a ffffffff 00020008 00000200 nt!NtOpenProcessTokenEx+0xb4
8f885d30 8187d215 ffffffff 00020008 00000200 nt!KiFastCallEntry+0x12a
8f885db8 915b5c74 ffffffff 00020008 00000200 nt!ZwOpenProcessTokenEx+0x11
8f88620c 915b4f3c 8f886768 00000000 00000000 mmdogflps!GetUserName+0x84 [d:\´©É½¼×\´úÂë¹ÜÀí\code\process.c @ 338]
8f886878 81878976 83bd7a70 83d56830 00000000 mmdogflps!FilemonRead+0x12c [d:\´©É½¼×\´úÂë¹ÜÀí\code\sfilter.c @ 8078]
8f886890 8186d74e 83dab1f0 83445654 83445620 nt!IofCallDriver+0x63
8f8868ac 818abf07 00000043 83dab1f0 83445660 nt!IoPageRead+0x172
8f886968 818cd325 90033228 00000000 00000000 nt!MiDispatchFault+0xd14
8f8869e4 81881db4 00000000 90033228 00000000 nt!MmAccessFault+0x10c6
8f8869e4 81a65dcf 00000000 90033228 00000000 nt!KiTrap0E+0xdc
8f886a80 81a65db4 90033230 00000001 8f886abc nt!ObDereferenceSecurityDescriptor+0x12
8f886a90 81a65fb9 90033230 00000000 82db29a8 nt!ObReleaseObjectSecurity+0x26
8f886abc 81a631c3 901c0440 8f886b01 00000001 nt!ObCheckObjectAccess+0xde
8f886b34 81a62a15 00000001 82dd3860 901c0440 nt!ObpIncrementHandleCount+0x2c6
8f886ba8 81a4adec 00000001 901c0440 862000b0 nt!ObpCreateHandle+0x182
8f886c9c 81a324d6 901c0440 00000200 00000000 nt!ObOpenObjectByPointer+0xbc
8f886d08 8187ec7a ffffffff 00020008 00000200 nt!NtOpenProcessTokenEx+0xb4
8f886d08 8187d215 ffffffff 00020008 00000200 nt!KiFastCallEntry+0x12a
8f886d90 915b5c74 ffffffff 00020008 00000200 nt!ZwOpenProcessTokenEx+0x11
8f8871e4 915b4f3c 8f887740 00320039 00320034 mmdogflps!GetUserName+0x84 [d:\´©É½¼×\´úÂë¹ÜÀí\code\process.c @ 338]
8f887850 81878976 83bd7a70 83c5d530 00000000 mmdogflps!FilemonRead+0x12c [d:\´©É½¼×\´úÂë¹ÜÀí\code\sfilter.c @ 8078]
8f887868 8186d74e 83dab1f0 83446674 83446640 nt!IofCallDriver+0x63
8f887884 818abf07 00000043 83dab1f0 83446680 nt!IoPageRead+0x172
8f887940 818cd325 90033232 00000000 00000000 nt!MiDispatchFault+0xd14
8f8879bc 81881db4 00000000 90033232 00000000 nt!MmAccessFault+0x10c6
8f8879bc 818e30c9 00000000 90033232 00000000 nt!KiTrap0E+0xdc
8f887a6c 818e2022 02000000 90033230 901c0440 nt!SepMandatoryIntegrityCheck+0x3e
8f887aa0 81a65f5a 90033230 8f887c34 00000001 nt!SeAccessCheck+0xbb
8f887aec 81a631c3 901c0440 8f887c18 00000001 nt!ObCheckObjectAccess+0x7f
8f887b64 81a62a15 00000001 83d55d90 901c0440 nt!ObpIncrementHandleCount+0x2c6
8f887bd8 81a4adec 00000001 901c0440 900b0f38 nt!ObpCreateHandle+0x182
8f887cc8 81a324d6 901c0440 00000000 00000000 nt!ObOpenObjectByPointer+0xbc
8f887d34 81a3560e ffffffff 02000000 00000000 nt!NtOpenProcessTokenEx+0xb4
8f887d50 8187ec7a ffffffff 02000000 0a7becf4 nt!NtOpenProcessToken+0x16
8f887d50 76fc5e74 ffffffff 02000000 0a7becf4 nt!KiFastCallEntry+0x12a
从堆栈看,在filemonread中调用了GetUserName,GetUserName调用了NtOpenProcessTokenEx,这个调用引起了缺页中断KiTrap0E,这个中断处理函数向磁盘发起读请求,这个读IRP又被hook到,陷入FilemonRead。这样陷入死循环。
之所以不容易复现,是因为只有缺页才会引起,如果NtOpenProcessTokenEx这个系统调用需要的信息在内存中,应该不会出。
这个问题需要解决重入问题。我们希望GetUserName引起的磁盘IRP我们驱动不处理。关键问题是如何识别这个IRP,还是用楚狂人教程里的办法,把GetUserName放到单独的线程中去运行,通过线程ID来识别当前IPR是否是这个单独线程发起的,如果是,则直接向后面驱动转发。