您好,登錄后才能下訂單哦!
這篇文章主要介紹“C++ DLL注入怎么實現”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“C++ DLL注入怎么實現”文章能幫助大家解決問題。
先上源碼:
#include "Inject_Main.h" #include "resource.h" #include <Windows.h> #include <TlHelp32.h> #include <string> #include <TCHAR.H> using namespace std; /// <summary> /// 通過進程名稱獲取該進程句柄 /// </summary> /// <param name="processName"></param> /// <returns>成功返回 DWORD,失敗返回 0</returns> DWORD GetProcessByName(CONST TCHAR* processName) { // 獲取到整個系統的進程 HANDLE processALL = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); // 定義一個容器,該容器用來接收,進程信息 PROCESSENTRY32W processInfo = { 0 }; processInfo.dwSize = sizeof(PROCESSENTRY32W); // 根據進程名稱,循環判斷是否是指定的進程 do { if (_tcscmp(processInfo.szExeFile, processName) == 0) { // 釋放進程快照,防止內存泄露 CloseHandle(processALL); // 如果是返回指定進程句柄 return processInfo.th42ProcessID; } // 一個迭代函數 } while (Process32Next(processALL, &processInfo)); // 釋放進程快照,防止內存泄露 CloseHandle(processALL); return 0; } /// <summary> /// 獲取指定 DLL 的內存地址 /// </summary> /// <param name="pid"></param> /// <param name="moduleName"></param> /// <returns></returns> HMODULE GetProcessModuleHandle(DWORD pid, CONST TCHAR* moduleName) { MODULEENTRY32 moduleEntry; HANDLE handle = NULL; handle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); if (!handle) { CloseHandle(handle); return NULL; } ZeroMemory(&moduleEntry, sizeof(MODULEENTRY32)); moduleEntry.dwSize = sizeof(MODULEENTRY32); if (!Module32First(handle, &moduleEntry)) { CloseHandle(handle); return NULL; } do { if (_tcscmp(moduleEntry.szModule, moduleName) == 0) { // 釋放進程快照,防止內存泄露 CloseHandle(handle); return moduleEntry.hModule; } } while (Module32Next(handle, &moduleEntry)); CloseHandle(handle); return 0; } /// <summary> /// 把指定DLL注入到指定進程中 /// </summary> /// <param name="processName">processName 進程名稱</param> /// <param name="dllPath">dllPath dll路徑</param> void InjectDll(const wchar_t* processName, const char* dllPath) { // 獲取指定進程的句柄 DWORD dword = GetProcessByName(processName); if (dword == 0) { MessageBox(NULL, TEXT("沒有找到指定進程"), TEXT("錯誤"), 0); return; } // 打開指定進程 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dword); if (hProcess == NULL) { MessageBox(NULL, TEXT("指定進程打開失敗"), TEXT("錯誤"), 0); return; } /* 在指定進程的地址,開辟一塊內存空間,用來保存 DLL的路徑信息 LPVOID VirtualAllocEx( [in] HANDLE hProcess, 在那個進程中開辟內存 [in, optional] LPVOID lpAddress, 開辟內存的起始地址 (NULL,不需要控制起始位置) [in] SIZE_T dwSize, 開辟內存的大小(當前保存的內容是 DLL的路徑) [in] DWORD flAllocationType, 內存分配的類型。(開辟內存) [in] DWORD flProtect,設置內存的權限 (可讀可寫) ); */ LPVOID DLLAddress = VirtualAllocEx(hProcess, NULL, strlen(dllPath), MEM_COMMIT, PAGE_READWRITE); /* 把DLL的路徑,寫入到剛開辟出來的內存中 BOOL WriteProcessMemory( [in] HANDLE hProcess, // 指定的進程 [in] LPVOID lpBaseAddress, // DLL路徑字符串,寫入的基址 [in] LPCVOID lpBuffer, // DLL路徑字符串,的指針 [in] SIZE_T nSize, // 需要寫入內存的字節長度 [out] SIZE_T *lpNumberOfBytesWritten // [out] 返回一個指針,不需要,NULL ); */ if (WriteProcessMemory(hProcess, DLLAddress, dllPath, strlen(dllPath), NULL) == 0) { MessageBox(NULL, TEXT("路徑寫入失敗"), TEXT("錯誤"), 0); return; } // 獲取 Kernel32.dll 這個模塊 HMODULE k32 = GetModuleHandle(TEXT("Kernel32.dll")); // 在 Kernel32.dll 模塊中找到 LoadLibrary 這個函數的內存地址 LPVOID loadADD = GetProcAddress(k32, "LoadLibraryA"); /* 在指定進程中,創建一個線程 并通過這個線程,調用 LoadLibrary 函數 通過 LoadLibrary 函數,把 DLL 載入到目標進程中 HANDLE CreateRemoteThread( [in] HANDLE hProcess, // 指定進程 [in] LPSECURITY_ATTRIBUTES lpThreadAttributes, // 設置線程安全屬性,表示線程是否可以繼承,NULL就夠了 [in] SIZE_T dwStackSize, // 堆棧的初始大小,0 表示使用可執行文件的默認大小 [in] LPTHREAD_START_ROUTINE lpStartAddress, // 遠程進程中,需要執行的那個函數的指針 [in] LPVOID lpParameter, // 目前進程中 DLL路徑的指針 [in] DWORD dwCreationFlags, // 0 線程在創建后立即運行。 [out] LPDWORD lpThreadId // [out] 當前不需要這個返回值 ); */ HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)loadADD, DLLAddress, 0, NULL); // 釋放指定的模塊 CloseHandle(hThread); CloseHandle(hProcess); } /// <summary> /// 把指定進程中的DLL卸載掉 /// </summary> /// <param name="processName"></param> /// <param name="dllPath"></param> void UnInjectDll(const wchar_t* processName) { // 通過進程名稱獲取該進程句柄 DWORD dword = GetProcessByName(processName); if (dword == 0) { MessageBox(NULL, TEXT("沒有找到指定進程"), TEXT("錯誤"), 0); return; } // 獲取指定進程中指定模塊的內存地址 HMODULE hmodule = GetProcessModuleHandle(dword, L"WX_Read_Write.dll"); // 打開指定進程 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dword); if (hProcess == NULL) { MessageBox(NULL, TEXT("指定進程打開失敗"), TEXT("錯誤"), 0); return; } // 獲取 Kernel32.dll 這個模塊 HMODULE k32 = GetModuleHandle(TEXT("Kernel32.dll")); // 在 Kernel32.dll 模塊中找到 LoadLibrary 這個函數的內存地址 LPVOID loadADD = GetProcAddress(k32, "FreeLibrary"); HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)loadADD, (LPVOID)hmodule, 0, NULL); // 釋放指定的模塊 CloseHandle(hThread); CloseHandle(hProcess); } /// <summary> /// /// </summary> /// <param name="hwndDlg"></param> /// <param name="uMsg"></param> /// <param name="wParam"></param> /// <param name="lParam"></param> /// <returns></returns> INT_PTR CALLBACK dialogProc(_In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam) { wchar_t processName[100] = L"WeChat.exe"; char dllPath[400] = { "C://Users//qiaoas//documents//visual studio 2015//Projects//ConsoleApplication1//Debug//WX_Read_Write.dll" }; switch (uMsg) { case WM_INITDIALOG: break; case WM_CLOSE: EndDialog(hwndDlg, 0); // 關閉窗體 break; case WM_COMMAND: /*GetDlgItemText(hwndDlg, Text_ProcessName, processName, sizeof(processName)); GetDlgItemText(hwndDlg, Text_DLLPath, (LPWSTR)dllPath, sizeof(dllPath));*/ if (wParam == Btn_Inject_DLL) { if (sizeof(processName) == 0) { MessageBox(NULL, TEXT("進程名稱不能為空"), TEXT("錯誤"), 0); } if (sizeof(dllPath) == 0) { MessageBox(NULL, TEXT("DLL路徑不能為空"), TEXT("錯誤"), 0); } InjectDll(processName, dllPath); // 注入DLL } if (wParam == Btn_unInject_DLL) { UnInjectDll(processName); // 卸載DLL } break; default: break; } return FALSE; } /// <summary> /// 初始化 /// </summary> /// <param name="hInstance"></param> /// <param name="hPrevInstance"></param> /// <param name="lpCmdLine"></param> /// <param name="nCmdShow"></param> /// <returns></returns> int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, &dialogProc); return 0; }
初學C++,代碼可能有些地方寫的不夠好,但是注入卸載是完全沒問題的。
注入邏輯解釋:
使用
CreateRemoteThread
函數可以為目標進程創建一個新的線程。在一個進程為另一個進程創建的線程就是遠程線程。
使用
LoadLibrary
函數把指定的DLL加載到進程中因此就可以在創建遠程線程的同時調用
LoadLibrary
函數,把指定的DLL
加載到目標進程中。
為什么創建遠程線程的時候調用 LoadLibrary 函數就能把 DLL 注入到目標進程中?
LoadLibrary
函數是 Kernel32.dll 中的一個成員
Kernel32.dll
這個DLL是創建進程必須的一個DLL,并且所有進程在內存中指向的 Kernel32.dll 是同一個地址
所以只要獲取到當前進程中 LoadLibrary
函數的地址就夠了
為什么要在目標進程中開辟一塊內存,再把DLL路徑寫入到塊內存中?
LoadLibrary
函數需要一個參數,就是DLL的路徑
把當前進程中的一個地址傳到另一個進程中,鬼知道另一個進程獲取這個地址中的數據時,讀取到的是否是我們想要的。
因此需要把DLL
的路徑直接寫入到目標進程中。
VirtualAllocEx
函數,在目標進程中開辟一塊空間,用來存放DLL路徑
WriteProcessMemory
函數,把DLL的路徑寫入進去
GetModuleHandle
獲取 Kernel32.dll 模塊
GetProcAddress
獲取 LoadLibraryA 函數在內存中的地址
CreateRemoteThread
創建遠程線程,并調用 LoadLibraryA 函數
LoadLibrary
、LoadLibraryA
、LoadLibraryW
這三者的區別。
LoadLibrary
是一個宏,可以根據字符集的不同,自動決定是使用 LoadLibraryA 還是 LoadLibraryW
LoadLibrary 宏定義的源碼:
WINBASEAPI _Ret_maybenull_ HMODULE WINAPI LoadLibraryA( _In_ LPCSTR lpLibFileName ); WINBASEAPI _Ret_maybenull_ HMODULE WINAPI LoadLibraryW( _In_ LPCWSTR lpLibFileName ); #ifdef UNICODE #define LoadLibrary LoadLibraryW #else #define LoadLibrary LoadLibraryA #endif // !UNICODE
卸載邏輯:
使用 CreateRemoteThread 函數創建一個遠程線程
調用 FreeLibrary 函數,卸載DLL
FreeLibrary 函數在 Kernel32.dll 模塊中,邏輯同上
FreeLibrary 函數需要 DLL 的內存地址
遍歷進程快照可以獲取到指定模塊的內存地址
卸載和注入的思路都是一樣的
確認DLL是否注入到目標進程中:
方式一:使用 procexp
方式二:Cheat Engine
確認 Kernel32.dll 中的 FreeLibrary 和 LoadLibraryA 在多個進程中是否指向同一塊內存地址:
可以通過CE查看多個進程中 Kernel32.dll 的內存地址是否相同
再通過 Kernel32.dll 中函數的內存地址,確認 FreeLibrary 和 LoadLibraryA 這兩個函數
關于“C++ DLL注入怎么實現”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。