x64内核实验7-线程

x64内核实验7-线程

TOC
线程是比较重要的内核结构,思考一下其实可以想到线程结构体在64位下的变化应该不会很大最多只是扩充了一些内容,因为从我们之前分析段页时候会发现cpu更新的这些内容大部分不影响xp时候的线程切换机制,下面我们来验证一下

线程结构体介绍

ETHREAD和KPCR都有点大就不全贴出来了只说一些常用的字段,一般熟悉了内核机制的话看名字很多都能猜出来

KTHREAD + 0x000     struct _DISPATCHER_HEADER Header;   跟之前的进程结构体一样是可等待对象都有的头部结构体
KTHREAD + 0x018    VOID*        SListFaultAddress   上一次用户模式互锁单链表POP操作发生页面错误的地址。
KTHREAD + 0x028     VOID*        InitialStack;            内核栈的原始栈位置(高地址)
KTHREAD + 0x030     VOID*        StackLimit;             内核栈低地址
KTHREAD + 0x038    VOID*        StackBase;              内核栈的栈基址
KTHREAD + 0x058    VOID*        KernelStack;            内核调用栈开始位置
KTHREAD + 0x0C8     INT64        WaitStatus            等待的结果状态
KTHREAD + 0x0F0     VOID*        Teb                         三环使用的线程环境块
----------------------------------Apc相关的后面说Apc时候会讲
KTHREAD + 0x098      ApcState         _KAPC_STATE        ApcState结构体
KTHREAD + 0x258     SavedApcState   KAPC_STATE    备份ApcState结构体
KTHREAD + 0x24a     ApcStateIndex    UChar                索引ApcState时候用的
----------------------------------Apc相关的后面说Apc时候会讲
KTHREAD + 0x184     State             UChar                    线程当前状态
KTHREAD + 0x090     TrapFrame    _KTRAP_FRAME            指向Trap_Frame结构体
KTHREAD + 0x232     PreviousMode   Char                存储了当前线程之前的模式是内核模式还是用户模式
KTHREAD + 0x2f8     ThreadListEntry  _LIST_ENTRY            KTHREAD里的双向链表串起当前进程的所有线程ETHREAD + 0x4e8     ThreadListEntry  _LIST_ENTRY         在Ethread里的这个链表也是圈起来了当前进程所有的线程
ETHREAD + 0x478     Cid              _CLIENT_ID        线程的Cid
ETHREAD + 0x220     Process          Ptr64 _KPROCESS        指向当前进程结构体

KPCR结构体介绍

KPCR是cpu控制区,一个核心一个KPCR对象,里面存放的大多是cpu相关的一些数据以及进程线程相关的一些常用数据
因为0环时候gs:0指向它所以无论在那个内核函数里都能很快的访问到这个结构体
KPCR和NTTIB比较小直接全贴出来了

0: kd> dt _NT_TIB
ntdll!_NT_TIB+0x000 ExceptionList    : Ptr64 _EXCEPTION_REGISTRATION_RECORD        当前的0环异常链表+0x008 StackBase        : Ptr64 Void                                   从线程里复制出来的栈位置+0x010 StackLimit       : Ptr64 Void                                    从线程里复制出来的栈低地址+0x018 SubSystemTib     : Ptr64 Void+0x020 FiberData        : Ptr64 Void+0x020 Version          : Uint4B+0x028 ArbitraryUserPointer : Ptr64 Void+0x030 Self             : Ptr64 _NT_TIB                            指向自己0: kd> dt _KPCR
ntdll!_KPCR+0x000 NtTib            : _NT_TIB+0x000 GdtBase          : Ptr64 _KGDTENTRY64+0x008 TssBase          : Ptr64 _KTSS64                            指向Tss+0x010 UserRsp          : Uint8B                                    指向用户层的栈+0x018 Self             : Ptr64 _KPCR                                指向自己+0x020 CurrentPrcb      : Ptr64 _KPRCB                               指向自己的KPRCB的位置+0x028 LockArray        : Ptr64 _KSPIN_LOCK_QUEUE                    +0x030 Used_Self        : Ptr64 Void+0x038 IdtBase          : Ptr64 _KIDTENTRY64                            指向IDT表基址+0x040 Unused           : [2] Uint8B                            +0x050 Irql             : UChar                                         存储了当前的irql+0x051 SecondLevelCacheAssociativity : UChar        +0x052 ObsoleteNumber   : UChar    +0x053 Fill0            : UChar+0x054 Unused0          : [3] Uint4B+0x060 MajorVersion     : Uint2B+0x062 MinorVersion     : Uint2B+0x064 StallScaleFactor : Uint4B+0x068 Unused1          : [3] Ptr64 Void+0x080 KernelReserved   : [15] Uint4B+0x0bc SecondLevelCacheSize : Uint4B+0x0c0 HalReserved      : [16] Uint4B+0x100 Unused2          : Uint4B+0x108 KdVersionBlock   : Ptr64 Void+0x110 Unused3          : Ptr64 Void+0x118 PcrAlign1        : [24] Uint4B+0x180 Prcb             : _KPRCB                                下面是KPRCB一个很大的结构体KPRCB有点大只介绍常用的字段了KPRCB + 0x008 CurrentThread    : Ptr64 _KTHREAD  当前线程
KPRCB + 0x004 LegacyNumber     : UChar             是否是兼容模式,兼容模式时候启动是是32位内核了
KPRCB + 0x010 NextThread       : Ptr64 _KTHREAD    下一个线程
KPRCB + 0x018 IdleThread       : Ptr64 _KTHREAD    空闲线程,一般cpu空闲时候就会执行这个线程
KPRCB + 0x028 RspBase          : Uint8B            内核栈
KPRCB + 0x8e88 RspBaseShadow    : Uint8B            kpti开启时候使用的跳板0环栈
KPRCB + 0x8e90 UserRspShadow    : Uint8B            3环栈
KPRCB + 0x7e9a DeepSleep        : UChar             深睡眠模式,在线程切换时候会查询不过不用太多关注跟硬件也有关系
KPRCB + 0x7e80 InterruptCount   : Uint4B            中断次数,在下面的逆向代码里能看到增加这个中断次数的代码
KPRCB + 

