標籤:

一篇文章教你如何檢測Win API Hooks(Ring3)

惡意軟體是如何從網路瀏覽器中獲取憑證的呢?目前,最熱門的方法是MiTB(Man-in-The-Browser 瀏覽器中間者)攻擊,它被稱為inline hooking為人們所熟知(有時也稱為detours)。inline hooks是非常通用的,而且在惡意軟體中非常常見。通過使用inline hooks,惡意軟體可以成為任何進程的puppetmaster,並且惡意軟體作者可以操縱它來實現任何他們想實現的東西。下面讓我們來看看是怎麼實現的。

如何將代碼插入目標程序中?

inline hooking的第一步是讓代碼在目標進程中運行。這個過程被稱為注入。

一般情況下有幾種常見的注入方法。例如,我們使用VirtualAllocEx,在0x0D000000的Firefox中創建一個內存區域。然後,CreateRemoteThread將被用於開始執行0x0D000000區域的Firefox,以便設置hooks,並處理初始化。(實際的注入過程本身就是一個很複雜的主題,超出了本文的範圍。)下面是我們注入的代碼塊。隨著繼續注入,高亮顯示的區域將變得更加清晰。

inline hook有四個部分:the hook、惡意代碼(這裡的惡意代碼全由NOPs組成)、被損壞位元組的執行和回復。

什麼是Windows API?

Windows API是一組函數和數據結構,Windows程序可以使用它來請求Windows執行一些命令,比如打開文件、顯示消息,等等。Windows程序所執行的所有命令幾乎都涉及到調用各種API函數。總的來說,Windows提供的所有API功能都稱為「Windows API」。

The hook

hook,有時被稱為trampoline,類似於一個交通主管把交通改道到另一個位置。示例如下,我們將從ws2_32庫中hook send()函數。下圖是ws2_32!中最初的幾條指令,像正常情況下一樣發送函數。為了放置hook,我們需要覆蓋函數中的一些現有指令。圖中的綠色框突出顯示了我們將要覆蓋的位元組。

由於hook佔用5個位元組,因此將有5個位元組被覆蓋,jmp指令跳轉到0x0D000000的代碼中。(還有其他放置hook的方法,如使用push addr與ret指令組合)。下面是放置了hook之後的同一個send()函數:

惡意代碼

既然,執行流程被重定向到我們的注入代碼中,必須保存寄存器,以確保當我們返回執行send()函數時不會崩潰。在32位進程中,我們可以使用pusha指令保存所有寄存器。當惡意代碼完成執行時,popad指令將把所有寄存器恢復到send()函數被最初執行調用時所處的狀態。既然我們已經控制了send()函數,可以實現很多有趣的指令。其中一件就是我們可以查看是否發送了POST請求,並將該數據發送回我們的命令和控制,希望它包含登錄憑證。

被損壞位元組的執行和回復

在對惡意代碼做了一些修改之後,我們必須確保我們的進程能夠跳轉回與之hook的原函數。

首先,我們使用popad指令來恢復所有的寄存器。在設置hook時損壞了5個位元組,由於這些原始指令仍然需要運行,所以在hook的進程中這5個位元組被複制到惡意代碼的末尾,以便在寄存器恢復後無縫地運行。最後,我們安全地跳回到send函數+0x05(hook的長度)。

總結

回顧上述所有的操作方法,然後把所有步驟按順序整合到一張圖片里。按照箭頭的指示,可以看到,Firefox中一個正常的、沒有被hook的send()函數的執行流程:

注入detour之後,執行流程如下:

需要hook API調用的情況

大家能隨便想到一種情況需要hook所有可以想像到的API調用。下面列出了幾個:

l. urlmon !URLDownloadToFile——用於攔截下載的文件。Shifu在每一個進程中都hook這個函數,以防止新出的惡意軟體下載文件。2. ws2_32!send——用於從未加密的流量中捕獲POST憑證。3. GetHostByName——Shifu hook這個函數是為了忽略它的命令和控制站點的流量。4. ws2_32!recv——用於從未加密的流量中捕獲傳入的數據包數據。5. Advapi32!CryptEncrypt——在它被加密之前用於捕獲數據,因為它在輸出send()函數時不是純文本6. Advapi32!CryptDecrypt——用於解密來自recv()函數的加密數據。7. User32!GetMessage——Shifu在這裡使用hook來攔截滑鼠點擊信息,以獲得虛擬鍵盤點擊的圖片。8. Kernel32!ExitProcess——有助於防止進程關閉(繞過遊戲反作弊程序)

檢測

下面是一個偽代碼簡單的解決方案,但如果攻擊者是一個硬茬,則不太有效。下面的代碼將檢查api ExitProcess的序言是否從0xE9開始(opcode JMP)

FARPROC Address = GetProcAddress(GetModuleHandle("kernel32.dll"),"ExitProcess");if (*(BYTE*)Address == 0xE9){ printf("Api hookedn");//Do your thing}

本文翻譯自: userpc.net/2017/12/03/u ,如若轉載,請註明原文地址: 4hou.com/system/9112.ht 更多內容請關注「嘶吼專業版」——Pro4hou

推薦閱讀:

別再說願天堂不再有騙子了,騙子可不會上天堂
Android啟動過程的分析
Cookie與Session機制
有意還是無意?一加手機正在收集用戶敏感數據

TAG:信息安全 |