日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

Qt:Windows编程—DLL注入与卸载

發(fā)布時(shí)間:2025/3/15 windows 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Qt:Windows编程—DLL注入与卸载 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

這里說的DLL注入 是將我們指定的DLL注入到指定的進(jìn)程中,DLL卸載也就是將指定進(jìn)程中的DLL卸載下來。在Windows提供的API中有 CreateRemoteThread函數(shù) 見名知意 創(chuàng)建遠(yuǎn)程線程函數(shù),這的遠(yuǎn)程指定的垮進(jìn)程,讓遠(yuǎn)程進(jìn)程執(zhí)行我們指定的線程回調(diào)函數(shù)。這就提供操作其他進(jìn)程的契機(jī)。
CreateRemoteThread 函數(shù)原型

// 函數(shù)是不是和CreateThread非常像,實(shí)際上內(nèi)部調(diào)用的該函數(shù) HANDLE WINAPI CreateRemoteThread(// 指定創(chuàng)建線程的進(jìn)程句柄_In_ HANDLE hProcess,_In_ LPSECURITY_ATTRIBUTES lpThreadAttributes,_In_ SIZE_T dwStackSize,// 線程回調(diào)函數(shù)地址_In_ LPTHREAD_START_ROUTINE lpStartAddress,// 線程回調(diào)函數(shù)的參數(shù)_In_ LPVOID lpParameter,_In_ DWORD dwCreationFlags,_Out_ LPDWORD lpThreadId );

實(shí)現(xiàn)思路

注入DLL

我們現(xiàn)在思考下面3個(gè)問題
第一個(gè)問題:如何加載DLL文件?DLL的調(diào)用方式,可以以參考 C/C++:Windows編程—調(diào)用DLL程序的2種方法。將一個(gè)DLL文件注入到目標(biāo)進(jìn)程 使用的是LoadLibrary函數(shù)。該函數(shù)的形式和ThreadProc形式一樣,即可將LoadLibrary函數(shù)地址作為線程回調(diào)函數(shù),這樣目標(biāo)進(jìn)程會(huì)執(zhí)行該函數(shù)將我們指定的DLL文件加載到目的進(jìn)程中。

//加載一個(gè)DLL文件到進(jìn)程的地址空間 HMODULE LoadLibraryA(LPCSTR lpLibFileName //dll文件的路徑 );

第二個(gè)問題:DLL的路徑參數(shù)呢?需要將DLL文件的路徑,同樣寫到目標(biāo)進(jìn)程中。這里需要借助WriteProcessMemory函數(shù),

