C++ DLL injection tool complete source code

First on the source code

#include "Inject_Main.h"
#include "resource.h"
#include <Windows.h>
#include <TlHelp32.h>
#include <string>
#include <TCHAR.H>

using namespace std;


/// <summary>
/// Get the process handle by the process name
/// </summary>
/// <param name="processName"></param>
/// <returns>Successful return DWORD,Failure returned 0</returns>
DWORD GetProcessByName(CONST TCHAR* processName) {
    // Get the process of the whole system
    HANDLE processALL = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

    // Define a container that is used to receive process information
    PROCESSENTRY32W processInfo = { 0 };
    processInfo.dwSize = sizeof(PROCESSENTRY32W);

    // According to the process name, loop to judge whether it is the specified process
    do
    {
        if (_tcscmp(processInfo.szExeFile, processName) == 0)
        {
            // Release process snapshot to prevent memory leakage
            CloseHandle(processALL);
            // If yes, return the specified process handle
            return processInfo.th32ProcessID;
        }
        // An iterative function
    } while (Process32Next(processALL, &processInfo));
    // Release process snapshot to prevent memory leakage
    CloseHandle(processALL);
    return 0;
}

/// <summary>
/// Get specified DLL Memory address of
/// </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) {
            // Release process snapshot to prevent memory leakage
            CloseHandle(handle);
            return moduleEntry.hModule;
        }
    } while (Module32Next(handle, &moduleEntry));
    CloseHandle(handle);
    return 0;
}

/// <summary>
/// Assign DLL Inject into the specified process
/// </summary>
/// <param name="processName">processName Process name</param>
/// <param name="dllPath">dllPath dll route</param>
void InjectDll(const wchar_t* processName, const char* dllPath) {
    // Gets the handle of the specified process
    DWORD dword = GetProcessByName(processName);
    if (dword == 0)
    {
        MessageBox(NULL, TEXT("The specified process was not found"), TEXT("error"), 0);
        return;
    }
    // Open the specified process
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dword);
    if (hProcess == NULL)
    {
        MessageBox(NULL, TEXT("The specified process failed to open"), TEXT("error"), 0);
        return;
    }
    /*
        Open up a memory space at the address of the specified process to save the path information of the DLL
        LPVOID VirtualAllocEx(
        [in]           HANDLE hProcess, Open up memory in that process
        [in, optional] LPVOID lpAddress, The starting address of the development memory (NULL, no need to control the starting position)
        [in]           SIZE_T dwSize,  The size of the development memory (the current saved content is the path of the DLL)
        [in]           DWORD  flAllocationType, Type of memory allocation. (open up memory)
        [in]           DWORD  flProtect,Set memory permissions (readable and writable)
        );
     */
    LPVOID DLLAddress = VirtualAllocEx(hProcess, NULL, strlen(dllPath), MEM_COMMIT, PAGE_READWRITE);
    /*
        Write the path of the DLL into the newly opened memory
        BOOL WriteProcessMemory(
        [in]  HANDLE  hProcess, // Specified process
        [in]  LPVOID  lpBaseAddress, // DLL Path string, write base address
        [in]  LPCVOID lpBuffer, // DLL Path string, pointer to
        [in]  SIZE_T  nSize, // Length of bytes to be written to memory
        [out] SIZE_T  *lpNumberOfBytesWritten // [out] Return a pointer, no need, NULL
        );
    */

    if (WriteProcessMemory(hProcess, DLLAddress, dllPath, strlen(dllPath), NULL) == 0)
    {
        MessageBox(NULL, TEXT("Path write failed"), TEXT("error"), 0);
        return;
    }

    // obtain Kernel32.dll This module
    HMODULE k32 = GetModuleHandle(TEXT("Kernel32.dll"));
    // stay Kernel32.dll Found in module LoadLibrary Memory address of this function
    LPVOID loadADD = GetProcAddress(k32, "LoadLibraryA");
    /*
        Create a thread in the specified process
        And through this thread, call the LoadLibrary function
        Load the DLL into the target process through the LoadLibrary function
        HANDLE CreateRemoteThread(
        [in]  HANDLE                 hProcess, // Specify process
        [in]  LPSECURITY_ATTRIBUTES  lpThreadAttributes, // Set the thread safety property to indicate whether the thread can inherit. NULL is enough
        [in]  SIZE_T                 dwStackSize, // The initial size of the stack. 0 means the default size of the executable file is used
        [in]  LPTHREAD_START_ROUTINE lpStartAddress, // Pointer to the function to be executed in the remote process
        [in]  LPVOID                 lpParameter, // Pointer to the DLL path in the current process
        [in]  DWORD                  dwCreationFlags, // 0 The thread runs immediately after creation.
        [out] LPDWORD                lpThreadId // [out] This return value is not currently required
        );
    */
    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)loadADD, DLLAddress, 0, NULL);


    // Release the specified module
    CloseHandle(hThread);
    CloseHandle(hProcess);

}



