C++?DLL注入工具(完整源碼)
先上源碼:
#include "Inject_Main.h" #include "resource.h" #include <Windows.h> #include <TlHelp32.h> #include <string> #include <TCHAR.H> using namespace std; /// <summary> /// 通過進(jìn)程名稱獲取該進(jìn)程句柄 /// </summary> /// <param name="processName"></param> /// <returns>成功返回 DWORD,失敗返回 0</returns> DWORD GetProcessByName(CONST TCHAR* processName) { ? ? // 獲取到整個系統(tǒng)的進(jìn)程 ? ? HANDLE processALL = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); ? ? // 定義一個容器,該容器用來接收,進(jìn)程信息 ? ? PROCESSENTRY32W processInfo = { 0 }; ? ? processInfo.dwSize = sizeof(PROCESSENTRY32W); ? ? // 根據(jù)進(jìn)程名稱,循環(huán)判斷是否是指定的進(jìn)程 ? ? do ? ? { ? ? ? ? if (_tcscmp(processInfo.szExeFile, processName) == 0) ? ? ? ? { ? ? ? ? ? ? // 釋放進(jìn)程快照,防止內(nèi)存泄露 ? ? ? ? ? ? CloseHandle(processALL); ? ? ? ? ? ? // 如果是返回指定進(jìn)程句柄 ? ? ? ? ? ? return processInfo.th32ProcessID; ? ? ? ? } ? ? ? ? // 一個迭代函數(shù) ? ? } while (Process32Next(processALL, &processInfo)); ? ? // 釋放進(jìn)程快照,防止內(nèi)存泄露 ? ? CloseHandle(processALL); ? ? return 0; } /// <summary> /// 獲取指定 DLL 的內(nèi)存地址 /// </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) { ? ? ? ? ? ? // 釋放進(jìn)程快照,防止內(nèi)存泄露 ? ? ? ? ? ? CloseHandle(handle); ? ? ? ? ? ? return moduleEntry.hModule; ? ? ? ? } ? ? } while (Module32Next(handle, &moduleEntry)); ? ? CloseHandle(handle); ? ? return 0; } /// <summary> /// 把指定DLL注入到指定進(jìn)程中 /// </summary> /// <param name="processName">processName 進(jìn)程名稱</param> /// <param name="dllPath">dllPath dll路徑</param> void InjectDll(const wchar_t* processName, const char* dllPath) { ? ? // 獲取指定進(jìn)程的句柄 ? ? DWORD dword = GetProcessByName(processName); ? ? if (dword == 0) ? ? { ? ? ? ? MessageBox(NULL, TEXT("沒有找到指定進(jìn)程"), TEXT("錯誤"), 0); ? ? ? ? return; ? ? } ? ? // 打開指定進(jìn)程 ? ? HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dword); ? ? if (hProcess == NULL) ? ? { ? ? ? ? MessageBox(NULL, TEXT("指定進(jìn)程打開失敗"), TEXT("錯誤"), 0); ? ? ? ? return; ? ? } ? ? /* ? ? ? ? 在指定進(jìn)程的地址,開辟一塊內(nèi)存空間,用來保存 DLL的路徑信息 ? ? ? ? LPVOID VirtualAllocEx( ? ? ? ? [in] ? ? ? ? ? HANDLE hProcess, 在那個進(jìn)程中開辟內(nèi)存 ? ? ? ? [in, optional] LPVOID lpAddress, 開辟內(nèi)存的起始地址 (NULL,不需要控制起始位置) ? ? ? ? [in] ? ? ? ? ? SIZE_T dwSize, ?開辟內(nèi)存的大?。ó?dāng)前保存的內(nèi)容是 DLL的路徑) ? ? ? ? [in] ? ? ? ? ? DWORD ?flAllocationType, 內(nèi)存分配的類型。(開辟內(nèi)存) ? ? ? ? [in] ? ? ? ? ? DWORD ?flProtect,設(shè)置內(nèi)存的權(quán)限 (可讀可寫) ? ? ? ? ); ? ? ?*/ ? ? LPVOID DLLAddress = VirtualAllocEx(hProcess, NULL, strlen(dllPath), MEM_COMMIT, PAGE_READWRITE); ? ? /* ? ? ? ? 把DLL的路徑,寫入到剛開辟出來的內(nèi)存中 ? ? ? ? BOOL WriteProcessMemory( ? ? ? ? [in] ?HANDLE ?hProcess, // 指定的進(jìn)程 ? ? ? ? [in] ?LPVOID ?lpBaseAddress, // DLL路徑字符串,寫入的基址 ? ? ? ? [in] ?LPCVOID lpBuffer, // DLL路徑字符串,的指針 ? ? ? ? [in] ?SIZE_T ?nSize, // 需要寫入內(nèi)存的字節(jié)長度 ? ? ? ? [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 這個函數(shù)的內(nèi)存地址 ? ? LPVOID loadADD = GetProcAddress(k32, "LoadLibraryA"); ? ? /* ? ? ? ? 在指定進(jìn)程中,創(chuàng)建一個線程 ? ? ? ? 并通過這個線程,調(diào)用 LoadLibrary 函數(shù) ? ? ? ? 通過 LoadLibrary 函數(shù),把 DLL 載入到目標(biāo)進(jìn)程中 ? ? ? ? HANDLE CreateRemoteThread( ? ? ? ? [in] ?HANDLE ? ? ? ? ? ? ? ? hProcess, // 指定進(jìn)程 ? ? ? ? [in] ?LPSECURITY_ATTRIBUTES ?lpThreadAttributes, // 設(shè)置線程安全屬性,表示線程是否可以繼承,NULL就夠了 ? ? ? ? [in] ?SIZE_T ? ? ? ? ? ? ? ? dwStackSize, // 堆棧的初始大小,0 表示使用可執(zhí)行文件的默認(rèn)大小 ? ? ? ? [in] ?LPTHREAD_START_ROUTINE lpStartAddress, // 遠(yuǎn)程進(jìn)程中,需要執(zhí)行的那個函數(shù)的指針 ? ? ? ? [in] ?LPVOID ? ? ? ? ? ? ? ? lpParameter, // 目前進(jìn)程中 DLL路徑的指針 ? ? ? ? [in] ?DWORD ? ? ? ? ? ? ? ? ?dwCreationFlags, // 0 線程在創(chuàng)建后立即運行。 ? ? ? ? [out] LPDWORD ? ? ? ? ? ? ? ?lpThreadId // [out] 當(dāng)前不需要這個返回值 ? ? ? ? ); ? ? */ ? ? HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)loadADD, DLLAddress, 0, NULL); ? ? // 釋放指定的模塊 ? ? CloseHandle(hThread); ? ? CloseHandle(hProcess); } /// <summary> /// 把指定進(jìn)程中的DLL卸載掉 /// </summary> /// <param name="processName"></param> /// <param name="dllPath"></param> void UnInjectDll(const wchar_t* processName) { ? ? // 通過進(jìn)程名稱獲取該進(jìn)程句柄 ? ? DWORD dword = GetProcessByName(processName); ? ? if (dword == 0) ? ? { ? ? ? ? MessageBox(NULL, TEXT("沒有找到指定進(jìn)程"), TEXT("錯誤"), 0); ? ? ? ? return; ? ? } ? ? // 獲取指定進(jìn)程中指定模塊的內(nèi)存地址 ? ? HMODULE hmodule = GetProcessModuleHandle(dword, L"WX_Read_Write.dll"); ? ? // 打開指定進(jìn)程 ? ? HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dword); ? ? if (hProcess == NULL) ? ? { ? ? ? ? MessageBox(NULL, TEXT("指定進(jìn)程打開失敗"), TEXT("錯誤"), 0); ? ? ? ? return; ? ? } ? ? // 獲取 Kernel32.dll 這個模塊 ? ? HMODULE k32 = GetModuleHandle(TEXT("Kernel32.dll")); ? ? // 在 Kernel32.dll 模塊中找到 LoadLibrary 這個函數(shù)的內(nèi)存地址 ? ? 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); // 關(guān)閉窗體 ? ? ? ? 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("進(jìn)程名稱不能為空"), 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; }
初學(xué)C++,代碼可能有些地方寫的不夠好,但是注入卸載是完全沒問題的。
注入邏輯解釋:
使用
CreateRemoteThread
函數(shù)可以為目標(biāo)進(jìn)程創(chuàng)建一個新的線程。在一個進(jìn)程為另一個進(jìn)程創(chuàng)建的線程就是遠(yuǎn)程線程。
使用
LoadLibrary
函數(shù)把指定的DLL加載到進(jìn)程中因此就可以在創(chuàng)建遠(yuǎn)程線程的同時調(diào)用
LoadLibrary
函數(shù),把指定的DLL
加載到目標(biāo)進(jìn)程中。
為什么創(chuàng)建遠(yuǎn)程線程的時候調(diào)用 LoadLibrary 函數(shù)就能把 DLL 注入到目標(biāo)進(jìn)程中?
LoadLibrary
函數(shù)是 Kernel32.dll 中的一個成員Kernel32.dll
這個DLL是創(chuàng)建進(jìn)程必須的一個DLL,并且所有進(jìn)程在內(nèi)存中指向的 Kernel32.dll 是同一個地址- 所以只要獲取到當(dāng)前進(jìn)程中
LoadLibrary
函數(shù)的地址就夠了
為什么要在目標(biāo)進(jìn)程中開辟一塊內(nèi)存,再把DLL路徑寫入到塊內(nèi)存中?
LoadLibrary
函數(shù)需要一個參數(shù),就是DLL的路徑- 把當(dāng)前進(jìn)程中的一個地址傳到另一個進(jìn)程中,鬼知道另一個進(jìn)程獲取這個地址中的數(shù)據(jù)時,讀取到的是否是我們想要的。
- 因此需要把
DLL
的路徑直接寫入到目標(biāo)進(jìn)程中。 VirtualAllocEx
函數(shù),在目標(biāo)進(jìn)程中開辟一塊空間,用來存放DLL路徑WriteProcessMemory
函數(shù),把DLL的路徑寫入進(jìn)去GetModuleHandle
獲取 Kernel32.dll 模塊GetProcAddress
獲取 LoadLibraryA 函數(shù)在內(nèi)存中的地址CreateRemoteThread
創(chuàng)建遠(yuǎn)程線程,并調(diào)用 LoadLibraryA 函數(shù)
LoadLibrary
、LoadLibraryA
、LoadLibraryW
這三者的區(qū)別。
LoadLibrary
是一個宏,可以根據(jù)字符集的不同,自動決定是使用 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 函數(shù)創(chuàng)建一個遠(yuǎn)程線程
調(diào)用 FreeLibrary 函數(shù),卸載DLL
FreeLibrary 函數(shù)在 Kernel32.dll 模塊中,邏輯同上
FreeLibrary 函數(shù)需要 DLL 的內(nèi)存地址
遍歷進(jìn)程快照可以獲取到指定模塊的內(nèi)存地址
卸載和注入的思路都是一樣的
確認(rèn)DLL是否注入到目標(biāo)進(jìn)程中:
方式一:使用 procexp
方式二:Cheat Engine
確認(rèn) Kernel32.dll 中的 FreeLibrary 和 LoadLibraryA 在多個進(jìn)程中是否指向同一塊內(nèi)存地址:
可以通過CE查看多個進(jìn)程中 Kernel32.dll 的內(nèi)存地址是否相同
再通過 Kernel32.dll 中函數(shù)的內(nèi)存地址,確認(rèn) FreeLibrary 和 LoadLibraryA 這兩個函數(shù)
到此這篇關(guān)于C++ DLL注入工具(完整源碼)的文章就介紹到這了,更多相關(guān)C++ DLL注入工具內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++中volatile關(guān)鍵字的使用詳解以及常見的誤解
volatile 關(guān)鍵字是一種類型修飾符,用它聲明的類型變量表示可以被某些編譯器未知的因素更改,比如:操作系統(tǒng),硬件或者其他線程等2020-01-01C++實現(xiàn)LeetCode(647.回文子字符串)
這篇文章主要介紹了C++實現(xiàn)LeetCode(647.回文子字符串),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07