1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <tlhelp32.h>
#pragma comment(lib, "kernel32.lib")
#pragma comment(lib, "user32.lib")
// Helper to free data when we leave the scope.
class DataToFree {
public:
HANDLE hProcess;
HANDLE snapshotHandle;
LPVOID remoteMemoryAddr;
int remoteMemorySize;
DataToFree(){
this->hProcess = nullptr;
this->snapshotHandle = nullptr;
this->remoteMemoryAddr = nullptr;
this->remoteMemorySize = 0;
}
~DataToFree() {
if(this->hProcess != nullptr){
if(this->remoteMemoryAddr != nullptr && this->remoteMemorySize != 0){
VirtualFreeEx(this->hProcess, this->remoteMemoryAddr, this->remoteMemorySize, MEM_RELEASE);
this->remoteMemoryAddr = nullptr;
this->remoteMemorySize = 0;
}
CloseHandle(this->hProcess);
this->hProcess = nullptr;
}
if(this->snapshotHandle != nullptr){
CloseHandle(this->snapshotHandle);
this->snapshotHandle = nullptr;
}
}
};
/**
* All we do here is load a dll in a remote program (in a remote thread).
*
* Arguments must be the pid and the dll name to run.
*
* i.e.: inject_dll.exe <pid> <dll path>
*/
int wmain( int argc, wchar_t *argv[ ], wchar_t *envp[ ] )
{
std::cout << "Running executable to inject dll." << std::endl;
// Helper to clear resources.
DataToFree dataToFree;
if(argc != 3){
std::cout << "Expected 2 arguments (pid, dll name)." << std::endl;
return 1;
}
const int pid = _wtoi(argv[1]);
if(pid == 0){
std::cout << "Invalid pid." << std::endl;
return 2;
}
const int MAX_PATH_SIZE_PADDED = MAX_PATH + 1;
char dllPath[MAX_PATH_SIZE_PADDED];
memset(&dllPath[0], '\0', MAX_PATH_SIZE_PADDED);
size_t pathLen = 0;
wcstombs_s(&pathLen, dllPath, argv[2], MAX_PATH);
const bool inheritable = false;
const HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_CREATE_THREAD | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION, inheritable, pid);
if(hProcess == nullptr || hProcess == INVALID_HANDLE_VALUE){
std::cout << "Unable to open process with pid: " << pid << ". Error code: " << GetLastError() << "." << std::endl;
return 3;
}
dataToFree.hProcess = hProcess;
std::cout << "OpenProcess with pid: " << pid << std::endl;
const LPVOID remoteMemoryAddr = VirtualAllocEx(hProcess, nullptr, MAX_PATH_SIZE_PADDED, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(remoteMemoryAddr == nullptr){
std::cout << "Error. Unable to allocate memory in pid: " << pid << ". Error code: " << GetLastError() << "." << std::endl;
return 4;
}
dataToFree.remoteMemorySize = MAX_PATH_SIZE_PADDED;
dataToFree.remoteMemoryAddr = remoteMemoryAddr;
std::cout << "VirtualAllocEx in pid: " << pid << std::endl;
const bool written = WriteProcessMemory(hProcess, remoteMemoryAddr, dllPath, pathLen, nullptr);
if(!written){
std::cout << "Error. Unable to write to memory in pid: " << pid << ". Error code: " << GetLastError() << "." << std::endl;
return 5;
}
std::cout << "WriteProcessMemory in pid: " << pid << std::endl;
const LPVOID loadLibraryAddress = (LPVOID) GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
if(loadLibraryAddress == nullptr){
std::cout << "Error. Unable to get LoadLibraryA address. Error code: " << GetLastError() << "." << std::endl;
return 6;
}
std::cout << "loadLibraryAddress: " << pid << std::endl;
const HANDLE remoteThread = CreateRemoteThread(hProcess, nullptr, 0, (LPTHREAD_START_ROUTINE) loadLibraryAddress, remoteMemoryAddr, 0, nullptr);
if (remoteThread == nullptr) {
std::cout << "Error. Unable to CreateRemoteThread. Error code: " << GetLastError() << "." << std::endl;
return 7;
}
// We wait for the load to finish before proceeding to get the function to actually do the attach.
std::cout << "Waiting for LoadLibraryA to complete." << std::endl;
DWORD result = WaitForSingleObject(remoteThread, 5 * 1000);
if(result == WAIT_TIMEOUT) {
std::cout << "WaitForSingleObject(LoadLibraryA thread) timed out." << std::endl;
return 8;
} else if(result == WAIT_FAILED) {
std::cout << "WaitForSingleObject(LoadLibraryA thread) failed. Error code: " << GetLastError() << "." << std::endl;
return 9;
}
std::cout << "Ok, finished dll injection." << std::endl;
return 0;
}
|