服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C++ DLL注入工具(完整源码)

C++ DLL注入工具(完整源码)

2022-09-14 15:45乔安生 C/C++

这篇文章主要介绍了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.th32ProcessID;
        }
        // 一个迭代函数
    } 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

C++ DLL注入工具(完整源码)

方式二:Cheat Engine

C++ DLL注入工具(完整源码)

C++ DLL注入工具(完整源码)

C++ DLL注入工具(完整源码)

确认 Kernel32.dll 中的 FreeLibrary 和 LoadLibraryA 在多个进程中是否指向同一块内存地址:

C++ DLL注入工具(完整源码)

可以通过CE查看多个进程中 Kernel32.dll 的内存地址是否相同

再通过 Kernel32.dll 中函数的内存地址,确认 FreeLibrary 和 LoadLibraryA 这两个函数

到此这篇关于C++ DLL注入工具(完整源码)的文章就介绍到这了,更多相关C++ DLL注入工具内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/ansheng/p/15855896.html

延伸 · 阅读

精彩推荐
  • C/C++C++的new和delete详解

    C++的new和delete详解

    这篇文章主要介绍的是C++的new和delete,可以这么理解 new相当于是malloc 、delete相当于是free,下面我们就来详情介绍,,需要的朋友可以参一考...

    欧阳大哥20137362022-01-11
  • C/C++详解C语言基础的类型转换

    详解C语言基础的类型转换

    这篇文章主要为大家介绍了C语言基础的类型转换,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助...

    RookieStriver7432022-02-23
  • C/C++C++实现LeetCode(128.求最长连续序列)

    C++实现LeetCode(128.求最长连续序列)

    这篇文章主要介绍了C++实现LeetCode(128.求最长连续序列),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...

    Grandyang4472021-12-03
  • C/C++C++ 名称空间详情

    C++ 名称空间详情

    当一个项目变得大型之后,我们会引入很多的库,这么一来两个库很可能会定义List、Tree、Node同名的类,编译器要是不考虑这情况的话,程序员调用时就会...

    用户9824330962144502022-01-11
  • C/C++C语言入门篇--函数及数组用法

    C语言入门篇--函数及数组用法

    本篇文章是c语言基础篇,主要为大家介绍了C语言的函数与数组,每个函数本质上都实现一个最小的功能,而main函数只负责调用函数,实现代码的核心逻辑...

    yycure6032021-12-23
  • C/C++基于C++自动化编译工具的使用详解

    基于C++自动化编译工具的使用详解

    本篇文章是对C++中自动化编译工具的使用进行了详细的分析介绍,需要的朋友参考下...

    C++教程网3432020-12-01
  • C/C++Visual C++中MFC消息的分类

    Visual C++中MFC消息的分类

    Visual C++中MFC消息的分类,标准(窗口)消息:窗口消息一般与窗口内部运作有关,如创建窗口,绘制窗口,销毁窗口,通常,消息是从系统发到窗口,或从窗...

    C++教程网2082020-11-10
  • C/C++基于Qt实现视频播放器功能

    基于Qt实现视频播放器功能

    本文通过实例代码给大家介绍了基于Qt实现视频播放器功能,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧...

    冷月枫啊10692022-01-11