逆向 API AuxKlibQueryModuleInformation 枚舉內核驅動列表的實現

http://dy.163.com/v2/article/detail/F70H7RS20511CJ6O.htmlhtml


  

  本文,我將介紹對AuxKlibQueryModuleInformation進行逆向工程的解決方案。其中,咱們會提到驅動程序可使用記錄的API AuxKlibQueryModuleInformation枚舉全部加載的模塊。這個API是否保證返回的模塊列表老是最新的?爲了回答這個問題,咱們要對Windows 8的AuxKlibQueryModuleInformation進行逆向工程,並解釋它是如何工做的。當多個線程請求訪問加載的模塊列表時,它如何處理這種狀況?注意:處理此請求和其餘請求的內部函數至關大,所以須要一些耐心。或者,你可使用調試器來幫助你跟蹤感興趣的代碼。
python

  首先,讓咱們將其劃分爲咱們須要執行的任務:git

  1.這個API (AuxKlibQueryModuleInformation)是否保證返回的模塊列表老是最新的?github

  2.對Windows 8的AuxKlibQueryModuleInformation進行逆向工程,並解釋其工做原理。json

  3.當多個線程請求訪問已加載的模塊列表時,它如何處理這種狀況?windows

  爲了解決這個問題,咱們將使用IDA對函數進行靜態反向工程。在本文的示例中,咱們將不使用反編譯器來讀取彙編代碼。使用反編譯器能夠節省大量時間,可是學習如何在反彙編窗口中導航對於逆向工程頗有價值。安全

  什麼是「AuxKlibQueryModuleInformation」?框架

  MSDN: The AuxKlibQueryModuleInformation例程檢索有關操做系統已加載的映像模塊的信息。函數

  NTSTATUS AuxKlibQueryModuleInformation(工具

  PULONG BufferSize,

  ULONG ElementSize,

  PVOID QueryInfo

  );

  聽起來它應該返回一個映像列表,不過,這些只是猜想,這些映像是加載到內存中的映像仍是僅加載到內核中的映像,咱們稍後將對此進行檢查。

  所以,要回答第一個問題,咱們的第一個子任務是找到' AuxKlibQueryModuleInformation '是在哪裏實現的。

  在搜索ntoskrnl.exe時,咱們沒有找到該函數。這意味着它必須在其餘地方聲明,經過查看該文檔,咱們就能夠看到這個函數是在aux_klib.h中聲明的,所需的庫是aux_klib.lib。

  LIB文件是靜態庫,該靜態庫就是一個包含目標文件的歸檔文件,連接器可使用這些目標文件將代碼添加到二進制文件中。如今,咱們知道這個函數是在aux_klib.lib中定義的。

  咱們能夠用 「dumpbin.exe」 工具來反彙編lib 文件,咱們還能夠編譯一個使用AuxKlibQueryModuleInformation的驅動程序,而後查看編譯後的二進制文件,看看結果如何。使用dumpbin.exe快速檢查後,能夠看到函數調用以下:=

  AuxKlibQueryModuleInformation:

  .....

  .....

  lea r9,[rsp+20h] ; ReturnLength

  mov r8d,esi ; SystemInformationLength

  mov rdx,rbx ; SystemInformation

  mov ecx,0Bh ; SystemInformationClass

  call qword ptr [__imp_ZwQuerySystemInformation] ; <-------

  .....

  .....

  能夠看到,AuxKlibQueryModuleInformation使用ZwQuerySystemInformation來查詢模塊列表,該函數的定義爲:

  NTSTATUS WINAPI ZwQuerySystemInformation(

  _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,

  _Inout_ PVOID SystemInformation,

  _In_ ULONG SystemInformationLength,

  _Out_opt_ PULONG ReturnLength

  );

  SystemInformationClass是咱們想要查詢的信息類型,正如你在反彙編中看到的,這個類等於0xb,可是0xb是什麼呢?

  一般,我會搜索SYSTEM_INFORMATION_CLASS枚舉定義,但咱們將查看ZwQuerySystemInformation的實際實現以找出SystemInformationClass,以瞭解如何能夠作到。

  此函數是在在ntoskrnl.exe中實現的,以下所示:

  

  這個函數是Zw函數,你能夠點擊這裏讀取更多關於Zw函數的信息。

  Zw函數調用Nt函數,並將PreviousMode更改成KernelMode。所以,jmp KiServiceInternal在後臺調用NtQuerySystemInformation。ntdll中存在相同的名稱,但ntoskrnl.exe包含系統調用的實際實現。若是你查看ntdll,會看到相同的ID是在執行「syscall」。

  

  這是由於內核Zw函數和用戶模式Nt函數都通過SSDT來提取系統調用處理程序指針,在本文的示例中,將在內核模式中執行相同的函數(NtQuerySystemInformation)。

  如今,讓咱們重複一下當前的任務:咱們須要找到SystemInformationClass 0xb指向的位置。檢查NtQuerySystemInformation後,咱們看到了經過ExpQuerySystemInformation或返回錯誤狀態的全部方法。SystemInformationClass在rcx中傳遞,請注意,我沒有開始從上到下閱讀反彙編,我只想知道當SystemInformationClass = 0xb時會發生什麼。

  

  跟蹤rcx,咱們看到在調用ExpQuerySystemInformation以前它沒有改變。這意味着ExpQuerySystemInformation的第一個參數是SystemInformationClass參數。

  查看ExpQuerySystemInformation能夠開始跟蹤rcx中的值,在IDA中,咱們能夠突出顯示rcx寄存器並查看其使用位置。

  

  你能夠看到rcx值被移動到rdi,而後它被覆蓋,如今咱們須要查看rdi,這是rdi寄存器的下一個用法:

  

  咱們知道0xb小於0x49,因此讓咱們觀察一下loc_14069F19C:

  

  這是switch語句的示例。該表包含switch語句中不一樣狀況的處理程序。IDA已經爲你找到了案例!要輕鬆找到案例,你可使用「Search Text」 (Alt-T)並搜索如下文本:「case 11」。因此,在搜索這篇文章後,咱們發現瞭如下內容:

  

  好的!因此咱們找到了查詢模塊列表的實際代碼。從它的名稱中,咱們能夠理解PsLoadedModuleList列表包含一個已加載模塊的列表。

  ExpQueryModuleInformation函數以下所示:

  

  咱們在這個函數中看到一個大循環,看看函數的開頭,咱們看到:

  

  如今,咱們假設這個函數枚舉這個列表並返回這個列表中的映像,咱們將在須要的時候驗證這個假設。最後,咱們完成了第一個任務,查找什麼是SystemInformationClass 0xb?

  第一個須要回答的問題是,這個API (AuxKlibQueryModuleInformation)是否保證返回的模塊列表老是最新的?

  要回答這個問題,咱們須要瞭解返回的值是否老是最新的。「最新的」的通常定義能夠有不一樣的含義。可是通常的答案是:不能保證在調用AuxKlibQueryModuleInformation以後,列表是最新的。看起來PsLoadedModuleList受ERESOURCE同步對象(讀寫鎖)PsLoadedModuleResource保護。在調用ExpQueryModuleInformation以前,咱們會獲取鎖。但在那以後,咱們調用ExReleaseResourceLite,列表能夠再次更新,咱們能夠假定僅在得到鎖時才更改PsLoadedModuleList。

  若是AuxKlibQueryModuleInformation被設計爲獲取PsLoadedModuleList的更新版本,那麼它將容許調用者本身獲取或釋放鎖。事實上,PsLoadedModuleResource是在windows 10的ntoskrnl中導出的:

  

  由於能夠從同一線程兩次獲取ERESOURCE鎖,因此這意味着調用方實際上能夠:

  1.獲取鎖;

  2.調用AuxKlibQueryModuleInformation;

  3.用列表作一些有趣的事情(列表也已導出;);

  4.運行完成後,釋放鎖;

  這將確保在保持鎖定狀態時沒法更新列表,固然,前提是假設PsLoadedModuleList在沒有鎖定的狀況下不會更新。不過這種方法還不夠好,由於實際使用會出現如下問題:

  1.即便咱們檢驗了咱們的假設並假設它是正確的,微軟也能夠隨時更改此行爲,例如,微軟2.有時會更改鎖的類型(將ERESOURCE更改成其餘類型的鎖);

  3.在Windows 7/8中不可用,列表和鎖沒有導出(這多是個問題,具體取決於你的運行狀況);

  出於好奇,讓咱們使用windows import searcher工具來查找究竟是哪些模塊導入這些變量:

  >python.exe windows_imports_searcher.py search -i index.json -f ntoskrnl.exe!PsLoadedModule*

  Reading file index.json

  c:\windows\system32\drivers\ntosext.sys Imports ntoskrnl.exe!PsLoadedModuleResource

  c:\windows\system32\drivers\ntosext.sys Imports ntoskrnl.exe!PsLoadedModuleList

  咱們看到導入這個列表的惟一驅動是ntosext.sys,咱們可能會錯過使用MmGetSystemRoutineAddress導入已加載模塊列表的其餘模塊。此外,有些組件(例如調試器)能夠很好地利用此列表。這個列表在windows 10中導出多是由於ntosext.sys被移出ntoskrnl.exe。

  如今回答第2個問題:對AuxKlibQueryModuleInformation進行逆向工程,並解釋其工做原理。

  咱們必須當心處理這個任務。「解釋它是如何工做的」很容易被誤解爲「理解關於AuxKlibQueryModuleInformation實現的每一個小細節」。有時候,在逆向工程中,咱們想要獲得某些東西的概況,這個「東西」能夠是一個完整的程序,也能夠是一個程序的特定特性。咱們必須當心,不能花太多時間來顛倒AuxKlibQueryModuleInformation,由於這裏所須要作的就是了解全局。

  好了,咱們已經從上一個任務的分析中獲得了一些映像:

  1.AuxKlibQueryModuleInformation在aux_klib.lib靜態庫中定義;

  2.它調用ZwQuerySystemInformation來觸發ExpQuerySystemInformation;

  3.ExpQuerySystemInformation獲取PsLoadedModuleResource並調用ExpQueryModuleInformation

  4.咱們能夠估計ExpQueryModuleInformation會獲取列表的快照,並將其保存到輸出緩衝區。

  5.鎖被釋放,緩衝區被返回給用戶;

  好的,實際上咱們能夠在此時中止分析了,由於咱們已經有一個大的框架。可是咱們尚未檢查ExpQueryModuleInformation,因此讓咱們驗證一下它的做用。

  如上所述,這個函數有一個大的循環。咱們能夠估計此循環枚舉PsLoadedModuleList中的條目,讓咱們驗證一下。

  咱們能夠在循環以前看到如下代碼,看起來r14是循環變量,而且已與列表的開頭進行了比較,若是它指向列表的開頭,則循環結束。驗證r14爲循環變量的過程以下:

  

  是的,看來估算是正確的。爲了大體瞭解此循環的做用,讓咱們看一下循環對象內r14的用法:

  

  看起來來自ListItem結構(表明已加載模塊)的值已複製到rsi指向的某些輸出結構,經過查看rsi的來源,來驗證rsi是否包含調用者的輸出緩衝區:

  

  好的,答案是rsi = (SecondParam + 8),接下來,讓咱們來看看第二個參數(rdx)是怎麼來的:

  (在ExpQuerySystemInformation內部)

  

  咱們來跟蹤rbx,可使用Alt-Up來查看rbx的第一次分配發生在什麼位置:

  

  rbx包含了ExpQuerySystemInformation的第四個參數,讓咱們追蹤一下調用者,看看它來自哪裏:

  (在NtQuerySystemInformation內部)

  

  它是NtQuerySystemInformation的第二個參數,讓咱們看看這個函數的原型:

  

  好極了!咱們是正確的,由於第二個參數是SystemInformation,是調用者的輸出參數。

  __kernel_entry NTSTATUS NtQuerySystemInformation(

  IN SYSTEM_INFORMATION_CLASS SystemInformationClass,

  OUT PVOID SystemInformation,

  IN ULONG SystemInformationLength,

  OUT PULONG ReturnLength

  );

  好,讓咱們來看最後一個問題

  當多個線程請求訪問加載的模塊列表時,它如何處理這種狀況?

  咱們已經知道答案了!這是使用讀寫鎖來處理的,這種類型的鎖容許讀取器一塊兒讀取列表(這是安全的,由於它們不會更改列表),可是若是編寫器但願編輯列表,則只有編寫器能夠訪問列表。奇怪的是,查詢函數使用exacquireresourceexclusive velite函數鎖定列表,不容許其餘人讀取列表。這很奇怪,由於這個函數應該讀取而不是寫入列表。通過驗證,我沒有在ExpQueryModuleInformation內找到對列表的任何寫操做,所以它看起來像是錯誤的編碼,又或許是我沒有理解到位。

  最後,咱們想知道函數是否返回用戶模式dll。咱們能夠嘗試找出靜態地插入到PsLoadedModuleList中的內容,可是讓咱們使用動態分析來解決這個問題。咱們如何解決這個問題?咱們能夠編寫調用AuxKlibQueryModuleInformation並查看返回值的代碼,可是有一種更簡單的方法,就是用循環對象自己。

  

  咱們能夠假設這是在將映像放入目標緩衝區以前對映像名稱的轉換,讓咱們在調用RtlUnicodeStringToAnsiString時設置一個斷點,而後查看源字符串。爲了使這個運行有效,咱們必須以某種方式觸發ZwQuerySystemInformation,打開process explorer並經過單擊View->System Information就能夠觸發它。

  kd> bp fffff80207203c57 "dS /c 100 rdx; g"

  kd> g

  ffffa78e`7e605f40 "\SystemRoot\system32\ntoskrnl.exe"

  ffffa78e`7e606e90 "\SystemRoot\system32\hal.dll"

  ffffa78e`7e606ef0 "\SystemRoot\system32\kdcom.dll"

  ffffa78e`7e605f40 "\SystemRoot\system32\ntoskrnl.exe"

  ffffa78e`7e606e90 "\SystemRoot\system32\hal.dll"

  ffffa78e`7e606ef0 "\SystemRoot\system32\kdcom.dll"

  ffffa78e`7e606f50 "\SystemRoot\system32\mcupdate_GenuineIntel.dll"

  ffffa78e`7e607d60 "\SystemRoot\System32\drivers\msrpc.sys"

  ffffa78e`7e607dd0 "\SystemRoot\System32\drivers\ksecdd.sys"

  ffffa78e`7e607e40 "\SystemRoot\System32\drivers\werkernel.sys"

  ffffa78e`7e607ec0 "\SystemRoot\System32\drivers\CLFS.SYS"

  ffffa78e`7e607f30 "\SystemRoot\System32\drivers\tm.sys"

  ffffa78e`7e608010 "\SystemRoot\system32\PSHED.dll"

  ffffa78e`7e608070 "\SystemRoot\system32\BOOTVID.dll"

  ffffa78e`7e6080e0 "\SystemRoot\System32\drivers\FLTMGR.SYS"

  ffffa78e`7e608150 "\SystemRoot\System32\drivers\clipsp.sys"

  ffffa78e`7e6081c0 "\SystemRoot\System32\drivers\cmimcext.sys"

  ffffa78e`7e608240 "\SystemRoot\System32\drivers\ntosext.sys"

  ..................

  ...(truncated)....

  ..................

  從輸出中能夠看到,只有內核映像保存在輸出列表中。

  正如你所看到的,逆向工程的大部分工做是跟蹤咱們程序中的數據流。這是反編譯器能夠作得更好的優點所在,由於它們以更高的表示形式顯示信息。全部變量在寄存器之間的「臨時」移動都不在反編譯視圖中體現。

  本文參考自:https://repnz.github.io/posts/practical-reverse-engineering/query-module-information/

相關文章
相關標籤/搜索