BOOL WINAPI WriteProcessMemory(// 進(jìn)程句柄_In_ HANDLE hProcess,// 指定寫入目標(biāo)進(jìn)程內(nèi)存的起始地址_In_ LPVOID lpBaseAddress,// 寫入的內(nèi)容的緩沖區(qū)起始地址_In_ LPCVOID lpBuffer,// lpBuffer長度_In_ SIZE_T nSize,// 接受實(shí)際寫入內(nèi)容的長度 _Out_ SIZE_T *lpNumberOfBytesWritten );

該函數(shù)非常強(qiáng)大,比如在破解方面,可以實(shí)現(xiàn)一個(gè)內(nèi)存補(bǔ)丁,在開發(fā)方面,該函數(shù)可以用于修改目標(biāo)進(jìn)程中指定的值。

這樣目標(biāo)進(jìn)程用LoadLibrary函數(shù)加載指定的DLL文件了。回到第二個(gè)問題 寫入目標(biāo)進(jìn)程的起始地址應(yīng)該是多少?目標(biāo)進(jìn)程中的內(nèi)存塊允許將DLL文件的路徑寫進(jìn)去嗎?這就引出了第3個(gè)問題

第三個(gè)問題:如何確定應(yīng)該將DLL文件的完整路徑寫入目標(biāo)進(jìn)程的哪塊地址呢?對(duì)于目標(biāo)進(jìn)程來說,不會(huì)事先準(zhǔn)備一塊地址讓用戶進(jìn)行寫入,用戶做的是自己在目標(biāo)進(jìn)程中申請(qǐng)一塊內(nèi)存,然后把DLL文件的路徑進(jìn)程寫入。在目標(biāo)進(jìn)程中申請(qǐng)內(nèi)存的函數(shù)是VirtualAllocEx().

// suc,返回值是在目標(biāo)進(jìn)程申請(qǐng)到的內(nèi)存起始地址 // err,NULL LPVOID WINAPI VirtualAllocEx(// 指定進(jìn)程句柄_In_ HANDLE hProcess,// 在目標(biāo)進(jìn)程中申請(qǐng)內(nèi)存的起始地址_In_opt_ LPVOID lpAddress,// 申請(qǐng)內(nèi)存的長度_In_ SIZE_T dwSize,// 申請(qǐng)內(nèi)存的狀態(tài)類型,如MEM_COMMIT _In_ DWORD flAllocationType,// 申請(qǐng)內(nèi)存的屬性,如PAGE_READWRITE _In_ DWORD flProtect ); // 獲取指定模塊的模塊句柄 HMODULE WINAPI GetModuleHandle(_In_opt_ LPCTSTR lpModuleName );

那么注入DLL的思路,就是是上面3個(gè)問題的思路。

  • 先在目標(biāo)進(jìn)程 申請(qǐng) 注入DLL的路徑長度的 內(nèi)存空間(也是LoadLibrary參數(shù)的),使用VirtualAllocEx
  • 將DLL路徑 寫入的目標(biāo)進(jìn)程,使用WriteProcessMemory
  • 獲取LoadLibraryA函數(shù)的地址,通過GetProcAddress,LoadLibraryA函數(shù)在kernel32.dll中使用GetModuleHandle
  • 創(chuàng)建線程并執(zhí)行,使用CreateRemoteThread在目標(biāo)進(jìn)程中執(zhí)行LoadLibrary。至就完成了將DLL注入到指定的進(jìn)程中了。
  • 卸載DLL

    卸載DLL庫的API函數(shù)
    https://docs.microsoft.com/zh-cn/windows/desktop/api/libloaderapi/nf-libloaderapi-freelibrary

    BOOL FreeLibrary(HMODULE hLibModule );

    思路還是和注入的一樣,因?yàn)槲覀冊(cè)谀繕?biāo)進(jìn)程使用LoadLibraryA將線程注入了,那么卸載DLL同樣要在目標(biāo)進(jìn)程中執(zhí)行!步驟同注入一樣。由于FreeLibrary參數(shù)為HMODULE 實(shí)際上就是一個(gè)指針值。這個(gè)句柄已經(jīng)加載就已經(jīng)存在。所以并不需要項(xiàng)目標(biāo)進(jìn)程申請(qǐng)空間和寫入數(shù)據(jù)。為什么LoadLibraryA需要在內(nèi)存中申請(qǐng)參數(shù)空間呢因?yàn)樽址?有空間,事先并沒有,必須自己開辟空間,然后將字符串指針值傳入

    實(shí)現(xiàn)效果

    事先準(zhǔn)備了一個(gè)DLLMsgBox.dll,在DLL加載和卸載的時(shí)候 會(huì)有個(gè)彈框效果。這里我們注入到KuGou.exe進(jìn)程中。


    我們用上次寫的進(jìn)程管理器 查看KuGou.exe進(jìn)程中的DLL

    滑到最下面

    已經(jīng)被注入到進(jìn)程中了。
    我們進(jìn)行卸載DLL

    卸載完畢,再次查看DLL列表

    已經(jīng)被成功卸載了。

    核心代碼

    相關(guān)基礎(chǔ)知識(shí)已經(jīng)有了,下面我們來看核心代碼

    注入DLL

    // 注入DLL void WorkerThread::injectDLL() {/*注入DLL的思路步驟:1. 在目標(biāo)進(jìn)程中申請(qǐng)一塊內(nèi)存空間(使用VirtualAllocEx函數(shù)) 存放DLL的路徑,方便后續(xù)執(zhí)行LoadLibraryA2. 將DLL路線寫入到目標(biāo)進(jìn)程(使用WriteProcessMemory函數(shù))3. 獲取LoadLibraryA函數(shù)地址(使用GetProcAddress),將其做為線程的回調(diào)函數(shù)4. 在目標(biāo)進(jìn)程 創(chuàng)建線程并執(zhí)行(使用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.目標(biāo)進(jìn)程申請(qǐng)空間LPVOID pDLLPath = VirtualAllocEx(targetProc,NULL,dllLen,MEM_COMMIT,PAGE_READWRITE );if( pDLLPath == NULL ){qDebug() << "VirtualAllocEx error";return;}SIZE_T wLen = 0;// 2.將DLL路徑寫進(jìn)目標(biāo)進(jìn)程內(nèi)存空間int ret = WriteProcessMemory(targetProc,pDLLPath,pChar,dllLen,&wLen);if( ret == 0 ){qDebug() << "WriteProcessMemory error";return;}// 3.獲取LoadLibraryA函數(shù)地址FARPROC myLoadLibrary = GetProcAddress(GetModuleHandleA("kernel32.dll"),"LoadLibraryA");if( myLoadLibrary == NULL ){qDebug() << "GetProcAddress error";return;}// 4.在目標(biāo)進(jìn)程執(zhí)行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步驟實(shí)質(zhì)差不多.注入DLL是 在目標(biāo)進(jìn)程中執(zhí)行LoadLibraryA卸載DLL是 在目標(biāo)進(jìn)程中執(zhí)行FreeLibrary函數(shù),不同的是卸載不需要再目標(biāo)進(jìn)程中申請(qǐng)空間,因?yàn)镕reeLibrary參數(shù)為HMODULE 實(shí)際上就是一個(gè)指針值。這個(gè)句柄已經(jīng)加載就已經(jīng)存在。*/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函數(shù)地址FARPROC myLoadLibrary = GetProcAddress(GetModuleHandleA("kernel32.dll"),"FreeLibrary");if( myLoadLibrary == NULL ){qDebug() << "GetProcAddress error";return;}// 3.在目標(biāo)進(jìn)程執(zhí)行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(); }

    完整工程

    整個(gè)qt工程請(qǐng)?jiān)谶@里下載(含DLLMsgBox.dll)。

    總結(jié)

    以上是生活随笔為你收集整理的Qt:Windows编程—DLL注入与卸载的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。