C++ Windows内核在用户模式下不会发生损坏吗

C++ Windows内核在用户模式下不会发生损坏吗,c++,windows,kernel,windbg,corruption,C++,Windows,Kernel,Windbg,Corruption,我目前正在使用liveKD执行内核调试 在发生阻塞的所有情况下(a::CloseHandle()函数调用永远不会返回),我碰巧有一个stacktrace,它在同步事件上阻塞内核 但是当我这样做的时候!对象12345678如果123456789是进程的线程信息中报告的我的同步事件,则表示不是有效对象(ObjectType invalid)。 我担心用户模式下应用程序级的损坏是否会损坏内核? windows是否保证内存空间的分离,从而防止类似的事情发生 应用程序代码采用C++、COM/DCOM和Wi

我目前正在使用liveKD执行内核调试

在发生阻塞的所有情况下(a
::CloseHandle()
函数调用永远不会返回),我碰巧有一个stacktrace,它在
同步事件上阻塞内核

但是当我这样做的时候!对象12345678
如果123456789是进程的线程信息中报告的我的
同步事件
,则表示
不是有效对象(ObjectType invalid)。

我担心用户模式下应用程序级的损坏是否会损坏内核? windows是否保证内存空间的分离,从而防止类似的事情发生

应用程序代码采用C++、COM/DCOM和Win32。


一条评论要求提供有关stacktrace和句柄类型的更多信息。 在这种情况下,它与串行com端口有关。但我想我也有它的文件句柄(还没有调试这些案例) 这就是我的stacktrace类型:

THREAD 856a2d48 Cid 0660.0350 Teb: 7ff25000 Win32Thread: ffaaedd8 WAIT: (Executive) KernelMode Non-Alertable 860c6f9c SynchronizationEvent IRP List: babea5d8: (0006,01d8) Flags: 00000404 Mdl: 00000000 Not impersonating DeviceMap 89809fc8 Owning Process 86212d40 Image: DataCaptorIS.exe Attached Process N/A Image: N/A Wait Start TickCount 27315407 Ticks: 6067021 (1:02:17:26.134) Context Switch Count 2259 IdealProcessor: 0 UserTime 00:00:04.976 KernelTime 00:00:02.184 Win32 Start Address 0x775c03e9 Stack Init 8aa0dfd0 Current 8aa0da98 Base 8aa0e000 Limit 8aa0b000 Call 0 Priority 9 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5 ChildEBP RetAddr Args to Child 8aa0dab0 824bfced 856a2d48 00000000 8ab00120 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4]) 8aa0dae8 824beb4b 856a2e08 856a2d48 860c6f9c nt!KiSwapThread+0x266 8aa0db10 824b856f 856a2d48 856a2e08 00000000 nt!KiCommitThreadWait+0x1df 8aa0db88 914539fb 860c6f9c 00000000 00000000 nt!KeWaitForSingleObject+0x393 8aa0dbcc 82478c1e 860c6f98 babea5d8 babea73c serial!SerialClose+0x332 (FPO: [Non-Fpo]) 8aa0dbe4 886206b9 babea5d8 861986d0 bc859308 nt!IofCallDriver+0x63 8aa0dc08 82478c1e 861986d0 860c6890 00000800 serenum!Serenum_CreateClose+0x77 (FPO: [Non-Fpo]) 8aa0dc20 82673be6 84aa7a00 bc8592f0 00000000 nt!IofCallDriver+0x63 8aa0dc64 826647c9 bc859308 bc859308 bc8592f0 nt!IopDeleteFile+0x10c 8aa0dc7c 824ba1e0 00000000 856a2d48 bc8592f0 nt!ObpRemoveObjectRoutine+0x59 8aa0dc90 824ba150 bc859308 82687556 960a5578 nt!ObfDereferenceObjectWithTag+0x88 (FPO: [0,0,3]) 8aa0dc98 82687556 960a5578 856a2d48 00000c80 nt!ObfDereferenceObject+0xd (FPO: [0,1,0]) 8aa0dcdc 8268727c 960a5578 a7d21900 86212d40 nt!ObpCloseHandleTableEntry+0x21d 8aa0dd0c 82687616 86212d40 856a2d01 0763f3b4 nt!ObpCloseHandle+0x7f 8aa0dd28 8247f8a6 00000c80 0763f3b8 775d7094 nt!NtClose+0x4e 8aa0dd28 775d7094 00000c80 0763f3b8 775d7094 nt!KiSystemServicePostCall (FPO: [0,3] TrapFrame @ 8aa0dd34) WARNING: Frame IP not in any known module. Following frames may be wrong. 0763f3b8 00000000 00000000 00000000 00000000 0x775d7094 在应用程序级别,在usermode中,这发生在本应取消并清除任何IRP的代码之后:

