APC 篇——初識 APC

寂靜的羽夏發表於2022-01-26

寫在前面

  此係列是本人一個字一個字碼出來的,包括示例和實驗截圖。由於系統核心的複雜性,故可能有錯誤或者不全面的地方,如有錯誤,歡迎批評指正,本教程將會長期更新。 如有好的建議,歡迎反饋。碼字不易,如果本篇文章有幫助你的,如有閒錢,可以打賞支援我的創作。如想轉載,請把我的轉載資訊附在文章後面,並宣告我的個人資訊和本人部落格地址即可,但必須事先通知我

你如果是從中間插過來看的,請仔細閱讀 羽夏看Win系統核心——簡述 ,方便學習本教程。

  看此教程之前,問幾個問題,基礎知識儲備好了嗎?保護模式篇學會了嗎?練習做完了嗎?沒有的話就不要繼續了。


? 華麗的分割線 ?


APC 結構

  上一篇我們簡單介紹了APC的概念。有些人可能對為什麼執行緒不能被“殺掉”、“掛起”和“恢復”還是有些疑問,我們舉個極端的例子:如果不呼叫API,遮蔽中斷,並保證程式碼不出現異常,執行緒將永久佔用CPU,何談控制呢?所以說執行緒如果想“死”,一定是自己執行程式碼把自己殺死,不存在“他殺”這種情況。我們可以畫個簡單的示意圖:

APC 篇——初識 APC

  下面我們來看看儲存APC的結構體:

kd> dt _KAPC
ntdll!_KAPC
   +0x000 Type             : Int2B
   +0x002 Size             : Int2B
   +0x004 Spare0           : Uint4B
   +0x008 Thread           : Ptr32 _KTHREAD
   +0x00c ApcListEntry     : _LIST_ENTRY
   +0x014 KernelRoutine    : Ptr32     void 
   +0x018 RundownRoutine   : Ptr32     void 
   +0x01c NormalRoutine    : Ptr32     void 
   +0x020 NormalContext    : Ptr32 Void
   +0x024 SystemArgument1  : Ptr32 Void
   +0x028 SystemArgument2  : Ptr32 Void
   +0x02c ApcStateIndex    : Char
   +0x02d ApcMode          : Char
   +0x02e Inserted         : UChar

  存在於KTHREAD結構體的0x34偏移的位置有一個ApcState,如下所示:

kd> dt _KTHREAD
nt!_KTHREAD
    ...
       +0x034 ApcState         : _KAPC_STATE
    ...

  我們看到這個存著一個結構體,如下所示:

kd> dt _KAPC_STATE
ntdll!_KAPC_STATE
   +0x000 ApcListHead      : [2] _LIST_ENTRY
   +0x010 Process          : Ptr32 _KPROCESS
   +0x014 KernelApcInProgress : UChar
   +0x015 KernelApcPending : UChar
   +0x016 UserApcPending   : UChar

ApcListHead

  第一個成員ApcListHead是個雙向連結串列的陣列,一共有兩個成員,所謂的APC就是插入到裡面的,給個示意圖如下:

APC 篇——初識 APC

  ApcListHead一個成員儲存著使用者APC,使用者APC的函式地址位於使用者空間,在使用者空間執行;另一個成員儲存著核心APC,核心APC函式地址位於核心空間,在核心空間執行。

Process

  執行緒執行緒所屬或者所掛靠的程式,這個在逆向執行緒切換的時候我們就用過。具體細節都在程式執行緒篇的總結與提升講過,就不再贅述了。

KernelApcInProgress

  指示核心APC是否正在執行。

KernelApcPending

  指示是否有正在等待執行的核心APC

UserApcPending

  指示是否有正在等待執行的使用者APC

小結

  上面的介紹僅僅是對APC的初步講解,裡面所有的詳細細節將在後面的教程講解。後面會詳細介紹KAPC這個結構體,並研究APC是誰插入的、插入到哪裡、誰執行APC和什麼時候執行APC。本篇是對後面學習的鋪墊。

本節練習

本節的答案將會在下一節進行講解,務必把本節練習做完後看下一個講解內容。不要偷懶,實驗是學習本教程的捷徑。

  俗話說得好,光說不練假把式,如下是本節相關的練習。如果練習沒做好,就不要看下一節教程了,越到後面,不做練習的話容易夾生了,開始還明白,後來就真的一點都不明白了。本節練習不多,請保質保量的完成。

1️⃣ 使用現成提供的API,自己編寫程式碼向某個執行緒插入一個使用者APC
2️⃣ 分析TerminateThreadSuspendThread是如何實現的(從3環開始分析)。(要求:只需逆向分析到別的程式是如何控制目標程式行為,其他細節暫時不需分析)

下一篇

  APC 篇——備用 APC 佇列

相關文章