學習筆記之卸載遠程目標進程中的DLL模組(轉)

來源:互聯網
上載者:User

標籤:


學習筆記之卸載遠程目標進程中的DLL模組 (2007-07-23 23:51:02) 轉載
學習筆記之卸載遠程目標進程中的DLL模組2007/7/23
1.首先得把DLL模組中的線程結束
使用CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0);建立系統線程的快照然後用Thread32First()和
Thread32Next()遍曆系統中所有線程.將遍曆到的線程儲存到THREADENTRY32結構,然後判斷結構中的th32OwnerProcessID成員是否與目標進程ID是否相等從而判斷該線程是否為目標進程的.然後用函數OpenThread()開啟該線程.但是OpenThread函數在VC6中未被定義.該函數存在於kernel32.dll中.在使用時需要自己定義:第三個參數指定要開啟的線程的ID(從THREADENTRY32結構擷取)
typedef HANDLE (WINAPI*OPENTHREAD)(DWORD dwFlag, BOOL bInheritHandle, DWORD dwThreadId);
然後用GetProcAddress函數從kernel32.dll中擷取OpenThread函數的地址後就可以使用該函數了
OPENTHREAD OpenThread=(OPENTHREAD)GetProcAddress(GetModuleHandle("Kernel32"), "OpenThread");
用OpenThread函數開啟線程擷取線程控制代碼
HANDLE hThread=OpenThread(THREAD_ALL_ACCESS,FALSE,Thread.th32ThreadID);
有了線程的控制代碼後就可以調用NtQueryInformationThread函數擷取線程的入口地址
函數NtQueryInformationThread在VC6中也未被定義需要自己定義然後再使用
NtQueryInformationThread函數的第一個參數即為線程控制代碼,第二個參數為一個枚舉值而該枚舉類型在VC6中未被定義,同樣需要自己定義
NtQueryInformationThread函數的定義
typedef DWORD (CALLBACK* NTQUERYINFORMATIONTHREAD)(HANDLE,DWORD,PVOID,DWORD,PDWORD);
擷取NtQueryInformationThread函數的地址:NtQueryInformationThread函數存在於ntdll.dll中,ntdll.dll與kernel32.dll一樣,在每個進程開始時,系統都為他們做了一會拷貝所以可以直接用
GetProcAddress函數擷取其地址
NTQUERYINFORMATIONTHREAD NtQueryInformationThread=(NTQUERYINFORMATIONTHREAD)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtQueryInformationThread");
定義NtQueryInformationThread要用到的枚舉類型:
typedef enum _THREAD_INFORMATION_CLASS
{
    ThreadBasicInformation,
    ThreadTimes,
    ThreadPriority,
    ThreadBasePriority,
    ThreadAffinityMask,
    ThreadImpersonationToken,
    ThreadDescriptorTableEntry,
    ThreadEnableAlignmentFaultFixup,
    ThreadEventPair,
    ThreadQuerySetWin32StartAddress,
    ThreadZeroTlsCell,
    ThreadPerformanceCount,
    ThreadAmILastThread,
    ThreadIdealProcessor,
    ThreadPriorityBoost,
    ThreadSetTlsArrayAddress,
    ThreadIsIoPending,
    ThreadHideFromDebugger
}THREAD_INFORMATION_CLASS,*PTHREAD_INFORMATION_CLASS;
在此處NtQueryInformationThread函數將用到此枚舉類型的第9個值ThreadQuerySetWin32StartAddress
可以不定義此枚舉類型,直接將NtQueryInformationThread函數的第二個參數設為數值9也可以
關於NtQueryInformationThread函數的詳細資料瞭解不多
此處的用法為:
NtQueryInformationThread(hThread,ThreadQuerySetWin32StartAddress,&Start,0x4,NULL);
第一個參數為線程控制代碼,由OpenThread函數擷取,第二個參數為枚舉值不多說了
第三個參數為一個DWORD變數的指標,此變數就是用來接收線程入口地址的.第四個參數只能為0x4暫時還不知道是什麼意思.第五個參數也是一個DWORD變數指標,但在此處可以設為NULL

判斷該線程的入口地址是否在某DLL模組中的方法為:
用NtQueryInformationThread函數擷取的線程入口地址 - 該DLL模組控制代碼(需要先轉換為DWORD值)
再用得到的差值與該DLL模組檔案的大小相比較如果該差值正好小於或等於DLL模組檔案的大小
說明該線程入口地址在該DLL模組之中.
這裡所需要模組控制代碼,對於它的擷取稍後再講.

最後就可以調用TerminateThread(hThread,0);函數結束該線程

