Windows进程与线程学习笔记(九)—— 线程优先级/进程挂靠/跨进程读写
Windows进程与线程学习笔记(九)—— 线程优先级/进程挂靠/跨进程读写
- 要点回顾
- 线程优先级
- 调度链表
- 分析 KiFindReadyThread
- 分析 KiSwapThread
- 总结
- 进程挂靠
- 进程与线程的关系
- 进程与线程的关联
- 分析 SwapContext
- 分析 NtReadVirtualMemory
- 总结
- 跨进程读写
- 跨进程读
- 跨进程写
- 总结
要点回顾
三种情况会导致线程切换:
- 当前线程主动调用API:
KiSwapThread -> KiSwapContext -> SwapContext - 当前线程时间片到期:
KiDispatchInterrupt -> KiQuantumEnd -> SwapContext - 存在备用线程(KPCR.PrcbData.NextThread)
KiDispatchInterrupt -> SwapContext
思考:在KiSwapThread与KiQuantumEnd函数中都是通过KiFindReadyThread来找下一个要切换的线程,KiFindReadyThread是根据什么条件来选择下一个要执行的线程呢?
线程优先级
调度链表
描述:
- 在Windows 32位操作系统中,共有32个双向链表(调度链表)
- 在Windows 64位操作系统中,共有64个双向链表(调度链表)
- 线程在调度链表的中下标表示线程优先级(0~31/64)
分析 KiFindReadyThread
查找方式:
按照优先级别进行查找:31…30…29…28…
也就是说,在本次查找中,如果级别31的链表里面有线程,那么就不会查找级别为30的链表
注意:
- Windows 32位操作系统中调度链表有32个,由于每次都从头开始查找效率太低,所以Windows通过一个DWORD类型的变量来记录:_KiReadySummary
- 当向调度链表(32个)中挂入或者摘除某个线程时,会判断当前级别的链表是否为空,为空则将 _KiReadySummary 对应位置0,否则置1
- 若当前级别链表的链表头和链表尾的值相同,并且等于它们的地址,说明不存在等待调度的线程
若当前级别链表的链表头和链表尾的值相同,但不等于它们的地址,说明存在一个等待调度的线程 - 多cpu会随机寻找 KiDispatcherReadyListHead 指向的数组中的线程。线程可以绑定某个cpu(API:setThreadAffinityMask)
- 若当前CPU不存在就绪线程,则会执行空闲线程,每一个CPU都会指定一个空闲线程
nt!_KPRCB+0x004 CurrentThread : Ptr32 _KTHREAD //当前线程+0x008 NextThread : Ptr32 _KTHREAD //就绪线程+0x00c IdleThread : Ptr32 _KTHREAD //空闲线程
分析 KiSwapThread
总结
- 调度链表的下标即线程优先级
- CPU通过遍历调度链表判断是否存在需要调度的线程
- 若不存在需要调度的线程,则会执行空闲线程(_KPRCB.IdleThread)
进程挂靠
进程与线程的关系
- 一个进程可以包含多个线程
- 一个进程至少要有一个线程
- 进程为线程提供资源,也就是提供Cr3的值,Cr3中存储的是页目录表基址
- Cr3确定了,线程能访问的内存也就确定了
例:CPU解析线程代码 mov eax,dword ptr ds:[0x12345678]
- CPU解析线性地址时要通过页目录表来找对应的物理页,页目录表基址存在
Cr3寄存器中 - 当前的Cr3的值来源于当前的进程(_KPROCESS.DirectoryTableBase(+0x018))
进程与线程的关联
- 资源提供者(养父母):_ETHREAD.Tcb.ApcState.Process
- 线程创建者(亲生父母):_ETHREAD.ThreadsProcess
- 一般情况下,_ETHREAD.Tcb.ApcState.Process 和 _ETHREAD.ThreadsProcess 指向的是同一个进程
- 将当前Cr3的值改为其它进程的Cr3,称为“进程挂靠”
mov cr3, A.DirectoryTableBase
mov eax,dword ptr ds:[0x12345678] //A进程的0x12345678内存
mov cr3, B.DirectoryTableBase
mov eax,dword ptr ds:[0x12345678] //B进程的0x12345678内存
mov cr3, C.DirectoryTableBase
mov eax,dword ptr ds:[0x12345678] //C进程的0x12345678内存
思考:在一份线程结构体中,存在着两个指向当前线程所属进程的指针,那么究竟是哪个提供了Cr3?
答案:线程切换的时候,会比较两个线程的EPROCESS是否为同一个,若不是同一个,则会将 _ETHREAD.Tcb.ApcState.Process 指向的 EPROCESS的DirectoryTableBase 取出,赋值给Cr3
分析 SwapContext
分析 NtReadVirtualMemory
MmCopyVirtualMemory:
MiDoPoolCopy:
KeStackAttachProcess:
KiAttachProcess:
KiSwapProcess:
思考:可不可以只修改Cr3而不修改养父母?
答案:不可以,假设刚刚修改完Cr3,还没读取内存时,发生了线程切换,当再次切换回来时,会根据养父母的值为Cr3赋值,Cr3又变回了原来的值,此时将变成自己读自己。如果我们自己来写这个代码,在切换Cr3后关闭中断,并且不调用会导致线程切换的API,就可以不用修改养父母的值
总结
- 正常情况下,当前线程使用的Cr3是由其所属进程提供的(_ETHREAD.Tcb.ApcState.Process),正是因为如此,A进程中的线程只能访问A的内存
- 如果要让A进程中的线程能够访问B进程的内存,就必须要修改Cr3的值为B进程的页目录表基址(B.DirectoryTableBase),这就是所谓的“进程挂靠”
跨进程读写
描述:跨进程的本质是“进程挂靠”,正常情况下,A进程的线程只能访问A进程的地址空间,如果A进程的线程想访问B进程的地址空间,就要修改当前的Cr3的值为B进程的页目录表基值(KPROCESS.DirectoryTableBase)。即:mov cr3, B.DirectoryTableBase
分析代码:
mov cr3,B.DirectoryTableBase //切换Cr3的值为B进程
mov eax,dword ptr ds:[0x12345678] //将进程B 0x12345678的值存入eax中
mov dword ptr ds:[0x00401234],eax //将数据存储到0x00401234中
mov cr3,A.DirectoryTableBase //切换回Cr3的值
问题:以上代码是否存在问题?
答案:存在问题。当读取B进程内存之后,由于Cr3并未改变,写入的地址仍为B进程的地址。当Cr3切换回A进程后,A进程中并不存在读出来的值
思考:如何解决以上问题?
跨进程读
NtReadVirtualMemory执行流程:
- 将当前线程的Cr3切换至目标进程的Cr3
- 将要读的数据复制到高2G(暂存区)
- 将当前线程的Cr3切换至原本进程的Cr3
- 将要读的数据从高2G复制到目标位置
跨进程写
NtWriteVirtualMemory执行流程:
- 将当前线程的数据复制到高2G(暂存区)
- 将当前线程的Cr3切换至目标进程的Cr3
- 将要写入的数据从高2G复制到目标位置
- 将当前线程的Cr3切换至原本进程的Cr3
总结
每个进程的高2G内存空间的线性地址对应的物理页几乎是相同的,可以通过对高2G内存空间的利用,实现跨进程内存读写的操作
Windows进程与线程学习笔记(九)—— 线程优先级/进程挂靠/跨进程读写相关推荐
- Windows 8 Metro App学习笔记(九)—磁砖
瓷砖,即桌面显示的Tile,它的创建和生命周期都可以由用户自由创建并可以直接访问一个应用程序,还可以为信息的及时推送带来很多的方便.在Windows 8中,由SecondaryTile对象负责. 首先 ...
- Windows进程与线程学习笔记(八)—— 线程切换与TSS/FS
Windows进程与线程学习笔记(八)-- 线程切换与TSS/FS 要点回顾 线程切换与TSS 内核堆栈 调用API进0环 实验:分析SwapContext 线程切换与FS 段描述符结构 分析Swap ...
- Windows进程与线程学习笔记(七)—— 时间片管理
Windows进程与线程学习笔记(七)-- 时间片管理 要点回顾 基本概念 CPU时间片 分析 KeUpdateRunTime 分析 KiDispatchInterrupt 备用线程 总结 要点回顾 ...
- Windows进程与线程学习笔记(六)—— 线程切换
Windows进程与线程学习笔记(六)-- 线程切换 主动切换 分析KiSwapContext 分析SwapContext 分析KiSWapThread 总结 时钟中断切换 系统时钟 分析INT 0x ...
- Windows进程与线程学习笔记(五)—— 模拟线程切换
Windows进程与线程学习笔记(五)-- 模拟线程切换 ThreadSwitch代码分析 ThreadSwitch.cpp ThreadCore.h ThreadCore.cpp 总结 Thread ...
- Windows进程与线程学习笔记(四)—— 等待链表调度链表
Windows进程与线程学习笔记(四)-- 等待链表&调度链表 要点回顾 33个链表 等待链表 实验:分析等待链表中的线程所属的进程 第一步:查看所属线程结构体: 第二步:查看所属进程结构体 ...
- Windows进程与线程学习笔记(三)—— KPCR
Windows进程与线程学习笔记(三)-- KPCR KPCR +0x000 NtTib : _NT_TIB +0x120 PrcbData : _KPRCB KPCR 描述:CPU控制区(Proce ...
- Windows进程与线程学习笔记(二)—— 线程结构体
Windows进程与线程学习笔记(二)-- 线程结构体 线程结构体 ETHREAD +0x000 Tcb : _KTHREAD 练习 线程结构体 ETHREAD 描述: 每个windows线程在0环都 ...
- Windows进程与线程学习笔记(一)—— 进程结构体
Windows进程与线程学习笔记(一)-- 进程结构体 进程结构体 EPROCESS +0x000 Pcb : _KPROCESS +0x1b0 Peb : Ptr32 _PEB 练习 解题步骤 第一 ...
最新文章
- Python使用tpot获取最优模型、将最优模型应用于交叉验证数据集(5折)获取数据集下的最优表现,并将每一折(fold)的预测结果、概率、属于哪一折与测试集标签、结果、概率一并整合输出为结果文件
- 爬虫数据采集技术趋势-智能化解析
- Thread 中的run() 与start() 方法
- 在word中使用notepad++实现代码的语法高亮
- 田志刚:企业知识管理的知识传播
- JS组件系列——Bootstrap 树控件使用经验分享 - 懒得安分 - 博客园
- spring中的IOC和AOP
- window.open不重复打开同一个名称的窗口_干货满满|Ctrl键的正确打开方式
- linux ext3下删除mysql数据库的数据恢复案例
- DOM 精通了?请问 Node 和 Element 有何区别?
- YOLOV5学习记录
- Java取交集方法retainAll()
- ID3 决策树(基于西瓜数据集2.0)
- TI Cortex-A9 AM437x系列-创龙TL437x-EVM开发板详解
- 六、肿瘤RNA突变的全组学研究-肿瘤基因调控(Genomic basis for RNA alterations in cancer)
- 一文带你了解python opencv中霍夫变换(Hough transform)的常用操作
- 李开复:未来最重要的不是操作系统 而是浏览器
- ORACLE字符集为US7ASCII,插入数据,中文乱码问题解决
- Win10 电脑屏幕亮度随背景颜色变化而变化
- PDF Reader Pro for mac(全能pdf阅读器)
热门文章
- Gradient Tree Boosting:梯度提升树详解
- STM32启动过程分析
- Using Preferences(Beginning Android)
- 野路子码农系列(3)plotly可视化的简单套路
- 在VMware运行Linux下,密码错误的原因
- 从零开始搭建系统1.1——CentOs安装
- Codeforces Round #433(Div. 2) D. Jury Meeting(贪心)
- Codeforces 766E
- Python Model : glob 文件路径查找
- vaddin使用技巧