private void FinalizeSections() { IMAGE_SECTION_HEADER *section = Win.IMAGE_FIRST_SECTION(_headers); #if WIN64 UIntPtrT imageOffset = ((UIntPtrT)_headers->OptionalHeader.ImageBase & 0xffffffff00000000); #elif WIN32 UIntPtrT imageOffset = 0; #endif SectionFinalizeData sectionData = new SectionFinalizeData(); sectionData.Address = (void *)(section->PhysicalAddress | imageOffset); sectionData.AlignedAddress = AlignAddressDown(sectionData.Address, _pageSize); sectionData.Size = GetRealSectionSize(section); sectionData.Characteristics = section->Characteristics; sectionData.Last = false; section++; // loop through all sections and change access flags for (int i = 1; i < _headers->FileHeader.NumberOfSections; i++, section++) { void *sectionAddress = (void *)(section->PhysicalAddress | imageOffset); void *alignedAddress = AlignAddressDown(sectionAddress, _pageSize); SizeT sectionSize = GetRealSectionSize(section); // Combine access flags of all sections that share a page // TODO(fancycode): We currently share flags of a trailing large section // with the page of a first small section. This should be optimized. if (sectionData.AlignedAddress == alignedAddress || (UIntPtrT)sectionData.Address + sectionData.Size > (UIntPtrT)alignedAddress) { // Section shares page with previous if ((section->Characteristics & Win.IMAGE_SCN_MEM_DISCARDABLE) == 0 || (sectionData.Characteristics & Win.IMAGE_SCN_MEM_DISCARDABLE) == 0) { sectionData.Characteristics = (sectionData.Characteristics | section->Characteristics) & ~Win.IMAGE_SCN_MEM_DISCARDABLE; } else { sectionData.Characteristics |= section->Characteristics; } sectionData.Size = (((UIntPtrT)sectionAddress) + (sectionSize)) - (UIntPtrT)sectionData.Address; continue; } FinalizeSection(sectionData); sectionData.Address = sectionAddress; sectionData.AlignedAddress = alignedAddress; sectionData.Size = sectionSize; sectionData.Characteristics = section->Characteristics; } sectionData.Last = true; FinalizeSection(sectionData); }
static void FinalizeSections(ref IMAGE_NT_HEADERS OrgNTHeaders, IntPtr pCode, IntPtr pNTHeaders, uint PageSize) { UIntPtr imageOffset = (Is64BitProcess ? (UIntPtr)(unchecked ((ulong)pCode.ToInt64()) & 0xffffffff00000000) : UIntPtr.Zero); IntPtr pSection = Win.IMAGE_FIRST_SECTION(pNTHeaders, OrgNTHeaders.FileHeader.SizeOfOptionalHeader); IMAGE_SECTION_HEADER Section = PtrRead <IMAGE_SECTION_HEADER>(pSection); SectionFinalizeData sectionData = new SectionFinalizeData(); sectionData.Address = PtrBitOr(PtrAdd((IntPtr)0, Section.PhysicalAddress), imageOffset); sectionData.AlignedAddress = PtrAlignDown(sectionData.Address, (UIntPtr)PageSize); sectionData.Size = GetRealSectionSize(ref Section, ref OrgNTHeaders); sectionData.Characteristics = Section.Characteristics; sectionData.Last = false; pSection = PtrAdd(pSection, Sz.IMAGE_SECTION_HEADER); // loop through all sections and change access flags for (int i = 1; i < OrgNTHeaders.FileHeader.NumberOfSections; i++, pSection = PtrAdd(pSection, Sz.IMAGE_SECTION_HEADER)) { Section = PtrRead <IMAGE_SECTION_HEADER>(pSection); IntPtr sectionAddress = PtrBitOr(PtrAdd((IntPtr)0, Section.PhysicalAddress), imageOffset); IntPtr alignedAddress = PtrAlignDown(sectionAddress, (UIntPtr)PageSize); IntPtr sectionSize = GetRealSectionSize(ref Section, ref OrgNTHeaders); // Combine access flags of all sections that share a page // TODO(fancycode): We currently share flags of a trailing large section with the page of a first small section. This should be optimized. IntPtr a = PtrAdd(sectionData.Address, sectionData.Size); ulong b = unchecked ((ulong)a.ToInt64()), c = unchecked ((ulong)alignedAddress); if (sectionData.AlignedAddress == alignedAddress || unchecked ((ulong)PtrAdd(sectionData.Address, sectionData.Size).ToInt64()) > unchecked ((ulong)alignedAddress)) { // Section shares page with previous if ((Section.Characteristics & Win.IMAGE_SCN_MEM_DISCARDABLE) == 0 || (sectionData.Characteristics & Win.IMAGE_SCN_MEM_DISCARDABLE) == 0) { sectionData.Characteristics = (sectionData.Characteristics | Section.Characteristics) & ~Win.IMAGE_SCN_MEM_DISCARDABLE; } else { sectionData.Characteristics |= Section.Characteristics; } sectionData.Size = PtrSub(PtrAdd(sectionAddress, sectionSize), sectionData.Address); continue; } FinalizeSection(sectionData, PageSize, OrgNTHeaders.OptionalHeader.SectionAlignment); sectionData.Address = sectionAddress; sectionData.AlignedAddress = alignedAddress; sectionData.Size = sectionSize; sectionData.Characteristics = Section.Characteristics; } sectionData.Last = true; FinalizeSection(sectionData, PageSize, OrgNTHeaders.OptionalHeader.SectionAlignment); }
private void FinalizeSection(SectionFinalizeData sectionData) { uint protect, oldProtect; int executable; int readable; int writeable; if (sectionData.Size == 0) { return; } if ((sectionData.Characteristics & Win.IMAGE_SCN_MEM_DISCARDABLE) > 0) { // section is not needed any more and can safely be freed if (sectionData.Address == sectionData.AlignedAddress && (sectionData.Last || _headers->OptionalHeader.SectionAlignment == _pageSize || (sectionData.Size % _pageSize) == 0) ) { // Only allowed to decommit whole pages Win.VirtualFree(sectionData.Address, sectionData.Size, AllocationType.DECOMMIT); } return; } // determine protection flags based on characteristics executable = (sectionData.Characteristics & (uint)ImageSectionFlags.IMAGE_SCN_MEM_EXECUTE) != 0 ? 1 : 0; readable = (sectionData.Characteristics & (uint)ImageSectionFlags.IMAGE_SCN_MEM_READ) != 0 ? 1 : 0; writeable = (sectionData.Characteristics & (uint)ImageSectionFlags.IMAGE_SCN_MEM_WRITE) != 0 ? 1 : 0; protect = (uint)ProtectionFlags[executable, readable, writeable]; if ((sectionData.Characteristics & Win.IMAGE_SCN_MEM_NOT_CACHED) > 0) { protect |= Win.PAGE_NOCACHE; } // change memory access flags if (!Win.VirtualProtect(sectionData.Address, sectionData.Size, protect, out oldProtect)) { throw new NativeDllLoadException("Error protecting memory page"); } }
static void FinalizeSection(SectionFinalizeData SectionData, uint PageSize, uint SectionAlignment) { if (SectionData.Size == IntPtr.Zero) { return; } if ((SectionData.Characteristics & Win.IMAGE_SCN_MEM_DISCARDABLE) > 0) { // section is not needed any more and can safely be freed if (SectionData.Address == SectionData.AlignedAddress && (SectionData.Last || SectionAlignment == PageSize || (unchecked ((ulong)SectionData.Size.ToInt64()) % PageSize) == 0) ) { // Only allowed to decommit whole pages Win.VirtualFree(SectionData.Address, SectionData.Size, AllocationType.DECOMMIT); } return; } // determine protection flags based on characteristics int readable = (SectionData.Characteristics & (uint)ImageSectionFlags.IMAGE_SCN_MEM_READ) != 0 ? 1 : 0; int writeable = (SectionData.Characteristics & (uint)ImageSectionFlags.IMAGE_SCN_MEM_WRITE) != 0 ? 1 : 0; int executable = (SectionData.Characteristics & (uint)ImageSectionFlags.IMAGE_SCN_MEM_EXECUTE) != 0 ? 1 : 0; uint protect = (uint)ProtectionFlags[executable, readable, writeable]; if ((SectionData.Characteristics & Win.IMAGE_SCN_MEM_NOT_CACHED) > 0) { protect |= Win.PAGE_NOCACHE; } // change memory access flags uint oldProtect; if (!Win.VirtualProtect(SectionData.Address, SectionData.Size, protect, out oldProtect)) { throw new DllException("Error protecting memory page"); } }