Last active
October 17, 2024 14:01
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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