dpc与线程切换

news2024/10/1 3:21:23

中断服务例程 延迟过程调用 线程切换 键盘信号传输

1. 背景

我一般用ctrl+alt+del能否呼出winlogon桌面作为Windows卡死(hang)还是个别程序卡死的鉴别手段。因为一则用户态的程序没办法干扰这个呼出流程,二则如果不能呼出任务管理器来终止进程或者呼出windbg等工具进行观察调试的话,其实排查的方法也跟windows卡死是一致的——触发scrolllock蓝屏。所以探究ctrl+alt+del呼出winlogon桌面的流程,就是分析这类卡死的第一步。

同样是按键后的反应,为什么在ctrl+alt+del不能呼出的场景下,scrolllock蓝屏还能够触发,也是一个获取关键知识的方向。

2. 键盘信号从按下到应用程序的窗口

大致分为中断服务例程,DPC, csrss,具体应用程序这四个阶段。

2.1 中断服务例程(ISR)

2.1.1 什么是中断服务例程

诸如按下键盘按下或处理器时钟产生的这类设备中断,Windows设置了对应函数(中断服务例程)来处理。Windows在启动的早期阶段先设置好中断号码和ISR的对应关系。当设备中断触发时,Windows先把当前线程的当前状态保存起来,然后用这个线程去执行对应的ISR。执行完毕后再从保存数据恢复那个线程。

2.1.2 查看PS2键盘信号对应的中断服务例程

直接用windbg的!idt查找对应关系

0: kd> .reload;!idt

Dumping IDT: fffff8033ea8e000

00:        fffff8033c351100 nt!KiDivideErrorFaultShadow
01:        fffff8033c351180 nt!KiDebugTrapOrFaultShadow        Stack = 0xFFFFF8033EA929D0
02:        fffff8033c351200 nt!KiNmiInterruptShadow        Stack = 0xFFFFF8033EA927D0
03:        fffff8033c351280 nt!KiBreakpointTrapShadow

……
90:        fffff8033c352700 i8042prt!I8042KeyboardInterruptService (KINTERRUPT ffffbb007e792a00)

……

上文的90对应的函数i8042prt!I8042KeyboardInterruptService就是90中断号对应的ISR。给这个函数下断点,

C
bp i8042prt!I8042KeyboardInterruptService "!thread"

只有当ps2键盘按下或松开时才会执行这个函数。

具体如何通过90和idt寄存器计算出90对应的isr地址fffff803 3c35 2700的,请看下图:

