Skip to content

Instantly share code, notes, and snippets.

@MurylloEx
Last active October 17, 2024 14:01
Show Gist options
  • Save MurylloEx/df1b56c928850a47d51ff2f4fcc16054 to your computer and use it in GitHub Desktop.
Save MurylloEx/df1b56c928850a47d51ff2f4fcc16054 to your computer and use it in GitHub Desktop.
This source load a simple DLL that was compiled in a .EXE as a resource.
typedef struct BASE_RELOCATION_BLOCK {
DWORD PageAddress;
DWORD BlockSize;
} BASE_RELOCATION_BLOCK, *PBASE_RELOCATION_BLOCK;
typedef struct BASE_RELOCATION_ENTRY {
USHORT Offset : 12;
USHORT Type : 4;
} BASE_RELOCATION_ENTRY, * PBASE_RELOCATION_ENTRY;
typedef BOOL(WINAPI* DLL_ENTRY_CALLBACK)(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved);
LPVOID VirtualAllocNear(
IN LPVOID PreferredBaseAddress,
IN SIZE_T SizeOfBlock,
IN DWORD AllocationTypeFlags,
IN DWORD ProtectionFlags
) {
LPVOID AllocatedAddress = VirtualAlloc(
PreferredBaseAddress,
SizeOfBlock,
AllocationTypeFlags,
ProtectionFlags
);
if (AllocatedAddress != NULL) {
return AllocatedAddress;
}
SYSTEM_INFO SystemInfo = { 0 };
GetSystemInfo(&SystemInfo);
DWORD_PTR HighestAddressAvailable = (DWORD_PTR)SystemInfo.lpMaximumApplicationAddress;
DWORD_PTR PreferredAddress = (DWORD_PTR)PreferredBaseAddress;
DWORD_PTR AddressOffset = PreferredAddress;
MEMORY_BASIC_INFORMATION MemoryPageInfo = { 0 };
while (AddressOffset < HighestAddressAvailable) {
AddressOffset += SystemInfo.dwPageSize;
ZeroMemory(&MemoryPageInfo, sizeof(MEMORY_BASIC_INFORMATION));
VirtualQuery((LPCVOID)AddressOffset, &MemoryPageInfo, SizeOfBlock);
if (MemoryPageInfo.State == MEM_FREE) {
LPVOID FoundAddress = VirtualAlloc(
MemoryPageInfo.BaseAddress,
SizeOfBlock,
AllocationTypeFlags,
ProtectionFlags
);
if (FoundAddress) {
return FoundAddress;
}
}
}
return VirtualAlloc(NULL, SizeOfBlock, AllocationTypeFlags, ProtectionFlags);
}
BOOL AllocateImageHeaders(
IN LPVOID BufferAddress,
OUT LPVOID* ImageBaseAddress,
OUT PIMAGE_DOS_HEADER* DosHeader,
OUT PIMAGE_NT_HEADERS* NtHeaders)
{
if (BufferAddress == NULL) {
return FALSE;
}
*DosHeader = (PIMAGE_DOS_HEADER)BufferAddress;
*NtHeaders = (PIMAGE_NT_HEADERS)((DWORD_PTR)BufferAddress + (*DosHeader)->e_lfanew);
DWORD_PTR ImageBase = (*NtHeaders)->OptionalHeader.ImageBase;
DWORD_PTR SizeOfImage = (*NtHeaders)->OptionalHeader.SizeOfImage;
PIMAGE_SECTION_HEADER FirstImageSectionHeader = IMAGE_FIRST_SECTION(*NtHeaders);
*ImageBaseAddress = VirtualAllocNear((LPVOID)ImageBase, SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (*ImageBaseAddress == NULL) {
*DosHeader = NULL;
*NtHeaders = NULL;
return FALSE;
}
// copy over DLL image headers to the newly allocated space for the DLL
memcpy(*ImageBaseAddress, BufferAddress, (*NtHeaders)->OptionalHeader.SizeOfHeaders);
for (WORD i = 0; i < (*NtHeaders)->FileHeader.NumberOfSections; i++)
{
LPVOID SectionDestinationAddress = (LPVOID)((DWORD_PTR)*ImageBaseAddress + (DWORD_PTR)FirstImageSectionHeader->VirtualAddress);
LPVOID SectionSourceAddress = (LPVOID)((DWORD_PTR)BufferAddress + (DWORD_PTR)FirstImageSectionHeader->PointerToRawData);
memcpy(SectionDestinationAddress, SectionSourceAddress, FirstImageSectionHeader->SizeOfRawData);
FirstImageSectionHeader++;
}
return TRUE;
}
BOOL PerformImageRelocations(
IN LPVOID ImageBaseAddress,
IN PIMAGE_DOS_HEADER DosHeader,
IN PIMAGE_NT_HEADERS NtHeaders
) {
if ((ImageBaseAddress == NULL) || (DosHeader == NULL) || (NtHeaders == NULL)) {
return FALSE;
}
DWORD_PTR ImageBase = NtHeaders->OptionalHeader.ImageBase;
IMAGE_DATA_DIRECTORY Relocations = NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
DWORD_PTR RelativeVirtualAddress = (DWORD_PTR)ImageBaseAddress - (DWORD_PTR)ImageBase;
DWORD_PTR RelocationTableAddress = (DWORD_PTR)ImageBaseAddress + Relocations.VirtualAddress;
DWORD RelocationsProcessed = 0;
while (RelocationsProcessed < Relocations.Size)
{
PBASE_RELOCATION_BLOCK RelocationBlock = (PBASE_RELOCATION_BLOCK)(RelocationTableAddress + RelocationsProcessed);
RelocationsProcessed += sizeof(BASE_RELOCATION_BLOCK);
DWORD RelocationsCount = (RelocationBlock->BlockSize - sizeof(BASE_RELOCATION_BLOCK)) / sizeof(BASE_RELOCATION_ENTRY);
PBASE_RELOCATION_ENTRY RelocationEntries = (PBASE_RELOCATION_ENTRY)(RelocationTableAddress + RelocationsProcessed);
for (DWORD i = 0; i < RelocationsCount; i++)
{
RelocationsProcessed += sizeof(BASE_RELOCATION_ENTRY);
if (RelocationEntries[i].Type == 0)
{
continue;
}
DWORD_PTR RelocationRelativeVirtualAddress = (DWORD_PTR)RelocationBlock->PageAddress + RelocationEntries[i].Offset;
PVOID Address = (PVOID)((DWORD_PTR)ImageBaseAddress + RelocationRelativeVirtualAddress);
DWORD_PTR AddressToPatch = *(DWORD_PTR*)Address;
AddressToPatch += RelativeVirtualAddress;
*(DWORD_PTR*)Address = AddressToPatch;
}
}
return TRUE;
}
BOOL ResolveImageDependencies(
IN LPVOID ImageBaseAddress,
IN PIMAGE_NT_HEADERS NtHeaders
) {
if ((ImageBaseAddress == NULL) || (NtHeaders == NULL)) {
return FALSE;
}
IMAGE_DATA_DIRECTORY ImportsDirectory = NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(ImportsDirectory.VirtualAddress + (DWORD_PTR)ImageBaseAddress);
while (ImportDescriptor->Name != NULL)
{
LPCSTR LibraryName = (LPCSTR)(ImportDescriptor->Name + (DWORD_PTR)ImageBaseAddress);
HMODULE ModuleHandle = LoadLibraryA(LibraryName);
if (ModuleHandle)
{
PIMAGE_THUNK_DATA Thunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)ImageBaseAddress + ImportDescriptor->FirstThunk);
while (Thunk->u1.AddressOfData != NULL)
{
if (IMAGE_SNAP_BY_ORDINAL(Thunk->u1.Ordinal))
{
// get function address by ordinal number
LPCSTR FunctionOrdinal = (LPCSTR)IMAGE_ORDINAL(Thunk->u1.Ordinal);
Thunk->u1.Function = (DWORD_PTR)GetProcAddress(ModuleHandle, FunctionOrdinal);
}
else
{
// get function address by function name
PIMAGE_IMPORT_BY_NAME ImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)ImageBaseAddress + Thunk->u1.AddressOfData);
Thunk->u1.Function = (DWORD_PTR)GetProcAddress(ModuleHandle, ImportByName->Name);
}
++Thunk;
}
}
ImportDescriptor++;
}
return TRUE;
}
LPVOID LoadLibraryInMemory(
IN LPVOID BufferAddress,
OUT LPVOID* VirtualAddress
) {
LPVOID ImageBaseAddress = NULL;
PIMAGE_DOS_HEADER DosHeader = NULL;
PIMAGE_NT_HEADERS NtHeaders = NULL;
BOOL Status = FALSE;
Status = AllocateImageHeaders(BufferAddress, &ImageBaseAddress, &DosHeader, &NtHeaders);
if (Status == FALSE) {
return NULL;
}
Status = PerformImageRelocations(ImageBaseAddress, DosHeader, NtHeaders);
if (Status == FALSE) {
VirtualFree(ImageBaseAddress, NULL, MEM_RELEASE);
return NULL;
}
Status = ResolveImageDependencies(ImageBaseAddress, NtHeaders);
if (Status == FALSE) {
VirtualFree(ImageBaseAddress, NULL, MEM_RELEASE);
return NULL;
}
*VirtualAddress = ImageBaseAddress;
FlushInstructionCache(GetCurrentProcess(), ImageBaseAddress, NtHeaders->OptionalHeader.SizeOfImage);
return (LPVOID)((DWORD_PTR)ImageBaseAddress + NtHeaders->OptionalHeader.AddressOfEntryPoint);
}
int main()
{
HRSRC MaliciousResource = FindResourceW(NULL, MAKEINTRESOURCEW(IDR_PAYLOAD_X86), L"PAYLOAD_X86");
if (MaliciousResource == NULL) {
return EXIT_FAILURE;
}
LPVOID Buffer = LoadResource(NULL, MaliciousResource);
LPVOID VirtualAddress = NULL;
LPVOID EntryPointAddress = LoadLibraryInMemory(Buffer, &VirtualAddress);
if (EntryPointAddress == NULL) {
printf_s("Could not allocate or resolve the specified image binary in memory.");
return EXIT_FAILURE;
}
DLL_ENTRY_CALLBACK DllMain = (DLL_ENTRY_CALLBACK)EntryPointAddress;
(*DllMain)((HINSTANCE)VirtualAddress, DLL_PROCESS_ATTACH, 0);
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment