internal static void MemoryFreeLibrary(MEMORYMODULE mod) { MEMORYMODULE module = mod; if (module == null) return; if (module.initialized) { // notify library about detaching from process DllEntryProc DllEntry = (DllEntryProc)Marshal.GetDelegateForFunctionPointer((IntPtr)(module.codeBase + (WIN64 ? ((IMAGE_NT_HEADERS64*)module.headers)->OptionalHeader.AddressOfEntryPoint : ((IMAGE_NT_HEADERS32*)module.headers)->OptionalHeader.AddressOfEntryPoint)), typeof(DllEntryProc)); DllEntry(module.codeBase, DLL_PROCESS_DETACH, null); } if (module.modules != null) { // free previously opened libraries int i; for (i = 0; i < module.numModules; i++) if ((void*)((IntPtr*)module.modules)[i] != null) module.freeLibrary((void*)((IntPtr*)module.modules)[i], module.userdata); free(module.modules); } if (module.codeBase != null) { // release memory of library module.free(module.codeBase, null, MEM_RELEASE, module.userdata); } if (WIN64) FreePointerList(module.blockedMemory, module.free, module.userdata); }
/// <summary> /// Calls module entry point. /// </summary> /// <param name="memory_module">Pointer to a memory module.</param> /// <param name="fdwReason"></param> /// <returns>If the function succeeds or if there is no entry point, the return value is true.</returns> private bool CallDllEntryPoint(MEMORY_MODULE *memory_module, uint fdwReason) { uint addressOfEntryPoint; if (Environment.Is64BitProcess) { WinNT.IMAGE_NT_HEADERS64 *headers = (WinNT.IMAGE_NT_HEADERS64 *)memory_module->headers; addressOfEntryPoint = headers->OptionalHeader.AddressOfEntryPoint; } else { WinNT.IMAGE_NT_HEADERS32 *headers = (WinNT.IMAGE_NT_HEADERS32 *)memory_module->headers; addressOfEntryPoint = headers->OptionalHeader.AddressOfEntryPoint; } if (addressOfEntryPoint != 0) { IntPtr dllEntry = (IntPtr)(memory_module->codeBase + addressOfEntryPoint); if (dllEntry == IntPtr.Zero) { return(false); } DllEntryProc dllEntryProc = (DllEntryProc)Marshal.GetDelegateForFunctionPointer(dllEntry, typeof(DllEntryProc)); if (dllEntryProc((IntPtr)memory_module->codeBase, fdwReason, 0)) { if (fdwReason == WinNT.DLL_PROCESS_ATTACH) { memory_module->initialized = 1; } else if (fdwReason == WinNT.DLL_PROCESS_DETACH) { memory_module->initialized = 0; } return(true); } else { return(false); } } return(true); }
public void ExecuteDllMain(Image image, DllCallType callType) { uint addressOfEntryPoint = Environment.Is64BitProcess ? image.OptionalHeader64->AddressOfEntryPoint : image.OptionalHeader32->AddressOfEntryPoint; if (addressOfEntryPoint >= image.Size - sizeof(IntPtr)) { throw new LoadFailedException("Cannot invoke this library's DllMain() function; its address is invalid."); } IntPtr callback = (IntPtr)(image.BasePtr + addressOfEntryPoint); DllEntryProc dllEntryProc = (DllEntryProc)Marshal.GetDelegateForFunctionPointer(callback, typeof(DllEntryProc)); uint succeeded = dllEntryProc((IntPtr)image.BasePtr, callType, IntPtr.Zero); if (succeeded == 0) { throw new LoadFailedException("This library's DllMain() function returned false in response to " + callType + "."); } }
public void ExecuteTlsFunctions(Image image, DllCallType callType) { IMAGE_DATA_DIRECTORY directory = Environment.Is64BitProcess ? image.OptionalHeader64->TLSTable : image.OptionalHeader32->TLSTable; if (directory.VirtualAddress == 0) { return; } if (directory.VirtualAddress > image.Size - sizeof(IntPtr)) { throw new LoadFailedException("This library's TLS table is damaged or invalid."); } IMAGE_TLS_DIRECTORY32 *tlsDirectory32 = (IMAGE_TLS_DIRECTORY32 *)(image.BasePtr + directory.VirtualAddress); IntPtr callbacks = (IntPtr)tlsDirectory32->AddressOfCallBacks; IntPtr endPtr = (IntPtr)(image.BasePtr + image.Size - sizeof(IntPtr)); if (callbacks != IntPtr.Zero) { IntPtr callback; while ((callback = *(IntPtr *)callbacks) != IntPtr.Zero) { if ((long)callback > (long)endPtr) { throw new LoadFailedException("One of this library's TLS functions is damaged or invalid."); } DllEntryProc dllEntryProc = (DllEntryProc)Marshal.GetDelegateForFunctionPointer(callback, typeof(DllEntryProc)); uint succeeded = dllEntryProc((IntPtr)image.BasePtr, DllCallType.PROCESS_ATTACH, IntPtr.Zero); if (succeeded == 0) { throw new LoadFailedException("One of this library's TLS functions returned false in response to " + callType + "."); } } } }
internal static MEMORYMODULE MemoryLoadLibraryEx(void* data, void* size, CustomAllocFunc allocMemory, CustomFreeFunc freeMemory, CustomLoadLibraryFunc loadLibrary, CustomGetProcAddressFunc getProcAddress, CustomFreeLibraryFunc freeLibrary, void* userdata) { MEMORYMODULE result = null; IMAGE_DOS_HEADER* dos_header; void* old_header; byte* code, headers; void* locationDelta; SYSTEM_INFO sysInfo; IMAGE_SECTION_HEADER* section; uint i; void* optionalSectionSize; void* lastSectionEnd = null; void* alignedImageSize; POINTER_LIST blockedMemory = null; if (!CheckSize(size, (void*)IMAGE_DOS_HEADER.UnmanagedSize)) return null; dos_header = (IMAGE_DOS_HEADER*)data; if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) return null; if (!CheckSize(size, (void*)(dos_header->e_lfanew + (WIN64 ? IMAGE_NT_HEADERS64.UnmanagedSize : IMAGE_NT_HEADERS32.UnmanagedSize)))) return null; old_header = &((byte*)data)[dos_header->e_lfanew]; if ((WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->Signature : ((IMAGE_NT_HEADERS32*)old_header)->Signature) != IMAGE_NT_SIGNATURE) return null; if ((WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->FileHeader.Machine : ((IMAGE_NT_HEADERS32*)old_header)->FileHeader.Machine) != HOST_MACHINE) return null; if (((WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->OptionalHeader.SectionAlignment : ((IMAGE_NT_HEADERS32*)old_header)->OptionalHeader.SectionAlignment) & 1) != 0) // Only support section alignments that are a multiple of 2 return null; section = IMAGE_FIRST_SECTION(old_header); optionalSectionSize = (void*)((WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->OptionalHeader.SectionAlignment : ((IMAGE_NT_HEADERS32*)old_header)->OptionalHeader.SectionAlignment)); for (i = 0; i < (WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->FileHeader.NumberOfSections : ((IMAGE_NT_HEADERS32*)old_header)->FileHeader.NumberOfSections); i++, section++) { void* endOfSection; if (section->SizeOfRawData == 0) { // Section without data in the DLL endOfSection = (void*)(section->VirtualAddress + (ulong)optionalSectionSize); } else { endOfSection = (void*)(section->VirtualAddress + (ulong)section->SizeOfRawData); } if ((ulong)endOfSection > (ulong)lastSectionEnd) lastSectionEnd = endOfSection; } GetNativeSystemInfo(&sysInfo); alignedImageSize = AlignValueUp((void*)(WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->OptionalHeader.SizeOfImage : ((IMAGE_NT_HEADERS32*)old_header)->OptionalHeader.SizeOfImage), (void*)sysInfo.dwPageSize); if (alignedImageSize != AlignValueUp(lastSectionEnd, (void*)sysInfo.dwPageSize)) return null; // reserve memory for image of library // XXX: is it correct to commit the complete memory region at once? // calling DllEntry raises an exception if we don't... code = (byte*)allocMemory((void*)(WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->OptionalHeader.ImageBase : ((IMAGE_NT_HEADERS32*)old_header)->OptionalHeader.ImageBase), alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE, userdata); if (code == null) { // try to allocate memory at arbitrary position code = (byte*)allocMemory(null, alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE, userdata); if (code == null) return null; } if (WIN64) { // Memory block may not span 4 GB boundaries. while ((ulong)code >> 32 < ((ulong)code + (ulong)alignedImageSize) >> 32) { POINTER_LIST node = new POINTER_LIST { next = blockedMemory, address = code }; blockedMemory = node; code = (byte*)allocMemory(null, alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE, userdata); if (code == null) { FreePointerList(blockedMemory, freeMemory, userdata); return null; } } } result = new MEMORYMODULE { codeBase = code, isDLL = ((WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->FileHeader.Characteristics : ((IMAGE_NT_HEADERS32*)old_header)->FileHeader.Characteristics) & IMAGE_FILE_DLL) != 0, alloc = allocMemory, free = freeMemory, loadLibrary = loadLibrary, getProcAddress = getProcAddress, freeLibrary = freeLibrary, userdata = userdata, pageSize = sysInfo.dwPageSize }; if (WIN64) result.blockedMemory = blockedMemory; if (!CheckSize(size, (void*)(WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->OptionalHeader.SizeOfHeaders : ((IMAGE_NT_HEADERS32*)old_header)->OptionalHeader.SizeOfHeaders))) goto error; // commit memory for headers headers = (byte*)allocMemory(code, (void*)(WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->OptionalHeader.SizeOfHeaders : ((IMAGE_NT_HEADERS32*)old_header)->OptionalHeader.SizeOfHeaders), MEM_COMMIT, PAGE_READWRITE, userdata); // copy PE header to code memcpy(headers, dos_header, (void*)(WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->OptionalHeader.SizeOfHeaders : ((IMAGE_NT_HEADERS32*)old_header)->OptionalHeader.SizeOfHeaders)); result.headers = &headers[dos_header->e_lfanew]; // update position if (WIN64) ((IMAGE_NT_HEADERS64*)result.headers)->OptionalHeader.ImageBase = (ulong)code; else ((IMAGE_NT_HEADERS32*)result.headers)->OptionalHeader.ImageBase = (uint)code; // copy sections from DLL file block to new memory location if (!CopySections((byte*)data, size, old_header, result)) goto error; // adjust base address of imported data locationDelta = (void*)((WIN64 ? ((IMAGE_NT_HEADERS64*)result.headers)->OptionalHeader.ImageBase : ((IMAGE_NT_HEADERS32*)result.headers)->OptionalHeader.ImageBase) - (WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->OptionalHeader.ImageBase : ((IMAGE_NT_HEADERS32*)old_header)->OptionalHeader.ImageBase)); if ((ulong)locationDelta != 0) result.isRelocated = PerformBaseRelocation(result, locationDelta); else result.isRelocated = true; // load required dlls and adjust function table of imports if (!BuildImportTable(result)) goto error; // mark memory pages depending on section headers and release // sections that are marked as "discardable" if (!FinalizeSections(result)) goto error; // TLS callbacks are executed BEFORE the main loading if (!ExecuteTLS(result)) goto error; // get entry point of loaded library if ((WIN64 ? ((IMAGE_NT_HEADERS64*)result.headers)->OptionalHeader.AddressOfEntryPoint : ((IMAGE_NT_HEADERS32*)result.headers)->OptionalHeader.AddressOfEntryPoint) != 0) { if (result.isDLL) { DllEntryProc DllEntry = (DllEntryProc)Marshal.GetDelegateForFunctionPointer((IntPtr)(code + (WIN64 ? ((IMAGE_NT_HEADERS64*)result.headers)->OptionalHeader.AddressOfEntryPoint : ((IMAGE_NT_HEADERS32*)result.headers)->OptionalHeader.AddressOfEntryPoint)), typeof(DllEntryProc)); // notify library about attaching to process bool successfull = DllEntry(code, DLL_PROCESS_ATTACH, null); if (!successfull) goto error; result.initialized = true; } else result.exeEntry = (ExeEntryProc)Marshal.GetDelegateForFunctionPointer((IntPtr)(code + (WIN64 ? ((IMAGE_NT_HEADERS64*)result.headers)->OptionalHeader.AddressOfEntryPoint : ((IMAGE_NT_HEADERS32*)result.headers)->OptionalHeader.AddressOfEntryPoint)), typeof(ExeEntryProc)); } else result.exeEntry = null; return result; error: // cleanup MemoryFreeLibrary(result); return null; }