/// <summary>
        /// Copies sections from a native module file block to the new memory location.
        /// </summary>
        /// <param name="ptr_data">Pointer to a native module byte array.</param>
        /// <param name="ptr_old_headers">Pointer to a source native module headers.</param>
        /// <param name="memory_module">Pointer to a memory module.</param>
        private void CopySections(byte *ptr_data, byte *ptr_old_headers, MEMORY_MODULE *memory_module)
        {
            byte *codeBase = memory_module->codeBase;

            WinNT.IMAGE_SECTION_HEADER *section = WinNT.IMAGE_FIRST_SECTION(memory_module->headers);

            ushort numberOfSections;
            uint   sectionAlignment;

            if (Environment.Is64BitProcess)
            {
                WinNT.IMAGE_NT_HEADERS64 *new_headers = (WinNT.IMAGE_NT_HEADERS64 *)memory_module->headers;
                numberOfSections = new_headers->FileHeader.NumberOfSections;

                WinNT.IMAGE_NT_HEADERS64 *old_headers = (WinNT.IMAGE_NT_HEADERS64 *)ptr_old_headers;
                sectionAlignment = old_headers->OptionalHeader.SectionAlignment;
            }
            else
            {
                WinNT.IMAGE_NT_HEADERS32 *new_headers = (WinNT.IMAGE_NT_HEADERS32 *)memory_module->headers;
                numberOfSections = new_headers->FileHeader.NumberOfSections;

                WinNT.IMAGE_NT_HEADERS32 *old_headers = (WinNT.IMAGE_NT_HEADERS32 *)ptr_old_headers;
                sectionAlignment = old_headers->OptionalHeader.SectionAlignment;
            }

            uint  index;
            byte *dest;

            for (index = 0; index < numberOfSections; index++, section++)
            {
                if (section->SizeOfRawData == 0)
                {
                    if (sectionAlignment > 0)
                    {
                        dest = (byte *)WinBase.VirtualAlloc((IntPtr)(codeBase + section->VirtualAddress), sectionAlignment, WinNT.MEM_COMMIT, WinNT.PAGE_READWRITE);
                        section->PhysicalAddress = (uint)dest;
                        memory.memset(dest, 0, sectionAlignment);
                    }

                    continue;
                }

                // commit memory block and copy data from dll
                dest = (byte *)WinBase.VirtualAlloc((IntPtr)(codeBase + section->VirtualAddress), section->SizeOfRawData, WinNT.MEM_COMMIT, WinNT.PAGE_READWRITE);
                memory.memcpy(dest, ptr_data + section->PointerToRawData, section->SizeOfRawData);

                section->PhysicalAddress = (uint)dest;
            }
        }
        /// <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);
                }
            }
        }