寻找线程切换函数

根据白皮书里描述30号中断为时钟中断,线程切换一定跟时钟中断相关,那么我们就先找一下时钟中断的函数叫什么

1: kd> !idt 30Dumping IDT: ffffba81de9d500030:	fffff80281402230 nt!KiHvInterrupt

通过在windbg里查看可以知道时钟中断函数是KiHvInterrupt,我们到ida里搜一下可以搜到下面几个
在这里插入图片描述

因为我的虚拟机环境默认是没开kpti的所以中断函数直接指向了KiHvInterrupt如果开了的话则是指向KiHvInterruptShadow,不过不要紧我们之前分析过int 3的那个Shadow函数这个KiHvInterruptShadow跟那个基本一样,我这里只贴个图上来就不详细说这个跳板函数了
在这里插入图片描述

下面我们就看一下这个KiHvInterrupt函数
一开始就还是熟悉的保存trapframe流程
在这里插入图片描述

中间是硬件相关的一堆调用不管
在这里插入图片描述

然后就是存浮点相关,之后是一些检测然后增加中断次数跳到KiHvInterruptDispatch
我们再看一下KiHvInterruptDispatch
在这里插入图片描述

我们再看一下KiDpcInterruptBypass
在这里插入图片描述

又调用了KiDispatchInterrupt
在这里插入图片描述

在跟进去会发现我们要找的函数,swapContext
在这里插入图片描述

swapContext就是我们要找的线程切换函数
现在我们记录一下win10系统下时钟中断进入线程切换的函数调用流程吧

  1. KiHvInterruptShadow(开了kpti的话有这一步)
  2. KiHvInterrupt
  3. KiHvInterruptDispatch
  4. KiDpcInterruptBypass
  5. KiDispatchInterrupt
  6. KxDispatchInterrupt
  7. SwapContext

这个流程里有大量的代码有兴趣深入研究的可以按照这个流程看一下,线程切换涉及到了很多系统内核的其他内容我们这里下面直接分析SwapContext

线程切换函数逆向分析

先看一下进入SwapContext之前都传了那些参数进来,可以看到先是调用KiQueueReadyThread找到要切换的线程
大家可以自己到这个函数里分析一下
从KiDpcInterruptBypass这里开始看

在这里插入图片描述

现在的寄存器值是
rsp = trapframe
rbp =TRAP_FRAME + 80
rcx = CurrentThread
然后走到KiDispatchInterrupt
在这里插入图片描述

看图中圈出来的位置,rsp在调用KxDispatchInterrupt之前又恢复成了trapframe,所以现在的寄存器状态还是
rsp = trapframe
rbp = TRAP_FRAME + 80
rcx = CurrentThread
rbx = kpcr + 20

在这里插入图片描述

