/// <summary> /// Deattach from the process and do a cleanup. /// </summary> /// <param name="hModule">Pointer to a memory module.</param> private void MemoryFreeLibrary(IntPtr hModule) { if (hModule == IntPtr.Zero) { return; } MEMORY_MODULE *memory_module = (MEMORY_MODULE *)hModule; if (memory_module != null) { if (memory_module->initialized != 0) { this.CallDllEntryPoint(memory_module, WinNT.DLL_PROCESS_DETACH); } if (memory_module->modules != null) { // free previously opened libraries for (int index = 0; index < memory_module->numModules; index++) { if (memory_module->modules[index] != IntPtr.Zero) { WinBase.FreeLibrary(memory_module->modules[index]); } } Marshal.FreeHGlobal((IntPtr)memory_module->modules); } if ((IntPtr)memory_module->codeBase != IntPtr.Zero) { // release memory of library WinBase.VirtualFree((IntPtr)memory_module->codeBase, 0, WinNT.MEM_RELEASE); } Marshal.FreeHGlobal((IntPtr)memory_module); } }
/// <summary> /// Marks memory pages depending on section headers and release sections that are marked as "discardable". /// </summary> /// <param name="memory_module">Pointer to a memory module.</param> private void FinalizeSections(MEMORY_MODULE *memory_module) { WinNT.IMAGE_SECTION_HEADER *section = WinNT.IMAGE_FIRST_SECTION(memory_module->headers);; ushort number_of_sections; uint size_of_initialized_data; uint size_of_uninitialized_data; long image_offset = 0; if (Environment.Is64BitProcess) { WinNT.IMAGE_NT_HEADERS64 *headers = (WinNT.IMAGE_NT_HEADERS64 *)memory_module->headers; number_of_sections = headers->FileHeader.NumberOfSections; size_of_initialized_data = headers->OptionalHeader.SizeOfInitializedData; size_of_uninitialized_data = headers->OptionalHeader.SizeOfUninitializedData; image_offset = (long)((ulong)headers->OptionalHeader.ImageBase & 0xffffffff00000000); } else { WinNT.IMAGE_NT_HEADERS32 *headers = (WinNT.IMAGE_NT_HEADERS32 *)memory_module->headers; number_of_sections = headers->FileHeader.NumberOfSections; size_of_initialized_data = headers->OptionalHeader.SizeOfInitializedData; size_of_uninitialized_data = headers->OptionalHeader.SizeOfUninitializedData; } for (int i = 0; i < number_of_sections; i++, section++) { uint protect, oldProtect, rawDataSize; uint executable = Convert.ToUInt32((section->Characteristics & WinNT.IMAGE_SCN_MEM_EXECUTE) != 0); uint readable = Convert.ToUInt32((section->Characteristics & WinNT.IMAGE_SCN_MEM_READ) != 0); uint writeable = Convert.ToUInt32((section->Characteristics & WinNT.IMAGE_SCN_MEM_WRITE) != 0); if ((section->Characteristics & WinNT.IMAGE_SCN_MEM_DISCARDABLE) != 0) { // section is not needed any more and can safely be freed WinBase.VirtualFree((IntPtr)(void *)((long)section->PhysicalAddress | (long)image_offset), section->SizeOfRawData, WinNT.MEM_DECOMMIT); continue; } protect = _protectionFlags[executable, readable, writeable]; if ((section->Characteristics & WinNT.IMAGE_SCN_MEM_NOT_CACHED) != 0) { protect |= WinNT.PAGE_NOCACHE; } // determine size of region rawDataSize = section->SizeOfRawData; if (rawDataSize == 0) { if ((section->Characteristics & WinNT.IMAGE_SCN_CNT_INITIALIZED_DATA) != 0) { rawDataSize = size_of_initialized_data; } else if ((section->Characteristics & WinNT.IMAGE_SCN_CNT_UNINITIALIZED_DATA) != 0) { rawDataSize = size_of_uninitialized_data; } } if (rawDataSize > 0) { // change memory access flags WinBase.VirtualProtect((IntPtr)(void *)((long)section->PhysicalAddress | (long)image_offset), rawDataSize, protect, &oldProtect); } } }