用上述方法結束該DLL模組中的所有線程後就可以對該DLL模組進行卸載操作了
2.要卸載DLL模組首先需要擷取該DLL模組的控制代碼
可以通過GetModuleHandle函數擷取
也可以通過建立快照CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,processID);的然後用
Module32First和Module32Next遍曆模組的方法擷取
先說說用GetModuleHandle函數擷取.此方法需要用CreateRemoteThread函數在遠程進程中建立線程,讓該線程調用Kernel32.dll中的GetModuleHandle函數.但是只這樣還不行.因為GetModuleHandle函數需要以DLL模組檔案名稱做參數.既然是遠程線程調用GetModuleHandle函數.還需要先把DLL模組檔案名稱寫入目標進程的地址空間中.最後用CreateRemoteThread函數建立線程執行GetModuleHandle函數來擷取DLL控制代碼
由於是用CreateRemoteThread函數遠程執行GetModuleHandle函數.所以無法直接從GetModuleHandle函數得到傳回值(也就是DLL控制代碼).在此必在WaitForSingleObject函數之後用GetExitCodeThread函數來擷取線程的結束代碼.如果線程正確返回.該結束代碼就是線程函數(GetModuleHandle)的傳回值然後再用同樣的方法用CreateRemoteThread遠程建立線程調用FreeLibrary函數來卸載該DLL
(注:此方法本人還沒實驗成功,理論上是可行的)
現在再來看第二種方法,通過CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,processID)建立進程模組的快照,然後用Module32First和Module32Next遍曆進程中所有模組.Module32First和Module32Next函數會將遍曆結果儲存到MODULEENTRY32結構中.通過查詢該結構中的szExePath或szModule成員來判斷是否為我們要卸載的目標模組.其中szExePath儲存了模組檔案的包括全路徑的檔案名稱而szModule只包括模組檔案名稱不含路徑
3.兩個關鍵的問題解決了,剩下的就是如何卸載DLL模組的問題
要卸載DLL模組需要用到FreeLibrary函數.由於是卸載遠程進程中的模組必須讓遠程進程來執行該函數.
所以將再次用到CreateRemoteThread函數來建立遠程線程
以下是實現方法:
首先從Kernel32.dll模組中擷取FreeLibrary函數的地址
LPVOID pFunc=(LPTHREAD_START_ROUTINE)GetProcAddress(Pkernel32,"FreeLibrary");//其中Pkernel32是Kernel32.dll的控制代碼
最後再調用
HANDLE hThread = CreateRemoteThread( process, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc,                (LPVOID)Module->hModule, 0, &dwID/*用來接收新線程的ID*/ );
其中第五個參數就是我們上一步驟中擷取的模組控制代碼
說明一下.由於一個進程可以多次調用LoadLibrary函數來裝載一個DLL模組(調用一次LoadLibrary函數系統就會對該DLL模組增加一個引用計數並不是說該進程中會有多個相同的DLL模組)為了防止這種情況.最好用一個迴圈來進行卸載操作.同樣通過用GetExitCodeThread的方法擷取FreeLibrary函數的執行情況
直到返回結果為False為止.這樣才表示完成了對該模組的卸載

4.另外附上一點關於CreateToolhelp32Snapshot函數的資料
CreateToolhelp32Snapshot函數為指定的進程、進程使用的堆[HEAP]、模組[MODULE]、線程[THREAD])建立一個快照[snapshot]。

原型:
HANDLE WINAPI CreateToolhelp32Snapshot(DWORD dwFlags,DWORD th32ProcessID);

參數:
dwFlags
[輸入]指定快照中包含的系統內容,這個參數能夠使用下列數值(變數)中的一個。

     TH32CS_INHERIT - 聲明快照控制代碼是可繼承的。
     TH32CS_SNAPALL - 在快照中包含系統中所有的進程和線程。
     TH32CS_SNAPHEAPLIST - 在快照中包含在th32ProcessID中指定的進程的所有的堆。
     TH32CS_SNAPMODULE - 在快照中包含在th32ProcessID中指定的進程的所有的模組。
     TH32CS_SNAPPROCESS - 在快照中包含系統中所有的進程。
     TH32CS_SNAPTHREAD - 在快照中包含系統中所有的線程。

th32ProcessID
[輸入]指定將要快照的進程ID。如果該參數為0表示快照當前進程。該參數只有在設定了TH32CS_SNAPHEAPLIST或TH32CS_SNAPMOUDLE後才有效,在其他情況下該參數被忽略,所有的進程都會被快照。

傳回值:
調用成功,返回快照的控制代碼,調用失敗,返回INVAID_HANDLE_VALUE。

5.新問題
在該次學習中所發現的新問題.某些程式在開始時總是要載入很多相關的DLL模組
比如QQGame.exe啟動時就載入了多達109個模組.有些是常見的如Ntdll.dll kernel32.dll Gdi32.dll ole32.dll等等.也有一些QQGame.exe自己的DLL模組這些模組完成QQGAME.EXE的一些特殊功能.但是QQGAME.EXE啟動後並沒有馬上就調用某些模組中的東西.比如QQGAME.EXE中的一個HelpDll.dll模組.我們就可以例用這樣的模組來啟動我們的病毒.我們可將該DLL模組檔案拷貝到一隱形目錄下.然後自己從新寫一個新的DLL模組.該模組應具備的功能.1首先要能載入我們拷貝的真正的DLL模組.2載入或者啟動我們的病毒程式.3完成這兩樣工作後馬上進行自我卸載. 最後將寫好的DLL檔案放到先前HelpDll.dll的目錄下複蓋真正的DLL檔案.這樣我們的病毒就會隨QQGame.exe的啟動而啟動了
上面的例子本人測試成功.不知道其它的進程或模組會不會支援這樣的方式
來源: <http://blog.sina.com.cn/s/blog_56ea069101000b3k.html>  

來自為知筆記(Wiz)

學習筆記之卸載遠程目標進程中的DLL模組(轉)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.