再看一下SwapContext都干了什么,我这里不一行一行去说了这个函数超级长,我把主要流程截图出来大家最好自己去逆一下会有自己的理解
先是判断要切换的线程是不是就是当前线程,是的话就不处理了,不是的话走下面更改线程状态
在这里插入图片描述

在这里插入图片描述

这里是切换线程的栈
在这里插入图片描述

判断俩线程是不是同一个进程不是的话要切换cr3
在这里插入图片描述

在这里插入图片描述

走到这里再往下就是收尾的动作了,就是复制进程和线程内容到kpcr里的过程
在这里插入图片描述

总结

我们最后总结一下
线程切换的流程(这个总体流程跟xp时候差不多只不过调用的函数链路变了而且多了不少的检测和动作):

  1. 当前线程保存上下文环境到内核栈
  2. 找到一个就绪线程
  3. 切换线程的内核栈
  4. 如果需要切换cr3就切换
  5. 复制信息到kpcr,比如线程结构体里的内核栈位置或者往tss里存进0环时候要用的ist0
  6. 从刚切换的线程内核栈里恢复上下文环境

触发线程切换的条件(这里只带大家看了时钟中断其他的几个场景大家可以自己去验证一下):

  1. 时钟中断
  2. 缺页异常
    环境到内核栈
  3. 找到一个就绪线程
  4. 切换线程的内核栈
  5. 如果需要切换cr3就切换
  6. 复制信息到kpcr,比如线程结构体里的内核栈位置或者往tss里存进0环时候要用的ist0
  7. 从刚切换的线程内核栈里恢复上下文环境

触发线程切换的条件(这里只带大家看了时钟中断其他的几个场景大家可以自己去验证一下):

  1. 时钟中断
  2. 缺页异常
  3. 系统api出0环

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

初识链表(7.25)

前面我们学习了顺序表,但顺序表其实存在一些问题 1. 中间/头部的插入删除,时间复杂度为O(N) 2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗(尤其是异地扩容)。 3. 增容一般是呈2倍的增长&am…

【Java 进阶篇】深入了解JDBCTemplate:简化Java数据库操作

数据库操作是几乎所有现代应用程序的一部分。从存储和检索数据到管理业务逻辑,数据库操作是不可或缺的。在Java应用程序中,JDBCTemplate是一种强大的工具,可帮助开发人员轻松进行数据库操作。本文将深入探讨JDBCTemplate,了解它的…

【gcc】RtpTransportControllerSend学习笔记 1

本文是大神 https://www.cnblogs.com/ishen 的文章的学习笔记。主要是大神文章: webrtc源码分析(8)-拥塞控制(上)-码率预估 的学习笔记。大神的webrtc源码分析(8)-拥塞控制(上)-码率预估 详尽而具体,堪称神作。因为直接看大神的文章,自己啥也没记住,所以同时跟着看代码。跟…

二蛋赠书四期:《Go编程进阶实战:开发命令行应用、HTTP应用和gRPC应用》

前言 大家好!我是二蛋,一个热爱技术、乐于分享的工程师。在过去的几年里,我一直通过各种渠道与大家分享技术知识和经验。我深知,每一位技术人员都对自己的技能提升和职业发展有着热切的期待。因此,我非常感激大家一直…

Java类加载机制

一、java类加载机制 类加载分为三个步骤:加载,连接,初始化: 1. JVM中类的装载是由类加载器(ClassLoader)和它的子类来实现的,Java中的类加载器是一个重要的Java运行时系统组件,它负…

设备上架与调试步骤项目篇

1.设备又哪些常见的调试方法? 2.设备开箱 -> 使用的步骤是什么? 3.开局新设备都要设置哪些功能? -- 工程师:架构设计 项目实施 故障排查 -- 调试设备: -- 1.WEB界面 - 界面调试 - 内容比较少的 主要项目 …

Zygote Secondary:加速应用启动的未来之路

Zygote Secondary:加速应用启动的未来之路 1. 引言 在现代的移动应用开发中,启动速度和响应性能是用户体验的重要方面。然而,传统的 Android 进程管理方式在启动应用时会出现性能瓶颈,导致启动时间过长和资源占用过多。为了解决…

2023/9/28 -- ARM

【内存读写指令】 int *p0X12345678 *p100;//向内存中写入数据 int a *p;//从内存读取 1.单寄存器内存读写指令 1.1 指令码以及功能 向内存中写: str:向内存中写一个字(4字节)的数据 strh:向内存写半个字(2字节)的数据 strb:向内存写一个字…

连接虚拟机工具推荐