/// <summary>
/// Put in the specified process DLL Unload
/// </summary>
/// <param name="processName"></param>
/// <param name="dllPath"></param>
void UnInjectDll(const wchar_t* processName) {
    // Get the process handle by the process name
    DWORD dword = GetProcessByName(processName);
    if (dword == 0)
    {
        MessageBox(NULL, TEXT("The specified process was not found"), TEXT("error"), 0);
        return;
    }
    // Gets the memory address of the specified module in the specified process
    HMODULE hmodule = GetProcessModuleHandle(dword, L"WX_Read_Write.dll");

    // Open the specified process
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dword);
    if (hProcess == NULL)
    {
        MessageBox(NULL, TEXT("The specified process failed to open"), TEXT("error"), 0);
        return;
    }

    // obtain Kernel32.dll This module
    HMODULE k32 = GetModuleHandle(TEXT("Kernel32.dll"));
    // stay Kernel32.dll Found in module LoadLibrary Memory address of this function
    LPVOID loadADD = GetProcAddress(k32, "FreeLibrary");

    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)loadADD, (LPVOID)hmodule, 0, NULL);

    // Release the specified module
    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); // Closing Windows 
        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("Process name cannot be empty"), TEXT("error"), 0);
            }
            if (sizeof(dllPath) == 0)
            {
                MessageBox(NULL, TEXT("DLL Path cannot be empty"), TEXT("error"), 0);
            }
            InjectDll(processName, dllPath); // injection DLL
        }
        if (wParam == Btn_unInject_DLL)
        {
            UnInjectDll(processName); // uninstall DLL
        }
        break;
    default:
        break;
    }
    return FALSE;
}


/// <summary>
/// initialization
/// </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;
}

For beginners of C + +, the code may not be well written in some places, but there is no problem with injection and unloading.

 

Injection logic explanation:

Use the CreateRemoteThread function to create a new thread for the target process.

A thread created in one process for another process is a remote thread.

Use the LoadLibrary function to load the specified DLL into the process

Therefore, you can call the LoadLibrary function while creating a remote thread to load the specified DLL into the target process.

 

Why can the DLL be injected into the target process by calling the LoadLibrary function when creating a remote thread

The LoadLibrary function is Kernel32 A member in DLL

  Kernel32.dll this DLL is a necessary DLL for creating processes, and all processes point to Kernel32 in memory DLL is the same address

So just get the address of the LoadLibrary function in the current process

 

Why open up a block of memory in the target process and then write the DLL path to the block memory

The LoadLibrary function requires a parameter, which is the path of the DLL

Transfer an address in the current process to another process. Who knows if the other process reads what we want when it obtains the data in this address.

Therefore, you need to write the path of the DLL directly to the target process.

VirtualAllocEx Function to open up a space in the target process for storage DLL route
WriteProcessMemory Function, put DLL Write in path

GetModuleHandle obtain Kernel32.dll modular
GetProcAddress obtain LoadLibraryA The address of the function in memory
CreateRemoteThread Create a remote thread and call LoadLibraryA function

The difference between LoadLibrary, LoadLibraryA and LoadLibraryW.

LoadLibrary is a macro that can automatically decide whether to use LoadLibraryA or LoadLibraryW according to different character sets

LoadLibrary Macro definition source code
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

Unload logic:

Use the CreateRemoteThread function to create a remote thread

Call the FreeLibrary function to unload the DLL

FreeLibrary function in Kernel32 DLL module, the logic is the same as above

The FreeLibrary function requires the memory address of the DLL

The memory address of the specified module can be obtained by traversing the process snapshot

The idea of unloading and injection is the same

 

Confirm whether the DLL is injected into the target process

Method 1: use {procexp

 

 

 

Mode 2: Cheat Engine

 

 

 

 

 

 

 

 

 

Confirm Kernel32 Whether FreeLibrary and LoadLibraryA in DLL point to the same memory address in multiple processes:

 

 

 

You can view {Kernel32. In multiple processes through CE Is the memory address of DLL the same

And then through # Kernel32 DLL, and confirm the functions FreeLibrary and loadlibrary a

 

Added by dandaman2007 on Sat, 29 Jan 2022 19:27:21 +0200