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.hqwc.cn/news/127337.html

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

相关文章

MySQL笔记(进阶篇)

包含内容: 存储引擎 索引 SQL优化 视图/存储过程/触发器 锁 InnoDB引擎 MySQL管理 存储引擎 MySQL体系结构 连接层:最上层是一些客户端和连接服务,主要完成一些类似于连接处理,授权认证,及相关的安全方案.服务器也会为安全接入的每个客户验证它所…

AXI总线协议基础--几分钟熟悉通道信号和基础架构

目录 一、AXI协议基础 1.1读写通道的基本架构图 1.2猝发操作举例 1.3传输顺序 二、各个通道中的信号描述 2.1全局信号 2.2写地址通道信号 2.3写数据通道信号 2.4写响应通道信号 2.5读地址通道信号 2.6读数据通道 三、通道握手 3.1单一信息传输时的握手过程 3.2不…

为Xshell生成密钥,实现免密登录远程Linux服务器

1、为Xshell生成密钥 依次打开Xshell-->工具-->新建用户密钥生成向导。 打开如下图所示的生产密钥参数窗口。 按默认参数,直接单击“下一步”按钮,直到如下图所示的用户密钥信息对话框。 在该界面,可以设置密钥名称,并设置…

用《斗破苍穹》的视角打开C#3 标签与反射(人物创建与斗技使用)

随着剧情的发展,主线人物登场得越来越多,时不时跳出一个大佬,对我张牙舞爪地攻击。眼花缭乱的斗技让我不厌其烦,一个不小心,我就记不清楚在哪里遇上过什么人,他会什么斗技了。这时候,我就特别希…

[CISCN2019 华北赛区 Day1 Web5]CyberPunk 二次报错注入

buu上 做点 首先就是打开环境 开始信息收集 发现源代码中存在?file 提示我们多半是包含 我原本去试了试 ../../etc/passwd 失败了 直接伪协议上吧 php://filter/readconvert.base64-encode/resourceindex.phpconfirm.phpsearch.phpchange.phpdelete.php 我们通过伪协议全…

JUC第十七讲:JUC集合: ConcurrentLinkedQueue详解

JUC第十七讲:JUC集合: ConcurrentLinkedQueue详解 本文是JUC第十七讲:JUC集合 - ConcurrentLinkedQueue详解。ConcurerntLinkedQueue一个基于链接节点的无界线程安全队列。此队列按照 FIFO(先进先出)原则对元素进行排序。队列的头部是在队列中时间最长的…

css自学框架之选项卡

这一节我们学习切换选项卡,两种切换方式,一种是单击切换选项,一种是鼠标滑动切换,通过参数来控制,切换方法。 一、参数 属性默认值描述tabBar.myth-tab-header span鼠标触发区域tabCon.myth-tab-content主体区域cla…

Mybatis 拦截器(Mybatis插件原理)

Mybatis为我们提供了拦截器机制用于插件的开发,使用拦截器可以无侵入的开发Mybatis插件,Mybatis允许我们在SQL执行的过程中进行拦截,提供了以下可供拦截的接口: Executor:执行器ParameterHandler:参数处理…

敲代码之余的表情包

欢迎来到上班休息区,请交出你的程序员专属表情包!你可以从以下几个方面进行创作(仅供参考)此为内容创作模板,在发布之前请将不必要的内容删除 方向一:分享你最喜欢的表情包 提示:请至少分享5个…

SpringBoot 如何使用 JWT 实现身份认证和授权

Spring Boot 使用 JWT 实现身份认证和授权 JSON Web Token(JWT)是一种用于在网络应用之间安全传递信息的开放标准。它使用了一种紧凑且独立于语言的方式在各方之间传递信息,通常用于在客户端和服务器之间验证用户身份和授权访问资源。本文将…

若依分离版-前端使用

1 执行 npm install --registryhttps://registry.npm.taobao.org,报错信息如下 npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resolving: ktg-mes-ui3.8.2 npm ERR! Found: vue2.6.12 npm ERR! node_modu…

第81步 时间序列建模实战:Adaboost回归建模

基于WIN10的64位系统演示 一、写在前面 这一期,我们介绍AdaBoost回归。 同样,这里使用这个数据: 《PLoS One》2015年一篇题目为《Comparison of Two Hybrid Models for Forecasting the Incidence of Hemorrhagic Fever with Renal Syndr…