学习笔记之卸载远程目标进程中的DLL模块(转)
生活随笔
收集整理的這篇文章主要介紹了
学习笔记之卸载远程目标进程中的DLL模块(转)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
學習筆記之卸載遠程目標進程中的DLL模塊
?(2007-07-23 23:51:02)轉載▼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)
轉載于:https://www.cnblogs.com/hungryvampire/p/4469918.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的学习笔记之卸载远程目标进程中的DLL模块(转)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android获取有线和无线(wifi)
- 下一篇: hdu 2648 Shopping