fancycode/memorymodule
repository·master·Indexed 25 days ago
https://github.com/fancycode/memorymoduleA C library and tutorial for loading Windows DLLs directly from memory buffers, bypassing the need for files on disk and the limitations of standard LoadLibrary APIs. It provides an interface mimicking standard Windows loading functions, including MemoryLoadLibrary, MemoryGetProcAddress, and MemoryFreeLibrary, while handling PE format structures, base relocation, and memory allocation via VirtualAlloc.
What's inside memorymodule
- MemoryModule is a library designed to load Windows DLLs directly from memory, bypassing the requirement for the DLL to exist as a file on the filesystem. This is useful for scenarios where you want to avoid distributing multiple files or wish to make reverse engineering (disassembling) more difficult by not leaving traces of the DLL on the disk.
Understand the PE (Portable Executable) format structure
masterWindows binaries (.exe, .dll, .sys) use the PE format. To load a DLL from memory, you must understand its structure, which is defined in
winnt.h. The format consists of:- DOS Header/Stub: For backwards compatibility.
- PE Header: Contains
IMAGE_NT_HEADERS, which includes:IMAGE_FILE_HEADER: Describes the physical format (e.g.,NumberOfSections,Characteristics).IMAGE_OPTIONAL_HEADER: Describes the logical format (e.g.,ImageBase,SizeOfImage,AddressOfEntryPoint, and theDataDirectory).
- Section Headers: A list of
IMAGE_SECTION_HEADERstructures describing the contents (code, data, etc.) and their locations. - Sections: The actual data/code blocks.
The
DataDirectorywithin theOptionalHeaderis critical for finding imports (Index 1), exports (Index 0), and the base relocation table (Index 5).Unload a library loaded with MemoryModule
masterTo properly free a custom loaded library, you must follow these steps:
- Call the DLL entry point to notify the library that it is being detached (using
DLL_PROCESS_DETACH). - Free any external libraries that were used to resolve imports.
- Free the allocated memory used by the module.
- Call the DLL entry point to notify the library that it is being detached (using
Use the MemoryModule API to load DLLs from memory
masterMemoryModule is a C library designed to load a DLL directly from a memory buffer. Its interface mimics the standard Windows library loading functions. UseMemoryLoadLibraryto load the module,MemoryGetProcAddressto retrieve function pointers, andMemoryFreeLibraryto unload it.Allocate memory for a DLL using VirtualAlloc
masterTo load a DLL from memory, you must reserve a memory block using
VirtualAlloc. The size of the block should be determined byPEHeader->OptionalHeader->SizeOfImage. It is best practice to attempt to reserve the memory at the address specified byImageBase.memory = VirtualAlloc((LPVOID)(PEHeader->OptionalHeader.ImageBase), PEHeader->OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE);If the reserved memory address differs from the
ImageBaserequested, you must perform Base relocation later.memory = VirtualAlloc((LPVOID)(PEHeader->OptionalHeader.ImageBase), PEHeader->OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE);Retrieve exported function addresses
masterTo access functions exported by a library loaded via MemoryModule, useMemoryGetProcAddress. This function allows you to find the entry point of a symbol by its name, similar to the standardGetProcAddressAPI.Reference: DLL Entry Point Signature
masterThe DLL entry point function signature used for notifying the library of attachment or detachment is:
typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);Reference: MemoryModule API types
masterThe primary handle type used by the MemoryModule API is
HMEMORYMODULE.typedef void *HMEMORYMODULE;Reference the DataDirectory indices
masterThe
DataDirectorycontains 16 entries defining the logical components of the library. Key indices for manual loading include:Index Description 0 Exported functions 1 Imported functions 2 Resources 3 Exception informations 4 Security informations 5 Base relocation table 6 Debug informations 7 Architecture specific data 8 Global pointer 9 Thread local storage 10 Load configuration 11 Bound imports 12 Import address table 13 Delay load imports 14 COM runtime descriptor To provide access to exported functions, the exports entry (0) is required. To load the DLL, the imports (1) and base relocation table (5) are necessary.
Reference the IMAGE_NT_HEADERS32 structure
masterThe
IMAGE_NT_HEADERS32structure is the core of the PE header, containing the file header and the optional header.typedef struct _IMAGE_NT_HEADERS { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER32 OptionalHeader; } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;typedef struct _IMAGE_NT_HEADERS { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER32 OptionalHeader; } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;Reference the IMAGE_OPTIONAL_HEADER32 structure
masterThe
IMAGE_OPTIONAL_HEADER32contains logical information required for loading the library, such as memory requirements and entry points.typedef struct _IMAGE_OPTIONAL_HEADER { // Standard fields. WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; // NT additional fields. DWORD ImageBase; DWORD SectionAlignment; DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; WORD Subsystem; DWORD DllCharacteristics; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; DWORD SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;typedef struct _IMAGE_OPTIONAL_HEADER { // // Standard fields. // WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; // // NT additional fields. // DWORD ImageBase; DWORD SectionAlignment; DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; WORD Subsystem; DWORD DllCharacteristics; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; DWORD SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;