连接虚拟机工具推荐 连接虚拟机的工具有很多种,以下是一些常用的推荐: PuTTY:这是一个非常常用的SSH和telnet客户端,适用于Windows系统。它允许你在本地机器上通过命令行接口远程登录到虚拟机。 SecureCRT:这是一个支…

202. 最幸运的数字

202. 最幸运的数字 - AcWing题库 #include<bits/stdc.h> #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define endl \nusing namespace std;typedef pair<int, int> PII; typedef long long ll; typedef long double ld;ll qmi(ll a, ll k, ll m…

微信小程序-2

微信开发文档 https://developers.weixin.qq.com/miniprogram/dev/framework/ 一、app.js中的生命周期函数与globalData(全局变量) 指南 - - - 小程序框架 - - - 注册小程序 删除app.js里的东西&#xff0c;输入App回车&#xff0c;调用生命周期 选项 - - - 重新打开此项目…

Scala第十八章节

Scala第十八章节 scala总目录 文档资料下载 章节目标 掌握Iterable集合相关内容.掌握Seq集合相关内容.掌握Set集合相关内容.掌握Map集合相关内容.掌握统计字符个数案例. 1. Iterable 1.1 概述 Iterable代表一个可以迭代的集合, 它继承了Traversable特质, 同时也是其他集合…

【数据分析】时间序列

UTC时间&#xff1a;时间戳是以格林威治时间1970年01月01日00时00分00秒为基准计算所经过时间的秒数&#xff0c;是一个浮点数。Python的内置模块time和datetime都可以对时间格式数据进行转换&#xff0c;如时间戳和时间字符串的相互转换。 报错记录&#xff1a;AR has been re…

分层强化学习 综述论文阅读 Hierarchical Reinforcement Learning: A Comprehensive Survey

分层强化学习 综述论文阅读 Hierarchical Reinforcement Learning: A Comprehensive Survey 摘要一、介绍二、基础知识回顾2.1 强化学习2.2 分层强化学习2.2.1 子任务符号2.2.2 基于半马尔可夫决策过程的HRL符号 2.3 通用项定义 三、分层强化学习方法3.1 学习分层策略 (LHP)3.1…

【yolo系列:yolov7改进wise-iou】

yolo系列文章目录 学习视频&#xff1a; YOLOV7改进-Wise IoU_哔哩哔哩_bilibili 代码地址&#xff1a; objectdetection_script/yolov7-iou.py at master z1069614715/objectdetection_script (github.com) 文章目录 yolo系列文章目录一、在yolov7之上进行替换二、在loss.p…

大语言模型之十六-基于LongLoRA的长文本上下文微调Llama-2

增加LLM上下文长度可以提升大语言模型在一些任务上的表现&#xff0c;这包括多轮长对话、长文本摘要、视觉-语言Transformer模型的高分辨4k模型的理解力以及代码生成、图像以及音频生成等。 对长上下文场景&#xff0c;在解码阶段&#xff0c;缓存先前token的Key和Value&#…

新文件覆盖旧文件还能复原吗,3个方法快速恢复覆盖文件!

iPhone在解压压缩文件时&#xff0c;不小心将同名文件进行了覆盖&#xff0c;怎么撤回&#xff1f; 在使用U盘转移文档时&#xff0c;意外将同名文档进行了替换&#xff0c;怎么恢复&#xff1f; 当误将重名文件进行了替换&#xff0c;如何找回这些被覆盖的旧文件&#xff1f;…

oracle linux8.8上安装oracle 19c集群

1、操作系统版本告警 处理办法&#xff1a;export CV_ASSUME_DISTIDRHEL7.6 2、ssh互信故障 查看ssh版本 [rootdb1 ~]# ssh -V OpenSSH_8.0p1, OpenSSL 1.1.1k FIPS 25 Mar 2021 处理办法-2个节点都需要操作 安装前配置 # mv /usr/bin/scp /usr/bin/scp.orig # echo "…

解决 Jenkins 性能缓慢的问题~转

解决 Jenkins 性能缓慢的问题 Docker中文社区 ​​ 计算机技术与软件专业技术资格持证人 2 人赞同了该文章 没有什么比缓慢的持续集成系统更令人沮丧的了。它减慢了反馈循环并阻止代码快速投入生产。虽然像使用性能更好的服务器可以为您争取时间&#xff0c;但您最终必须投资…

c++day1

#include <iostream> //#预处理 using namespace std; //using :使用命名空间的关键字 //namespace:命名空间的关键字 //std:标准的命名空间//程序入口 int main() {//程序的开始int daxie 0,xiaoxie 0,sum 0, kong 0,other 0;string str;getline(cin , str);for(in…