遍歷進程句柄並幹掉互斥體

互斥體例子

int main(int argc, char* argv[])  
{  
    HANDLE hMtx = CreateMutex(NULL,false,"process"); //創建一個有名對象,可以在其他進程中訪問   
    if(GetLastError() == ERROR_ALREADY_EXISTS)    //除了創建該對象的進程能進到else分支,其他進程都進入if分支,然後退出  
    {  
        ExitProcess(0);  
    }  
    else  
            //do something    
    return 0;  
}  

幹掉互斥體

a.主要思路是查找目標進程,b.找到後枚舉進程所有打開的句柄,c.用ZwDuplicateObject複製句柄,能複製成功的基本是可用的句柄,d.先關閉上次調用ZwDuplicateObject時複製的句柄,然後已DUPLICATE_CLOSE_SOURCE的方式(複製後關閉原句柄)再次複製/關閉句柄。以此關閉限制多開的Mutex。

1.準備工作。代碼進行枚舉並打開進程,打開進程需要提權,使進程本身具有SE_PRIVILEGE_ENABLED權限。然後導出一堆Zw*函數用於枚舉系統和進程的UnDocument API。讀者可能知道進程EPROCESS結構中有進程句柄表,記錄了進程打開的句柄信息,但是有了SE_PRIVILEGE_ENABLED權限和UnDocument API就能獲得目標進程的句柄表了麼?貌似也不是~那這不就無解了?在R3下的確很直白的方法,但是,有個很重要的事:進程句柄從4開始計數,每次往上加4,這個可以通過ARK工具查看驗證。知道這個事就好辦了,大不了在循環中慢慢找過去唄~雖然挨個找過去是一個辦法,但是未必每個值爲4N的整數就是進程內有效句柄啊~因此,需要用另一個UnDocument API----ZwDuplicateObject加以驗證,如果調用這個函數成功就是一個可用的句柄,然後對這個句柄經行下一步處理。

2.摸排信息。光有進程句柄,同時知道這是一個有效的句柄作用不大。想想GUI進程一堆窗口,每個窗口一個句柄,不可能直接一棍打死吧?所以得摸清楚這個句柄的背景信息,通過調用ZwQueryObject可以獲得該句柄的類型名和句柄名。通過字符串比較(wcsstr)找到Mutext對應的句柄。

3.暗殺。以DUPLICATE_CLOSE_SOURCE方式調用DuplicateHandle,意思很直白了,複製的時候把源句柄關閉。誰是源句柄?當然是創建Mutext的進程中的Mutext句柄。讀者可以在調試時單步運行到DuplicateHandle,然後觀察xuetr中句柄佔用情況:調用前,創建這個Mutext的進程對這個句柄的引用數>0,調用成功後引用數=0,因此在創建進程中再也找不到這個句柄的信息了。最後在代碼中調用CloseHandle,關閉複製到本進程中的Mutext句柄。當系統發現這個句柄的引用數==0,於是會刪除對應的內核對象。當下次運行同一個進程並創建互斥體時,發現系統中並沒有這個互斥體,於是順利的通過if語句往下執行。

源碼在此
OK

發佈了35 篇原創文章 · 獲贊 2 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章