0: kd> dt nt!_kidtentry64 @idtr+(90*10)
   +0x000 OffsetLow        : 0x2700
   +0x002 Selector         : 0x10
   +0x004 IstIndex         : 0y000
   +0x004 Reserved0        : 0y00000 (0)
   +0x004 Type             : 0y01110 (0xe)
   +0x004 Dpl              : 0y00
   +0x004 Present          : 0y1
   +0x006 OffsetMiddle     : 0x3c35
   +0x008 OffsetHigh       : 0xfffff803
   +0x00c Reserved1        : 0
   +0x000 Alignment        : 0x3c358e00`00102700

bp i8042prt!I8042KeyboardInterruptService"k";g

断点触发时,可以看到此时是idel线程fffff8033c591400调用了这个isr。

C
THREAD fffff8033c591400  Cid 0000.0000  Teb: 0000000000000000 Win32Thread: 0000000000000000 RUNNING on processor 0
Not impersonating
DeviceMap                 ffff9388274154e0
Owning Process            fffff8033c58e9c0       Image:         Idle
……
Call Site
i8042prt!I8042KeyboardInterruptService
nt!KiCallInterruptServiceRoutine+0xa5
nt!KiInterruptSubDispatch+0x11f
nt!KiInterruptDispatch+0x37
hal!HalProcessorIdle+0xf
nt!PpmIdleDefaultExecute+0x1b
nt!PpmIdleExecuteTransition+0x70c
nt!PoIdle+0x36e
nt!KiIdleLoop+0x48

这个isr内部会创建一个延迟过程调用(dpc),然后迅速结束isr。为的是确保响应硬件中断的接手工作尽可能快完结,而具体的事项留给其它时机处理这个dpc的时候来做。

2.2 延迟过程调用(DPC)

2.2.1 什么是延迟过程调用(DPC)

类似于一种延迟的任务。先尽快登记上这个任务——把任务插入排队的队列中。之后其它空闲的线程再扫描队列时候发现有任务未处理,那就会来处理它。dpc的有如下两个特点能满足操作系统的要求:

一般对于硬件中断的处理这类需求,需要尽快完成,则先用KeInsertQueueDpc函数登记上dpc,然后完成接手工作。dpc里面登记了个函数地址DeferredRoutine,等其它空闲线程发现有dpc要处理时,则执行此函数。

Windows抽象出中断请求级别(IRQL)的概念,在处理高级别的IRQL时,小于等于它的中断请求就不会处理了。大部分代码运行在被动级别上,线程切换流程里的某个阶段和dpc的DeferredRoutine处理是运行在dpc级别上,硬件中断都更高。dpc的第二个特点就是DeferredRoutine的IRQL又比一般的代码高,所以能尽快不被打扰地处理完毕。

2.2.2 查看PS2键盘ISR对应的DPC

接2.1.2,在该线程给函数nt!KeInsertQueueDpc下断点,这个函数的参数一就是DPC变量的结构体nt!_KDPC

C
bp /t  fffff8033c591400 nt!KeInsertQueueDpc "dt nt!_KDPC @rcx"

断点触发时,能看到DPC结构体里的数据,尤其是DefferedRoutine:

C
+0x000 TargetInfoAsUlong : 0x113
   +0x000 Type             : 0x13 ''
   +0x001 Importance       : 0x1 ''
   +0x002 Number           : 0
   +0x008 DpcListEntry     : _SINGLE_LIST_ENTRY
   +0x010 ProcessorHistory : 1
   +0x018 DeferredRoutine  : 0xfffff8033fe45fb0     void  i8042prt!I8042KeyboardIsrDpc+0
   +0x020 DeferredContext  : 0xffffd0036c0d1040 Void
   +0x028 SystemArgument1  : (null)
   +0x030 SystemArgument2  : (null)
   +0x038 DpcData          : (null)

再给这个DeferredRoutine下断点:

C
bd 0,1;bp I8042KeyboardIsrDpc "!thread"

断点触发时,内核调用KiRetireDpcList->KiExecuteAllDpcs->DeferredRoutine:

C
THREAD fffff8033c591400  Cid 0000.0000  Teb: 0000000000000000 Win32Thread: 0000000000000000 RUNNING on processor 0
Not impersonating
DeviceMap                 ffff9388274154e0
Owning Process            fffff8033c58e9c0       Image:         Idle
……
Call Site
i8042prt!I8042KeyboardIsrDpc
nt!KiExecuteAllDpcs+0x305
nt!KiRetireDpcList+0x1ef
nt!KiIdleLoop+0x84

2.3 DeferredRoutine调用kbdclass.sys进一步处理

执行i8042prt!I8042KeyboardIsrDpc函数,该函数调用i8042prt!I8xGetDataQueuePointer获取键盘端口驱动保存在设备扩展的按键信息队列指针,调用kbdclass!KeyboardClassServiceCallback完成按键信息的交付。然后调用i8042prt!I8xSetDataQueuePointer更新设备扩展的按键信息队列。kbdclass!KeyboardClassServiceCallback类驱动函数处理过程。将键盘信息从端口驱动的键盘信息队列中复制到类驱动的队列中。wdk的例子中有该函数源代码。[2]

将上述函数下断点,可以看到他们依此触发了:

C
bd 2;
bp /t fffff8033c591400 i8042prt!I8xGetDataQueuePointer "k";
bp /t fffff8033c591400 kbdclass!KeyboardClassServiceCallback "k";
bp /t fffff8033c591400 i8042prt!I8xSetDataQueuePointer "k"

C
i8042prt!I8xGetDataQueuePointer
nt!KeSynchronizeExecution+0x48
i8042prt!I8042KeyboardIsrDpc+0x109
nt!KiExecuteAllDpcs+0x305
nt!KiRetireDpcList+0x1ef
nt!KiIdleLoop+0x84
……
kbdclass!KeyboardClassServiceCallback
i8042prt!I8042KeyboardIsrDpc+0x2f8
nt!KiExecuteAllDpcs+0x305
nt!KiRetireDpcList+0x1ef
nt!KiIdleLoop+0x84
……
i8042prt!I8xSetDataQueuePointer
nt!KeSynchronizeExecution+0x48
i8042prt!I8042KeyboardIsrDpc+0x397
nt!KiExecuteAllDpcs+0x305
nt!KiRetireDpcList+0x1ef
nt!KiIdleLoop+0x84

2.3 csrss

csrss.exe进程一般有两个,0号session的和1号session的

C
0: kd> !process 0 0 csrss.exe
PROCESS ffffca057479e080
    SessionId: 0  Cid: 019c    Peb: 162aa55000  ParentCid: 0194
    DirBase: 01fba002  ObjectTable: ffffdf0200b584c0  HandleCount: 537.
    Image: csrss.exe

PROCESS ffffca0574b59080
    SessionId: 1  Cid: 01f4    Peb: 8216b90000  ParentCid: 01e0
    DirBase: 131bc7002  ObjectTable: ffffdf0200bfce40  HandleCount: 352.
    Image: csrss.exe

这两个进程里都各有一个线程调用win32kfull!RawInputThread,姑且称这两个线程为RawInputThread

C
THREAD ffffca0574b6a080
Owning Process            ffffca057479e080       Image:         csrss.exe
Call Site
nt!KiSwapContext+0x76
nt!KiSwapThread+0xbfd
nt!KiCommitThreadWait+0x144
nt!KeWaitForMultipleObjects+0x287
win32kbase!LegacyInputDispatcher::WaitAndDispatch+0x8b
win32kfull!RawInputThread+0x95e
win32kbase!xxxCreateSystemThreads+0xa3
win32kfull!NtUserCallNoParam+0x6f
nt!KiSystemServiceCopyEnd+0x28 (TrapFrame @ fffff20cb6217a80)
0x00007ffca6f81144
……
THREAD ffffca0574b8c080
Owning Process            ffffca0574b59080       Image:         csrss.exe
Call Site
nt!KiSwapContext+0x76
nt!KiSwapThread+0xbfd
nt!KiCommitThreadWait+0x144
nt!KeWaitForMultipleObjects+0x287
win32kbase!LegacyInputDispatcher::WaitAndDispatch+0x8b
win32kfull!RawInputThread+0x95e
win32kbase!xxxCreateSystemThreads+0xa3
win32kfull!NtUserCallNoParam+0x6f
nt!KiSystemServiceCopyEnd+0x28 (TrapFrame @ fffff20c`b6407a80)
0x00007ffc`a6f81144

3. 为什么hang witch dpc时,整个操作系统都挂起(卡死)了

因为线程切换的代码也是在dpc级别执行的。所以此时没有机会执行线程切换的代码。所以windows里大部分线程都无法工作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1332984.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

openmediavault基本操作

omv基本操作 使用hostname访问共享文件夹设置1.挂载磁盘2.提交更改3.新建用户4.建立共享文件夹5.设置SMB/CIFS服务7.测试7.1.速度测试 使用hostname访问 把网口和wifi设置成DHCP,使用hostname访问,这样把NAS拿到任何地方都不需要配置了,自动联网进行访问. #网络->常规 #设…

搭建谷歌 Gemini,体验谷歌版GPT4

12.06 日谷歌 DeepMind CEO 和联合创始人 Demis Hassabis 正式推出了大模型Gemini 目前,Gemini 1.0 提供了三个不同的尺寸版本,分别如下: Gemini Ultra:规模最大、能力最强,用于处理高度复杂的任务;Gemin…

map容器的基本使用

文章目录 mapmap模板参数默认构造迭代器[ ]{ }inserterasefindlower_bound && upper_boundcountequal_range map和set容器,multimap和multiset是树形结构的关联式容器,这四种容器底层原理都是红黑树,容器中的元素是一个有序序列。 ma…

电子电器架构(E/E)演化 —— 主流主机厂域集中架构概述

电子电器架构(E/E)演化 —— 主流主机厂域集中架构概述 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。…

存储卡显示0字节怎么办?恢复0字节的存储小技巧

存储卡显示0字节是一个常见的故障现象,可能由多种原因引起。本文将详细分析存储卡出现此类问题的各种原因,并提供针对性的解决方法。通过深入了解这些原因和解决方案,读者可以有效地应对存储卡显示0字节的故障,从而恢复存储卡的正…

博主自制PDF转换工具丨支持PDF转图片丨PDF转word丨PDF转Excel丨PDF文本识别丨免费使用在线下载

博主自制PDF转换工具丨支持PDF转图片丨PDF转word丨PDF转Excel丨PDF文本识别丨免费使用在线下载 点我立即下载

CSB文件上传漏洞 -->Day4(图片挂马)

22二号,冬至啦,深圳这边只有5(尊嘟好冷啊),写这篇文章的时候都已经是凌晨一点了,相信大部分的人都在温暖的被窝里面了吧!!(可怜的我,还得写writeup&#xff0…

【XML】TinyXML 详解(一):介绍

【C】郭老二博文之:C目录 1、简介 优点: TinyXML 是一个简单、小型的 C XML 解析器,可以轻松集成到项目中。 TinyXML 解析 XML 文档,并根据该文档构建可读取、修改和保存的文档对象模型 (DOM) TinyXML 是在 ZLib 许可下发布的&a…

UG凸起命令

凸起命令是拉伸命令的补充,可以方便的对曲面进行拉伸切除。 当端盖中几何体类型选择默认的截面平面的时候,相当于拉伸命令 当端盖中几何体类型选择凸起的面的时候,相当于拉伸其实曲线变为选择曲线在凸起面的投影曲线,然后基于凸起…

栈的常见题型

1.有效的括号 char pairs(char a) {if(a})return {;if(a])return [;if(a))return (;return 0; } bool isValid(char* s) {char* stack(char*)malloc(sizeof(char)*10000);int top0;int lenstrlen(s);if(len%21)return false;for(int i0;s[i];i){char chpairs(s[i]);if(ch){if(t…

BTF:实践指南

本文地址:BTF:实践指南 | 深入浅出 eBPF 1. BPF 的常见限制 1.1 调试限制1.2 可移植性2. BTF 是什么?3. BTF 快速入门 3.1 BPF 快速入门3.1 BTF 和 CO-RE4. 结论 BPF 是 Linux 内核中基于寄存器的虚拟机,可安全、高效和事件驱动…

【STM32】STM32学习笔记-TIM定时中断(13)

00. 目录 文章目录 00. 目录01. TIM简介02. 定时器类型03. 基本定时器04. 通用定时器05. 高级定时器06. 定时中断基本结构07. 预分频器时序08. 计数器时序09. 计数器无预装时序10. 计数器有预装时序11. RCC时钟树12. 附录 01. TIM简介 TIM(Timer)定时器…

数据库中间件介绍

文章目录 什么是数据库中间件?Smart-client 模式优点缺点 Proxy 模式优点缺点 单元化架构优点缺点 总结 数据库中间件是连接数据库和应用程序之间的软件层,用于简化数据库管理、提高性能和可伸缩性,同时提供额外的功能和服务。在分布式系统和…

mybatis的二级缓存使用以及禁用

目录 mybatis 二级缓存配置有两处 全局设置 mapper 设置 测试代码 执行结果 源码执行逻辑 创建 SqlSession 二级缓存配置是否添加 解析 cache 标签 XMLMapperBuilder MapperBuilderAssistant CacheBuilder PerpetualCache SerializedCache LoggingCache 将 cach…

Python教程(17)——python模块是什么?python模块详解

Python模块简介 模块是一个包含了Python定义和语句的文件,可用于将功能组织成可重用和可维护的代码块。每个Python文件都可以作为一个模块,模块可以包含变量、函数、类或可执行代码。通过使用模块,我们可以将代码分离成逻辑单元,…

【vtkWidgetRepresentation】第十八期 vtkHoverWidget

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 前言 本文分享vtkHoverWidget,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U^)ノ~YO 1. vtkHoverWidget vtkHoverWidget用于在呈现窗口中…

Python生成圣诞节贺卡-代码案例剖析【第18篇—python圣诞节系列】

文章目录 ❄️Python制作圣诞节贺卡🐬展示效果🌸代码🌴代码剖析 ❄️Python制作圣诞树贺卡🐬展示效果🌸代码🌴代码剖析🌸总结 🎅圣诞节快乐! ❄️Python制作圣诞节贺卡 …

商户如何去申请支付宝小程序以及对接团购(天财商龙)

申请支付宝小程序的前提:必须要是支付宝实名认证用户(要申请企业支付宝) 1.申请企业支付宝 申请网址:支付宝商家后台 https://b.alipay.com 企业支付宝必须是法人扫码进行注册 申请资料:企业的营业执照,没…

simulink代码生成(二)——ADC采样模块

这一节梳理如何使用C2000库中的ADC模块,从而实现采样; 先预留几个问题,逐步进行解决。 (1)在simulink中C2000的ADC采样模块设置是怎么样的?各个选项卡代表什么? (2)AD…

【开源】基于JAVA语言的学校热点新闻推送系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 新闻类型模块2.2 新闻档案模块2.3 新闻留言模块2.4 新闻评论模块2.5 新闻收藏模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 新闻类型表3.2.2 新闻表3.2.3 新闻留言表3.2.4 新闻评论表3.2.5 新闻收藏表 四、系统展…