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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

进程线程007 进程挂靠与跨进程读写内存

發(fā)布時間:2025/3/21 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 进程线程007 进程挂靠与跨进程读写内存 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

    • 進程掛靠
      • 進程與線程的關(guān)系
      • 線程與進程如何關(guān)聯(lián)
      • 為什么需要ApcState.Process
      • CR3的值可以隨便改嗎
      • 分析NtReadVirtualMemory函數(shù)
      • 總結(jié)
    • 跨進程讀寫內(nèi)存
      • 跨進程操作
      • NtReadVirtualMemory流程解析

進程掛靠

進程與線程的關(guān)系

一個進程可以包含多個線程

一個進程至少要有一個線程

進程為線程提供資源,也就是提供CR3的值,CR3中存儲的是頁目錄表的基址,CR3確定了線程能訪問的內(nèi)存也就確定了

mov eax,dowrd ptr ds:[0x12345678]

CPU如何解析0x12345678這個地址呢?

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

    ETHREAD結(jié)構(gòu)體:+0x034 ApcState+0x000 ApcListHead +0x010 Process +0x014 KernelApcInProgress+0x015 KernelApcPending+0x016 UserApcPending+0x220 ThreadsProcess

    ETHREAD結(jié)構(gòu)體+0x220的位置存儲的就是當(dāng)前線程所屬的進程。

    另外在KTHREAD結(jié)構(gòu)體0x34的位置是子結(jié)構(gòu)體ApcState,ApcState也有一個成員Process指向了當(dāng)前線程所屬的進程。

    這就存在一個問題,同一個線程結(jié)構(gòu)體里存了兩份指針,這兩份指針代表什么?

    為什么需要ApcState.Process

    下面分析SwapContext函數(shù):

    這里首先取出目標(biāo)線程的ApcState.Process存到eax里,然后比較當(dāng)前線程的ApcState.Process和目標(biāo)線程的這個成員是否相同,如果不相同就說明不屬于同一個進程

    代碼繼續(xù)往下走,就會切換CR3的值

    線程切換的時候,會比較KTHREAD結(jié)構(gòu)體0x044處指定的EPROCESS是否為同一個,如果不是同一個,會將eax的值取出,賦給CR3。eax此時存儲的是目標(biāo)線程的ApcState.Process。這個時候就發(fā)生了進程切換

    所以,線程需要的CR3的值來源于0x44處偏移指定的EPROCESS

    總結(jié):

    0x220親生父母:這個線程誰創(chuàng)建的

    0x44 養(yǎng)父母:誰在為這個線程提供資源,也就是提供CR3

    一般情況下,0x220與0x44指向的是同一個進程

    CR3的值可以隨便改嗎

    正常情況下,CR3的值是由養(yǎng)父母提供的,但CR3的值也可以改成和當(dāng)前線程毫不相關(guān)的其他進程的DirectoryTableBase

    線程代碼:

    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)存

    將當(dāng)前cr3的值改為其他進程,稱為進程掛靠

    分析NtReadVirtualMemory函數(shù)

    接下來就通過分析NtReadVirtualMemory函數(shù),來看看是怎么讀取其他進程的內(nèi)存。

    [外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-hprSWzoq-1581511027410)(assets/1581507589446.png)]

    首先找到NtReadVirtualMemory函數(shù)

    這個函數(shù)在內(nèi)部調(diào)用了MmCopyVirtualMemory,繼續(xù)跟進

    真正COPY的函數(shù)是MiDoMappedCopy,繼續(xù)跟進

    在開始讀取之前先調(diào)用了KeStackAttachProcess,也就是之前說過的進程掛靠,繼續(xù)

    這個函數(shù)又繼續(xù)調(diào)用了KiAttachProcess,繼續(xù)跟進

    這里先將該線程的+0x44位置的ApcState.Process修改為要讀取的進程的KPROCESS

    然后又調(diào)用KiSwapProcess,真正的掛靠是通過這個函數(shù)實現(xiàn)的,繼續(xù)跟進

    真正關(guān)鍵的代碼是上面兩行,首先取出要讀取進程的CR3,+0x18的位置是DirectoryTableBase頁目錄表基址,然后修改CR3為要讀取進程的CR3

    NtReadVirtualMemory流程總結(jié)

  • NtReadVirtualMemory
  • MmCopyVirtualMemory
  • MiDoMappedCopy
  • KeStackAttachProcess
  • KiAttachProcess 修改當(dāng)前線程的ApcState.Process為要掛靠的進程
  • KiSwapProcess修改CR3為要掛靠的進程的CR3
  • 既然修改CR3就可以讀取目標(biāo)進程的內(nèi)存,那么NtReadVirtualMemory可不可以只修改CR3,不修改當(dāng)前線程的ApcState.Process為要掛靠的進程。

    答案是不可以。

    回顧一下之前的為什么需要ApcState.Process的問題就會發(fā)現(xiàn),當(dāng)調(diào)用SwapContext進行線程切換的時候,給CR3賦值的時候賦的是ApcState.Process的值。

    如果沒有修改ApcState.Process,那就意味著ApcState.Process指向的不是掛靠的進程,而是自己的父進程,一旦這個時候發(fā)生線程切換并且在線程切換回來的時候,NtReadVirtualMemory讀取的就是自己進程的內(nèi)存了。

    如果我們自己來寫這個代碼,在切換CR3后關(guān)閉中斷,并且不調(diào)用會導(dǎo)致線程切換的API,就可以不用修改養(yǎng)父母的值

    總結(jié)

    正常情況下,當(dāng)前線程使用的CR3是由其所屬進程提供的(ETHREAD 0x44偏移處指定的EPROCESS),正因為如此,A進程中的線程只能訪問A進程的內(nèi)存

    如果要讓A進程中的內(nèi)容能夠訪問B進程的內(nèi)存,就必須修改CR3的值為B進程的頁目錄表基址(DirectoryTableBase),這就是所謂的進程掛靠

    跨進程讀寫內(nèi)存

    跨進程的本質(zhì)就是進程掛靠,也就是修改CR3的值為目標(biāo)進程的頁目錄表基址

    跨進程操作

    A進程中的線程代碼

    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的值

    這段代碼的問題在于,當(dāng)我切換CR3為B進程的頁目錄基址時,讀取的是B進程的內(nèi)存,那么讀取的這段數(shù)據(jù)該如何傳遞給A進程呢?不管將這段數(shù)據(jù)放在哪個位置,始終都是B進程的內(nèi)存空間。

    這里需要回顧一下進程的地址空間管理,低2GB是每個進程私有的,而高2GB的操作系統(tǒng)共享的。如果在B進程將讀取的數(shù)據(jù)放到高2GB共享的內(nèi)核空間,然后在切回CR3的時候,從高2GB取數(shù)據(jù),就解決了這個問題

    NtReadVirtualMemory流程解析

    我們來看一下NtReadVirtualMemory是如何解決這個問題的:

  • 首先切換CR3為目標(biāo)進程的頁目錄基址
  • 接著將數(shù)據(jù)復(fù)制到高2GB的某一個位置
  • 然后切回CR3
  • 最后從高2GB復(fù)制到目標(biāo)位置
  • NtWriteVirtualMemory和NtReadVirtualMemory的執(zhí)行流程類似

    總結(jié)

    以上是生活随笔為你收集整理的进程线程007 进程挂靠与跨进程读写内存的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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