千家信息网

C++ DLL注入怎么实现

发表于:2025-02-01 作者:千家信息网编辑
千家信息网最后更新 2025年02月01日,这篇文章主要介绍"C++ DLL注入怎么实现"的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇"C++ DLL注入怎么实现"文章能帮助大家解决问题。先上源码:#in
千家信息网最后更新 2025年02月01日C++ DLL注入怎么实现

这篇文章主要介绍"C++ DLL注入怎么实现"的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇"C++ DLL注入怎么实现"文章能帮助大家解决问题。

先上源码:

#include "Inject_Main.h"#include "resource.h"#include #include #include #include using namespace std;/// /// 通过进程名称获取该进程句柄/// /// /// 成功返回 DWORD,失败返回 0DWORD 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;}/// /// 获取指定 DLL 的内存地址/// /// /// /// 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;}/// /// 把指定DLL注入到指定进程中/// /// processName 进程名称/// dllPath dll路径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);}/// /// 把指定进程中的DLL卸载掉/// /// /// 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);}/// /// /// /// /// /// /// /// 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;}/// /// 初始化/// /// /// /// /// /// 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 函数

LoadLibraryLoadLibraryALoadLibraryW 这三者的区别。

LoadLibrary 是一个宏,可以根据字符集的不同,自动决定是使用 LoadLibraryA 还是 LoadLibraryW

LoadLibrary 宏定义的源码:

WINBASEAPI_Ret_maybenull_HMODULEWINAPILoadLibraryA(    _In_ LPCSTR lpLibFileName    );WINBASEAPI_Ret_maybenull_HMODULEWINAPILoadLibraryW(    _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注入怎么实现"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注行业资讯频道,小编每天都会为大家更新不同的知识点。

0