Qt:Windows编程—DLL注入与卸载
前言
這里說的DLL注入 是將我們指定的DLL注入到指定的進程中,DLL卸載也就是將指定進程中的DLL卸載下來。在Windows提供的API中有 CreateRemoteThread函數 見名知意 創建遠程線程函數,這的遠程指定的垮進程,讓遠程進程執行我們指定的線程回調函數。這就提供操作其他進程的契機。
CreateRemoteThread 函數原型
實現思路
注入DLL
我們現在思考下面3個問題
第一個問題:如何加載DLL文件?DLL的調用方式,可以以參考 C/C++:Windows編程—調用DLL程序的2種方法。將一個DLL文件注入到目標進程 使用的是LoadLibrary函數。該函數的形式和ThreadProc形式一樣,即可將LoadLibrary函數地址作為線程回調函數,這樣目標進程會執行該函數將我們指定的DLL文件加載到目的進程中。
第二個問題:DLL的路徑參數呢?需要將DLL文件的路徑,同樣寫到目標進程中。這里需要借助WriteProcessMemory函數,
BOOL WINAPI WriteProcessMemory(// 進程句柄_In_ HANDLE hProcess,// 指定寫入目標進程內存的起始地址_In_ LPVOID lpBaseAddress,// 寫入的內容的緩沖區起始地址_In_ LPCVOID lpBuffer,// lpBuffer長度_In_ SIZE_T nSize,// 接受實際寫入內容的長度 _Out_ SIZE_T *lpNumberOfBytesWritten );該函數非常強大,比如在破解方面,可以實現一個內存補丁,在開發方面,該函數可以用于修改目標進程中指定的值。
這樣目標進程用LoadLibrary函數加載指定的DLL文件了。回到第二個問題 寫入目標進程的起始地址應該是多少?目標進程中的內存塊允許將DLL文件的路徑寫進去嗎?這就引出了第3個問題
第三個問題:如何確定應該將DLL文件的完整路徑寫入目標進程的哪塊地址呢?對于目標進程來說,不會事先準備一塊地址讓用戶進行寫入,用戶做的是自己在目標進程中申請一塊內存,然后把DLL文件的路徑進程寫入。在目標進程中申請內存的函數是VirtualAllocEx().
// suc,返回值是在目標進程申請到的內存起始地址 // err,NULL LPVOID WINAPI VirtualAllocEx(// 指定進程句柄_In_ HANDLE hProcess,// 在目標進程中申請內存的起始地址_In_opt_ LPVOID lpAddress,// 申請內存的長度_In_ SIZE_T dwSize,// 申請內存的狀態類型,如MEM_COMMIT _In_ DWORD flAllocationType,// 申請內存的屬性,如PAGE_READWRITE _In_ DWORD flProtect ); // 獲取指定模塊的模塊句柄 HMODULE WINAPI GetModuleHandle(_In_opt_ LPCTSTR lpModuleName );那么注入DLL的思路,就是是上面3個問題的思路。
卸載DLL
卸載DLL庫的API函數
https://docs.microsoft.com/zh-cn/windows/desktop/api/libloaderapi/nf-libloaderapi-freelibrary
思路還是和注入的一樣,因為我們在目標進程使用LoadLibraryA將線程注入了,那么卸載DLL同樣要在目標進程中執行!步驟同注入一樣。由于FreeLibrary參數為HMODULE 實際上就是一個指針值。這個句柄已經加載就已經存在。所以并不需要項目標進程申請空間和寫入數據。為什么LoadLibraryA需要在內存中申請參數空間呢?因為字符串 有空間,事先并沒有,必須自己開辟空間,然后將字符串指針值傳入。
實現效果
事先準備了一個DLLMsgBox.dll,在DLL加載和卸載的時候 會有個彈框效果。這里我們注入到KuGou.exe進程中。
我們用上次寫的進程管理器 查看KuGou.exe進程中的DLL
滑到最下面
已經被注入到進程中了。
我們進行卸載DLL
卸載完畢,再次查看DLL列表
已經被成功卸載了。
核心代碼
相關基礎知識已經有了,下面我們來看核心代碼
注入DLL
// 注入DLL void WorkerThread::injectDLL() {/*注入DLL的思路步驟:1. 在目標進程中申請一塊內存空間(使用VirtualAllocEx函數) 存放DLL的路徑,方便后續執行LoadLibraryA2. 將DLL路線寫入到目標進程(使用WriteProcessMemory函數)3. 獲取LoadLibraryA函數地址(使用GetProcAddress),將其做為線程的回調函數4. 在目標進程 創建線程并執行(使用CreateRemoteThread)*/HANDLE targetProc = OpenProcess(PROCESS_ALL_ACCESS,FALSE,m_pId);if( targetProc == NULL ){qDebug() << "OpenProcess error";return;}QString dllPath = m_dllPath;const char* pChar = dllPath.toStdString().c_str();int dllLen = dllPath.length();// 1.目標進程申請空間LPVOID pDLLPath = VirtualAllocEx(targetProc,NULL,dllLen,MEM_COMMIT,PAGE_READWRITE );if( pDLLPath == NULL ){qDebug() << "VirtualAllocEx error";return;}SIZE_T wLen = 0;// 2.將DLL路徑寫進目標進程內存空間int ret = WriteProcessMemory(targetProc,pDLLPath,pChar,dllLen,&wLen);if( ret == 0 ){qDebug() << "WriteProcessMemory error";return;}// 3.獲取LoadLibraryA函數地址FARPROC myLoadLibrary = GetProcAddress(GetModuleHandleA("kernel32.dll"),"LoadLibraryA");if( myLoadLibrary == NULL ){qDebug() << "GetProcAddress error";return;}// 4.在目標進程執行LoadLibrary 注入指定的線程HANDLE tHandle = CreateRemoteThread(targetProc,NULL,NULL,(LPTHREAD_START_ROUTINE)myLoadLibrary,pDLLPath,NULL,NULL);if(tHandle == NULL){qDebug() << "CreateRemoteThread error";return ;}qDebug() << "注入,wait ..." ;WaitForSingleObject(tHandle,INFINITY);CloseHandle(tHandle);CloseHandle(targetProc);qDebug() << "注入,finish ...";emit doInjectFinish(); }卸載DLL
// 卸載DLL void WorkerThread::uninstallDLL() {/*卸載步驟和注入DLL步驟實質差不多.注入DLL是 在目標進程中執行LoadLibraryA卸載DLL是 在目標進程中執行FreeLibrary函數,不同的是卸載不需要再目標進程中申請空間,因為FreeLibrary參數為HMODULE 實際上就是一個指針值。這個句柄已經加載就已經存在。*/HANDLE targetProc = OpenProcess(PROCESS_ALL_ACCESS,FALSE,m_pId);if( targetProc == NULL ){qDebug() << "OpenProcess error";return;}QString dllPath = m_dllPath;// 1. 獲取卸載dll的模塊句柄HANDLE snapHandele = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE ,m_pId);if( INVALID_HANDLE_VALUE == snapHandele){qDebug() << "CreateToolhelp32Snapshot error" ;return;}MODULEENTRY32 entry = {0};entry.dwSize = sizeof(entry);// 長度必須賦值BOOL ret = Module32First(snapHandele,&entry);HMODULE dllHandle = NULL;while (ret) {QString dllName = QString::fromWCharArray(entry.szModule);if(dllPath.endsWith(dllName)){dllHandle = entry.hModule;qDebug() << dllName;break;}ret = Module32Next(snapHandele,&entry);}CloseHandle(snapHandele);if( dllHandle == NULL ){qDebug() << "dll 并未被加載";return;}// 2.獲取FreeLibrary函數地址FARPROC myLoadLibrary = GetProcAddress(GetModuleHandleA("kernel32.dll"),"FreeLibrary");if( myLoadLibrary == NULL ){qDebug() << "GetProcAddress error";return;}// 3.在目標進程執行FreeLibrary 卸載指定的線程HANDLE tHandle = CreateRemoteThread(targetProc,NULL,NULL,(LPTHREAD_START_ROUTINE)myLoadLibrary,dllHandle,NULL,NULL);if(tHandle == NULL){qDebug() << "CreateRemoteThread error";return ;}qDebug() << "卸載,wait ..." ;WaitForSingleObject(tHandle,INFINITY);CloseHandle(tHandle);CloseHandle(targetProc);qDebug() << "卸載,finish ...";emit doUninstallFinish(); }完整工程
整個qt工程請在這里下載(含DLLMsgBox.dll)。
總結
以上是生活随笔為你收集整理的Qt:Windows编程—DLL注入与卸载的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 二、内存空间
- 下一篇: Redis 与 hash (哈希)相关的