日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

Windows进程与线程学习笔记(九)—— 线程优先级/进程挂靠/跨进程读写

發(fā)布時間:2025/3/21 windows 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Windows进程与线程学习笔记(九)—— 线程优先级/进程挂靠/跨进程读写 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Windows進程與線程學習筆記(九)—— 線程優(yōu)先級/進程掛靠/跨進程讀寫

    • 要點回顧
    • 線程優(yōu)先級
      • 調(diào)度鏈表
      • 分析 KiFindReadyThread
      • 分析 KiSwapThread
      • 總結
    • 進程掛靠
      • 進程與線程的關系
      • 進程與線程的關聯(lián)
      • 分析 SwapContext
      • 分析 NtReadVirtualMemory
      • 總結
    • 跨進程讀寫
      • 跨進程讀
      • 跨進程寫
      • 總結

要點回顧

三種情況會導致線程切換

  • 當前線程主動調(diào)用API
    KiSwapThread -> KiSwapContext -> SwapContext
  • 當前線程時間片到期
    KiDispatchInterrupt -> KiQuantumEnd -> SwapContext
  • 存在備用線程(KPCR.PrcbData.NextThread)
    KiDispatchInterrupt -> SwapContext
  • 思考:在KiSwapThread與KiQuantumEnd函數(shù)中都是通過KiFindReadyThread來找下一個要切換的線程,KiFindReadyThread是根據(jù)什么條件來選擇下一個要執(zhí)行的線程呢?

    線程優(yōu)先級

    調(diào)度鏈表

    描述

  • Windows 32位操作系統(tǒng)中,共有32個雙向鏈表(調(diào)度鏈表)
  • Windows 64位操作系統(tǒng)中,共有64個雙向鏈表(調(diào)度鏈表)
  • 線程在調(diào)度鏈表的中下標表示線程優(yōu)先級(0~31/64)
  • 分析 KiFindReadyThread

    查找方式

    按照優(yōu)先級別進行查找:31…30…29…28…
    也就是說,在本次查找中,如果級別31的鏈表里面有線程,那么就不會查找級別為30的鏈表

    注意

  • Windows 32位操作系統(tǒng)中調(diào)度鏈表有32個,由于每次都從頭開始查找效率太低,所以Windows通過一個DWORD類型的變量來記錄:_KiReadySummary
  • 當向調(diào)度鏈表(32個)中掛入或者摘除某個線程時,會判斷當前級別的鏈表是否為空,為空則將 _KiReadySummary 對應位置0,否則置1
  • 若當前級別鏈表的鏈表頭鏈表尾的值相同,并且等于它們的地址,說明不存在等待調(diào)度的線程
    若當前級別鏈表的鏈表頭鏈表尾的值相同,但不等于它們的地址,說明存在一個等待調(diào)度的線程
  • 多cpu會隨機尋找 KiDispatcherReadyListHead 指向的數(shù)組中的線程。線程可以綁定某個cpu(API:setThreadAffinityMask
  • 若當前CPU不存在就緒線程,則會執(zhí)行空閑線程,每一個CPU都會指定一個空閑線程nt!_KPRCB+0x004 CurrentThread : Ptr32 _KTHREAD //當前線程+0x008 NextThread : Ptr32 _KTHREAD //就緒線程+0x00c IdleThread : Ptr32 _KTHREAD //空閑線程
  • 分析 KiSwapThread



    總結

  • 調(diào)度鏈表的下標即線程優(yōu)先級
  • CPU通過遍歷調(diào)度鏈表判斷是否存在需要調(diào)度的線程
  • 若不存在需要調(diào)度的線程,則會執(zhí)行空閑線程(_KPRCB.IdleThread
  • 進程掛靠

    進程與線程的關系

  • 一個進程可以包含多個線程
  • 一個進程至少要有一個線程
  • 進程為線程提供資源,也就是提供Cr3的值,Cr3中存儲的是頁目錄表基址
  • Cr3確定了,線程能訪問的內(nèi)存也就確定了
  • :CPU解析線程代碼 mov eax,dword ptr ds:[0x12345678]

  • CPU解析線性地址時要通過頁目錄表來找對應的物理頁,頁目錄表基址存在
    Cr3寄存器中
  • 當前的Cr3的值來源于當前的進程(_KPROCESS.DirectoryTableBase(+0x018))
  • 進程與線程的關聯(lián)

  • 資源提供者(養(yǎng)父母):_ETHREAD.Tcb.ApcState.Process
  • 線程創(chuàng)建者(親生父母):_ETHREAD.ThreadsProcess
  • 一般情況下,_ETHREAD.Tcb.ApcState.Process_ETHREAD.ThreadsProcess 指向的是同一個進程
  • 將當前Cr3的值改為其它進程的Cr3,稱為“進程掛靠

    mov cr3, A.DirectoryTableBase
    mov eax,dword ptr ds:[0x12345678] //A進程的0x12345678內(nèi)存
    mov cr3, B.DirectoryTableBase
    mov eax,dword ptr ds:[0x12345678] //B進程的0x12345678內(nèi)存
    mov cr3, C.DirectoryTableBase
    mov eax,dword ptr ds:[0x12345678] //C進程的0x12345678內(nèi)存

  • 思考:在一份線程結構體中,存在著兩個指向當前線程所屬進程的指針,那么究竟是哪個提供了Cr3?
    答案:線程切換的時候,會比較兩個線程的EPROCESS是否為同一個,若不是同一個,則會將 _ETHREAD.Tcb.ApcState.Process 指向的 EPROCESS的DirectoryTableBase 取出,賦值給Cr3

    分析 SwapContext

    分析 NtReadVirtualMemory


    MmCopyVirtualMemory:

    MiDoPoolCopy:

    KeStackAttachProcess:

    KiAttachProcess:


    KiSwapProcess:

    思考:可不可以只修改Cr3而不修改養(yǎng)父母?
    答案:不可以,假設剛剛修改完Cr3,還沒讀取內(nèi)存時,發(fā)生了線程切換,當再次切換回來時,會根據(jù)養(yǎng)父母的值為Cr3賦值,Cr3又變回了原來的值,此時將變成自己讀自己。如果我們自己來寫這個代碼,在切換Cr3后關閉中斷,并且不調(diào)用會導致線程切換的API,就可以不用修改養(yǎng)父母的值

    總結

  • 正常情況下,當前線程使用的Cr3是由其所屬進程提供的(_ETHREAD.Tcb.ApcState.Process),正是因為如此,A進程中的線程只能訪問A的內(nèi)存
  • 如果要讓A進程中的線程能夠訪問B進程的內(nèi)存,就必須要修改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 //將數(shù)據(jù)存儲到0x00401234中 mov cr3,A.DirectoryTableBase //切換回Cr3的值

    問題:以上代碼是否存在問題?
    答案:存在問題。當讀取B進程內(nèi)存之后,由于Cr3并未改變,寫入的地址仍為B進程的地址。當Cr3切換回A進程后,A進程中并不存在讀出來的值

    思考:如何解決以上問題?

    跨進程讀

    NtReadVirtualMemory執(zhí)行流程

  • 當前線程的Cr3切換至目標進程的Cr3
  • 將要讀的數(shù)據(jù)復制到高2G(暫存區(qū))
  • 當前線程的Cr3切換至原本進程的Cr3
  • 將要讀的數(shù)據(jù)從高2G復制到目標位置
  • 跨進程寫

    NtWriteVirtualMemory執(zhí)行流程

  • 將當前線程的數(shù)據(jù)復制到高2G(暫存區(qū))
  • 當前線程的Cr3切換至目標進程的Cr3
  • 將要寫入的數(shù)據(jù)從高2G復制到目標位置
  • 當前線程的Cr3切換至原本進程的Cr3
  • 總結

    每個進程的高2G內(nèi)存空間的線性地址對應的物理頁幾乎是相同的,可以通過對高2G內(nèi)存空間的利用,實現(xiàn)跨進程內(nèi)存讀寫的操作

    總結

    以上是生活随笔為你收集整理的Windows进程与线程学习笔记(九)—— 线程优先级/进程挂靠/跨进程读写的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。