2023-06-25 09:32:19 +00:00
|
|
|
#include <inject.h>
|
2023-06-06 17:23:15 +00:00
|
|
|
|
2023-07-16 11:58:18 +00:00
|
|
|
#define JUMP_SIZE (6 + sizeof(void*))
|
|
|
|
|
|
|
|
// Original values to recover after the injection
|
|
|
|
// Recovery is performed by the assembly payload
|
|
|
|
#pragma pack(push, 1)
|
|
|
|
struct recovery_data {
|
|
|
|
void *entryPointAddress;
|
|
|
|
char entryPointData[JUMP_SIZE];
|
|
|
|
|
|
|
|
void *importDescriptorAddress;
|
|
|
|
IMAGE_IMPORT_DESCRIPTOR importDescriptorData;
|
|
|
|
|
|
|
|
void *sizeFieldAddress;
|
|
|
|
DWORD sizeFieldData;
|
|
|
|
};
|
|
|
|
#pragma pack(pop)
|
|
|
|
|
2023-06-05 21:23:08 +00:00
|
|
|
static inline void write_protected_process_memory(HANDLE process, void *address, const void *buf, size_t size) {
|
|
|
|
DWORD oldProtect;
|
|
|
|
VirtualProtectEx(process, address, size, PAGE_EXECUTE_READWRITE, &oldProtect);
|
|
|
|
|
2023-12-29 12:14:05 +00:00
|
|
|
WriteProcessMemory(process, address, buf, size, NULL);
|
2023-06-05 21:23:08 +00:00
|
|
|
|
|
|
|
VirtualProtectEx(process, address, size, oldProtect, &oldProtect);
|
|
|
|
}
|
|
|
|
|
2023-07-03 11:04:04 +00:00
|
|
|
void inject(HANDLE process, const void *payload, size_t payloadSize, const wchar_t *dllPath) {
|
2023-06-05 21:23:08 +00:00
|
|
|
// Find the EXE header in the process
|
|
|
|
char exeHeader[1024];
|
2023-06-07 17:57:56 +00:00
|
|
|
IMAGE_DOS_HEADER *dosHeader = NULL;
|
|
|
|
IMAGE_NT_HEADERS64 *ntHeaders = NULL;
|
2023-06-05 21:23:08 +00:00
|
|
|
|
|
|
|
MEMORY_BASIC_INFORMATION memoryInfo;
|
|
|
|
char *currentAddress = 0x0;
|
|
|
|
while (VirtualQueryEx(process, currentAddress, &memoryInfo, sizeof(memoryInfo))) {
|
2023-12-29 12:14:05 +00:00
|
|
|
ReadProcessMemory(process, currentAddress, exeHeader, sizeof(exeHeader), NULL);
|
2023-06-05 21:23:08 +00:00
|
|
|
|
|
|
|
dosHeader = (IMAGE_DOS_HEADER*)exeHeader;
|
|
|
|
|
|
|
|
// DOS header magic "MZ"
|
|
|
|
if (dosHeader->e_magic != 0x5A4D) {
|
|
|
|
goto cont;
|
|
|
|
}
|
|
|
|
|
|
|
|
ntHeaders = (IMAGE_NT_HEADERS64*)(exeHeader + dosHeader->e_lfanew);
|
|
|
|
|
|
|
|
// NT header signature "PE"
|
|
|
|
if (ntHeaders->Signature != 0x4550) {
|
|
|
|
goto cont;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip DLLs
|
2023-07-03 22:03:21 +00:00
|
|
|
if ((ntHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) == IMAGE_FILE_DLL) {
|
2023-06-05 21:23:08 +00:00
|
|
|
goto cont;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip potential headers without an entry point
|
|
|
|
// I have no idea how and why they exist, but apparently they do
|
|
|
|
if (ntHeaders->OptionalHeader.AddressOfEntryPoint == 0) {
|
|
|
|
goto cont;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Found EXE header
|
|
|
|
break;
|
|
|
|
|
|
|
|
cont:
|
|
|
|
currentAddress += memoryInfo.RegionSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *exe = (char*)memoryInfo.BaseAddress;
|
|
|
|
|
2023-07-16 11:58:18 +00:00
|
|
|
|
|
|
|
// Inject the loader into the process
|
|
|
|
const unsigned char JUMP_INST[] = { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 };
|
|
|
|
|
|
|
|
size_t dllPathSize = (wcslen(dllPath) + 1) * sizeof(wchar_t);
|
|
|
|
|
|
|
|
size_t allocSize = payloadSize + dllPathSize + sizeof(struct recovery_data);
|
|
|
|
char *remoteAlloc = VirtualAllocEx(process, NULL, allocSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
|
|
|
|
|
|
|
// Write the assembly payload and dll path
|
2023-12-29 12:14:05 +00:00
|
|
|
WriteProcessMemory(process, remoteAlloc, payload, payloadSize, NULL);
|
|
|
|
WriteProcessMemory(process, remoteAlloc + payloadSize, dllPath, dllPathSize, NULL);
|
2023-07-16 11:58:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
// Modify the executable to run the assembly payload
|
|
|
|
// Recovery data structure
|
|
|
|
struct recovery_data rd;
|
|
|
|
|
2023-06-05 21:23:08 +00:00
|
|
|
// Replace the entry point with a jump to the loader
|
|
|
|
char *entryPoint = exe + ntHeaders->OptionalHeader.AddressOfEntryPoint;
|
|
|
|
|
2023-07-16 11:58:18 +00:00
|
|
|
// Save the original entry point address and bytes
|
|
|
|
rd.entryPointAddress = entryPoint;
|
2023-12-29 12:14:05 +00:00
|
|
|
ReadProcessMemory(process, rd.entryPointAddress, rd.entryPointData, sizeof(rd.entryPointData), NULL);
|
2023-06-05 21:23:08 +00:00
|
|
|
|
2023-07-16 11:58:18 +00:00
|
|
|
// Replace the entry point with a jump to the assembly payload
|
2023-06-05 21:23:08 +00:00
|
|
|
write_protected_process_memory(process, entryPoint, JUMP_INST, sizeof(JUMP_INST));
|
|
|
|
write_protected_process_memory(process, entryPoint + sizeof(JUMP_INST), &remoteAlloc, sizeof(remoteAlloc));
|
|
|
|
|
2023-07-16 11:58:18 +00:00
|
|
|
|
2023-06-05 21:23:08 +00:00
|
|
|
// Break the import table to prevent any dlls from being loaded
|
|
|
|
// Step 1: break the first import descriptor
|
|
|
|
char *importDescriptors = exe + ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
|
2023-07-16 11:58:18 +00:00
|
|
|
|
|
|
|
// Save the original descriptor address and bytes
|
|
|
|
rd.importDescriptorAddress = importDescriptors;
|
2023-12-29 12:14:05 +00:00
|
|
|
ReadProcessMemory(process, rd.importDescriptorAddress, &rd.importDescriptorData, sizeof(rd.importDescriptorData), NULL);
|
2023-07-16 11:58:18 +00:00
|
|
|
|
|
|
|
// Overwrite with zeroes
|
2023-06-05 21:23:08 +00:00
|
|
|
IMAGE_IMPORT_DESCRIPTOR firstDescriptor;
|
|
|
|
ZeroMemory(&firstDescriptor, sizeof(firstDescriptor));
|
|
|
|
write_protected_process_memory(process, importDescriptors, &firstDescriptor, sizeof(firstDescriptor));
|
|
|
|
|
|
|
|
// Step 2: break the image data directory entry
|
2023-07-16 11:58:18 +00:00
|
|
|
char* ddAddr = ((char*)&(ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size)) - exeHeader + exe;
|
|
|
|
|
|
|
|
// Save the original value
|
|
|
|
rd.sizeFieldAddress = ddAddr;
|
2023-12-29 12:14:05 +00:00
|
|
|
ReadProcessMemory(process, rd.sizeFieldAddress, &rd.sizeFieldData, sizeof(rd.sizeFieldData), NULL);
|
2023-07-16 11:58:18 +00:00
|
|
|
|
|
|
|
// Set to 0
|
2023-06-23 15:55:22 +00:00
|
|
|
DWORD newSize = 0;
|
2023-07-16 11:58:18 +00:00
|
|
|
write_protected_process_memory(process, ddAddr, &newSize, sizeof(newSize));
|
2023-06-05 21:23:08 +00:00
|
|
|
|
2023-07-16 11:58:18 +00:00
|
|
|
// Write recovery data to the allocation
|
2023-12-29 12:14:05 +00:00
|
|
|
WriteProcessMemory(process, remoteAlloc + payloadSize + dllPathSize, &rd, sizeof(rd), NULL);
|
2023-06-05 21:23:08 +00:00
|
|
|
}
|