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) {
? ? // 獲取到整個系統(tǒng)的進程
? ? HANDLE processALL = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
? ? // 定義一個容器,該容器用來接收,進程信息
? ? PROCESSENTRY32W processInfo = { 0 };
? ? processInfo.dwSize = sizeof(PROCESSENTRY32W);
? ? // 根據進程名稱,循環(huán)判斷是否是指定的進程
? ? do
? ? {
? ? ? ? if (_tcscmp(processInfo.szExeFile, processName) == 0)
? ? ? ? {
? ? ? ? ? ? // 釋放進程快照,防止內存泄露
? ? ? ? ? ? CloseHandle(processALL);
? ? ? ? ? ? // 如果是返回指定進程句柄
? ? ? ? ? ? return processInfo.th32ProcessID;
? ? ? ? }
? ? ? ? // 一個迭代函數(shù)
? ? } 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, ?開辟內存的大?。ó斍氨4娴膬热菔?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, // 需要寫入內存的字節(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ù)的內存地址
? ? LPVOID loadADD = GetProcAddress(k32, "LoadLibraryA");
? ? /*
? ? ? ? 在指定進程中,創(chuàng)建一個線程
? ? ? ? 并通過這個線程,調用 LoadLibrary 函數(shù)
? ? ? ? 通過 LoadLibrary 函數(shù),把 DLL 載入到目標進程中
? ? ? ? HANDLE CreateRemoteThread(
? ? ? ? [in] ?HANDLE ? ? ? ? ? ? ? ? hProcess, // 指定進程
? ? ? ? [in] ?LPSECURITY_ATTRIBUTES ?lpThreadAttributes, // 設置線程安全屬性,表示線程是否可以繼承,NULL就夠了
? ? ? ? [in] ?SIZE_T ? ? ? ? ? ? ? ? dwStackSize, // 堆棧的初始大小,0 表示使用可執(zhí)行文件的默認大小
? ? ? ? [in] ?LPTHREAD_START_ROUTINE lpStartAddress, // 遠程進程中,需要執(zhí)行的那個函數(shù)的指針
? ? ? ? [in] ?LPVOID ? ? ? ? ? ? ? ? lpParameter, // 目前進程中 DLL路徑的指針
? ? ? ? [in] ?DWORD ? ? ? ? ? ? ? ? ?dwCreationFlags, // 0 線程在創(chuàng)建后立即運行。
? ? ? ? [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 這個函數(shù)的內存地址
? ? 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函數(shù)可以為目標進程創(chuàng)建一個新的線程。在一個進程為另一個進程創(chuàng)建的線程就是遠程線程。
使用
LoadLibrary函數(shù)把指定的DLL加載到進程中因此就可以在創(chuàng)建遠程線程的同時調用
LoadLibrary函數(shù),把指定的DLL加載到目標進程中。
為什么創(chuàng)建遠程線程的時候調用 LoadLibrary 函數(shù)就能把 DLL 注入到目標進程中?
LoadLibrary函數(shù)是 Kernel32.dll 中的一個成員Kernel32.dll這個DLL是創(chuàng)建進程必須的一個DLL,并且所有進程在內存中指向的 Kernel32.dll 是同一個地址- 所以只要獲取到當前進程中
LoadLibrary函數(shù)的地址就夠了
為什么要在目標進程中開辟一塊內存,再把DLL路徑寫入到塊內存中?
LoadLibrary函數(shù)需要一個參數(shù),就是DLL的路徑- 把當前進程中的一個地址傳到另一個進程中,鬼知道另一個進程獲取這個地址中的數(shù)據時,讀取到的是否是我們想要的。
- 因此需要把
DLL的路徑直接寫入到目標進程中。 VirtualAllocEx函數(shù),在目標進程中開辟一塊空間,用來存放DLL路徑WriteProcessMemory函數(shù),把DLL的路徑寫入進去GetModuleHandle獲取 Kernel32.dll 模塊GetProcAddress獲取 LoadLibraryA 函數(shù)在內存中的地址CreateRemoteThread創(chuàng)建遠程線程,并調用 LoadLibraryA 函數(shù)
LoadLibrary 、LoadLibraryA、LoadLibraryW 這三者的區(qū)別。
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 函數(shù)創(chuàng)建一個遠程線程
調用 FreeLibrary 函數(shù),卸載DLL
FreeLibrary 函數(shù)在 Kernel32.dll 模塊中,邏輯同上
FreeLibrary 函數(shù)需要 DLL 的內存地址
遍歷進程快照可以獲取到指定模塊的內存地址
卸載和注入的思路都是一樣的
確認DLL是否注入到目標進程中:
方式一:使用 procexp

方式二:Cheat Engine



確認 Kernel32.dll 中的 FreeLibrary 和 LoadLibraryA 在多個進程中是否指向同一塊內存地址:

可以通過CE查看多個進程中 Kernel32.dll 的內存地址是否相同
再通過 Kernel32.dll 中函數(shù)的內存地址,確認 FreeLibrary 和 LoadLibraryA 這兩個函數(shù)
到此這篇關于C++ DLL注入工具(完整源碼)的文章就介紹到這了,更多相關C++ DLL注入工具內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C++實現(xiàn)LeetCode(647.回文子字符串)
這篇文章主要介紹了C++實現(xiàn)LeetCode(647.回文子字符串),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下2021-07-07