::CancelIoEx(m_handle_to_serial_port_com);
WaitForRequestToComplete(); // our function calls ::GetOverlappedResult(..., bWait) for any OVERLAPPED that was pending, with bWait == TRUE

::PurgeComm(m_handle_to_serial_port_com);
WaitForRequestToComplete(); // our function calls ::GetOverlappedResult(..., bWait) for any OVERLAPPED that was pending, with bWait == TRUE

::CloseHandle(m_handle_to_serial_port_com); // the closeHandle which never returns
这些问题确实是随机发生的。有时需要几天才能繁殖


显示SynchronizationEvent对象的内存地址86184f9c(在另一台有相同错误的机器上):

0:kd>dp 86184f9c-@@c++(sizeof(nt!\u对象\u头)-(RTL\u字段\u大小(nt!\u对象\u头,体)) 86184f84 0000000 6 00000000 00000000 00000000 86184f94 00000000 00000001 00040001 00000000 86184fa4 85917420 85917420 00000000 00000000 86184fb4 0000000000000000000000000000000 d 86184fc4 86184890 000000 40 00000000 000000800 86184 FD4 00000000 85747a68 00000000 00000000 86184fe4 00000000000000 86184fec 86184fec 86184ff4 86184ff4 86184ff4 96d4c000 04040000 并尝试显示对象标题:

0: kd> dt nt!_object_header 86184f9c - @@c++(sizeof(nt!_object_header) - #RTL_FIELD_SIZE(nt!_object_header, Body)) Cannot find specified field members. 0:kd>dt-nt_object_header 86184f9c-@@c++(sizeof(nt!_object_header)-#RTL_FIELD_SIZE(nt!_object_header,Body)) 找不到指定的字段成员。
当然应该是这样的。如果内核可以从用户模式被破坏,那么您将有一个可能影响机器上所有用户的安全缺陷。您可以通过使内核崩溃来拒绝服务。您可以利用内核缓冲区溢出来提升权限。您可以使用内核信息泄露漏洞窃取其他人的数据

仅仅因为你给内核提供了坏数据并不意味着它有这样一个漏洞。内核可能足够聪明,可以检测和防止此类问题,或者它可以执行任何可能受到userland中损坏的userland输入影响的代码


如果您确实发现了一个bug,该bug会导致内核崩溃、读取其他人传递给内核的数据或类似的内容,那么您应该向Microsoft报告。如果您怀疑发现了什么,请尝试联系MS支持部门,看看他们是否能提供帮助。他们是操作系统方面的专家,最有可能确定您怀疑的缺陷是否是真正的缺陷。

很遗憾,运行在环0中的内核不能与运行在环3中的进程进行更改。Windows中继来自微处理器的硬件支持,以实现内存和I/O隔离,因此任何进程都无法访问内核空间或其他用户的内存空间中的内存

访问内核的唯一方法是通过系统调用。Windows中的系统调用采用称为“本机API”的API形式。例如
NtCreateFile
,它是代表调用
CreateFile
函数而调用的函数
NtCreateFile
必须检查所有参数的有效性。这个函数可以从内核本身作为
ZwCreateFile
访问。从内核调用时,它不进行检查,因为内核信任在内核模式下运行的任何代码。

CloseHandle()仅在句柄的所有挂起IO完成后才会完成。根据你发布的线程信息,这个线程至少有一个挂起的IRP——我想看看它是否与你试图关闭的对象相同


FWIW,-您的串行设备支持取消吗?

这只是为什么
的后续说明!对象
在给定地址上不起作用

TL;DR:您的SynchronizationEvent未损坏。传递给
的地址!object
命令不是内核对象,它只是一个内核结构

0: kd> dt _KEVENT
nt!_KEVENT
   +0x000 Header           : _DISPATCHER_HEADER 

kd> dt _dispatcher_header 0xffffd000`6dba6278
ntdll!_DISPATCHER_HEADER
   +0x000 Lock             : 0n1594228737
   +0x000 LockNV           : 0n1594228737
   +0x000 Type             : 0x1 ''
   +0x001 Signalling       : 0 ''
   +0x002 Size             : 0x6 ''
   +0x003 Reserved1        : 0x5f '_'
   +0x000 TimerType        : 0x1 ''
   +0x001 TimerControlFlags : 0 ''
   +0x001 Absolute         : 0y0
   +0x001 Wake             : 0y0
   +0x001 EncodedTolerableDelay : 0y000000 (0)
   +0x002 Hand             : 0x6 ''
   +0x003 TimerMiscFlags   : 0x5f '_'
   +0x003 Index            : 0y011111 (0x1f)
   +0x003 Inserted         : 0y1
   +0x003 Expired          : 0y0
   +0x000 Timer2Type       : 0x1 ''
   +0x001 Timer2Flags      : 0 ''
   +0x001 Timer2Inserted   : 0y0
   +0x001 Timer2Expiring   : 0y0
   +0x001 Timer2CancelPending : 0y0
   +0x001 Timer2SetPending : 0y0
   +0x001 Timer2Running    : 0y0
   +0x001 Timer2Disabled   : 0y0
   +0x001 Timer2ReservedFlags : 0y00
   +0x002 Timer2Reserved1  : 0x6 ''
   +0x003 Timer2Reserved2  : 0x5f '_'
   +0x000 QueueType        : 0x1 ''
   +0x001 QueueControlFlags : 0 ''
   +0x001 Abandoned        : 0y0
   +0x001 DisableIncrement : 0y0
   +0x001 QueueReservedControlFlags : 0y000000 (0)
   +0x002 QueueSize        : 0x6 ''
   +0x003 QueueReserved    : 0x5f '_'
   +0x000 ThreadType       : 0x1 ''
   +0x001 ThreadReserved   : 0 ''
   +0x002 ThreadControlFlags : 0x6 ''
   +0x002 CycleProfiling   : 0y0
   +0x002 CounterProfiling : 0y1
   +0x002 GroupScheduling  : 0y1
   +0x002 AffinitySet      : 0y0
   +0x002 ThreadReservedControlFlags : 0y0000
   +0x003 DebugActive      : 0x5f '_'
   +0x003 ActiveDR7        : 0y1
   +0x003 Instrumented     : 0y1
   +0x003 Minimal          : 0y1
   +0x003 Reserved4        : 0y011
   +0x003 UmsScheduled     : 0y1
   +0x003 UmsPrimary       : 0y0
   +0x000 MutantType       : 0x1 ''
   +0x001 MutantSize       : 0 ''
   +0x002 DpcActive        : 0x6 ''
   +0x003 MutantReserved   : 0x5f '_'
   +0x004 SignalState      : 0n0
   +0x008 WaitListHead     : _LIST_ENTRY [ 0xffffe001`ef7a5540 - 0xffffe001`ef7a5540 ]
kd
!object
命令只是查找一个特殊的结构(即
nt!\u object\u HEADER
),该结构预先添加到所有内核对象。更准确地说,内核结构一有
nt_对象头
就在它前面。在结构前面加上这个
\u OBJECT\u HEADER
后,它就成为一个内核对象,然后由内核对象管理器处理(特别是以
Ob
前缀开头的所有内核函数,但内核中还有其他涉及对象管理的函数)

如果内核想要创建一个事件,但特别是如果这个对象不必跨越用户区域/内核区域边界(或者如果不需要ref计数),那么内核可能只创建一个
nt_KEVENT
结构,无
nt_对象标题

检查地址是否是内核对象(或不是)

查看堆栈跟踪,我们有以下两行:

    8aa0db88 914539fb 860c6f9c 00000000 00000000 nt!KeWaitForSingleObject+0x393
    8aa0dbcc 82478c1e 860c6f98 babea5d8 babea73c serial!SerialClose+0x332 (FPO: [Non-Fpo])
幸运的是,
serial.sys
是Microsoft驱动程序,因此我们有符号信息。查看
serial中的代码!SerialClose
大约偏移量0x332,我们有以下代码:

PAGESER:0001EEFC                 lea     eax, [esi+654h]
PAGESER:0001EF02                 push    ebx             ; Timeout
PAGESER:0001EF03                 push    ebx             ; Alertable
PAGESER:0001EF04                 push    ebx             ; WaitMode
PAGESER:0001EF05                 push    ebx             ; WaitReason
PAGESER:0001EF06                 push    eax             ; Object
PAGESER:0001EF07                 call    ds:__imp__KeWaitForSingleObject@20 ; KeWaitForSingleObject(x,x,x,x,x)
等待代码的事件(
KEVENT
类型)来自
[esi+0x654]
。。。 回溯在函数开始时,我们有:

PAGESER:0001EBD5                 mov     esi, [ebp+DeviceObject]
PAGESER:0001EBD8                 push    edi
PAGESER:0001EBD9                 mov     esi, [esi+_DEVICE_OBJECT.DeviceExtension]
因此,esi(在
[esi+0x654]
中)是设备ob的设备扩展
PAGESER:0001EBD5                 mov     esi, [ebp+DeviceObject]
PAGESER:0001EBD8                 push    edi
PAGESER:0001EBD9                 mov     esi, [esi+_DEVICE_OBJECT.DeviceExtension]
PAGESRP0:000194AF                 push    esi             ; State
PAGESRP0:000194B0                 push    1               ; Type
PAGESRP0:000194B2                 lea     eax, [ebx+654h]
PAGESRP0:000194B8                 push    eax             ; Event
PAGESRP0:000194B9                 call    edi ; KeInitializeEvent(x,x,x) ; KeInitializeEvent(x,x,x)
kd> !thread ffffe001ef7a5400
THREAD ffffe001ef7a5400  Cid 0538.054c  Teb: 00007ff7a9869000 Win32Thread: fffff901406825d0 WAIT: (Executive) KernelMode Non-Alertable
    ffffd0006dba6278  SynchronizationEvent
...
kd> dt _kthread ffffe001ef7a5400 waitblocklist
ntdll!_KTHREAD
   +0x0d0 WaitBlockList : 0xffffe001`ef7a5540 _KWAIT_BLOCK
kd> dt _kthread ffffe001ef7a5400 alertable
ntdll!_KTHREAD
   +0x074 Alertable : 0y0
kd> dt _kthread ffffe001ef7a5400 waitmode
ntdll!_KTHREAD
   +0x187 WaitMode : 0 ''
kd> dt _kwait_block 0xffffe001`ef7a5540
ntdll!_KWAIT_BLOCK
   +0x000 WaitListEntry    : _LIST_ENTRY [ 0xffffd000`6dba6280 - 0xffffd000`6dba6280 ]
   +0x010 WaitType         : 0x1 ''
   +0x011 BlockState       : 0x4 ''
   +0x012 WaitKey          : 0
   +0x014 SpareLong        : 0n1089
   +0x018 Thread           : 0xffffe001`ef7a5400 _KTHREAD
   +0x018 NotificationQueue : 0xffffe001`ef7a5400 _KQUEUE
   +0x020 Object           : 0xffffd000`6dba6278 Void
   +0x028 SparePtr         : (null)
0: kd> dt _KEVENT
nt!_KEVENT
   +0x000 Header           : _DISPATCHER_HEADER 

kd> dt _dispatcher_header 0xffffd000`6dba6278
ntdll!_DISPATCHER_HEADER
   +0x000 Lock             : 0n1594228737
   +0x000 LockNV           : 0n1594228737
   +0x000 Type             : 0x1 ''
   +0x001 Signalling       : 0 ''
   +0x002 Size             : 0x6 ''
   +0x003 Reserved1        : 0x5f '_'
   +0x000 TimerType        : 0x1 ''
   +0x001 TimerControlFlags : 0 ''
   +0x001 Absolute         : 0y0
   +0x001 Wake             : 0y0
   +0x001 EncodedTolerableDelay : 0y000000 (0)
   +0x002 Hand             : 0x6 ''
   +0x003 TimerMiscFlags   : 0x5f '_'
   +0x003 Index            : 0y011111 (0x1f)
   +0x003 Inserted         : 0y1
   +0x003 Expired          : 0y0
   +0x000 Timer2Type       : 0x1 ''
   +0x001 Timer2Flags      : 0 ''
   +0x001 Timer2Inserted   : 0y0
   +0x001 Timer2Expiring   : 0y0
   +0x001 Timer2CancelPending : 0y0
   +0x001 Timer2SetPending : 0y0
   +0x001 Timer2Running    : 0y0
   +0x001 Timer2Disabled   : 0y0
   +0x001 Timer2ReservedFlags : 0y00
   +0x002 Timer2Reserved1  : 0x6 ''
   +0x003 Timer2Reserved2  : 0x5f '_'
   +0x000 QueueType        : 0x1 ''
   +0x001 QueueControlFlags : 0 ''
   +0x001 Abandoned        : 0y0
   +0x001 DisableIncrement : 0y0
   +0x001 QueueReservedControlFlags : 0y000000 (0)
   +0x002 QueueSize        : 0x6 ''
   +0x003 QueueReserved    : 0x5f '_'
   +0x000 ThreadType       : 0x1 ''
   +0x001 ThreadReserved   : 0 ''
   +0x002 ThreadControlFlags : 0x6 ''
   +0x002 CycleProfiling   : 0y0
   +0x002 CounterProfiling : 0y1
   +0x002 GroupScheduling  : 0y1
   +0x002 AffinitySet      : 0y0
   +0x002 ThreadReservedControlFlags : 0y0000
   +0x003 DebugActive      : 0x5f '_'
   +0x003 ActiveDR7        : 0y1
   +0x003 Instrumented     : 0y1
   +0x003 Minimal          : 0y1
   +0x003 Reserved4        : 0y011
   +0x003 UmsScheduled     : 0y1
   +0x003 UmsPrimary       : 0y0
   +0x000 MutantType       : 0x1 ''
   +0x001 MutantSize       : 0 ''
   +0x002 DpcActive        : 0x6 ''
   +0x003 MutantReserved   : 0x5f '_'
   +0x004 SignalState      : 0n0
   +0x008 WaitListHead     : _LIST_ENTRY [ 0xffffe001`ef7a5540 - 0xffffe001`ef7a5540 ]