private static bool FinalizeSection(MEMORYMODULE module, SECTIONFINALIZEDATA sectionData) { uint protect, oldProtect; bool executable; bool readable; bool writeable; if (sectionData.size == null) return true; if ((sectionData.characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0) { // section is not needed any more and can safely be freed if (sectionData.address == sectionData.alignedAddress && (sectionData.last || (WIN64 ? ((IMAGE_NT_HEADERS64*)module.headers)->OptionalHeader.SectionAlignment : ((IMAGE_NT_HEADERS32*)module.headers)->OptionalHeader.SectionAlignment) == module.pageSize || ((ulong)sectionData.size % module.pageSize) == 0)) // Only allowed to decommit whole pages module.free(sectionData.address, sectionData.size, MEM_DECOMMIT, module.userdata); return true; } // determine protection flags based on characteristics executable = (sectionData.characteristics & IMAGE_SCN_MEM_EXECUTE) != 0; readable = (sectionData.characteristics & IMAGE_SCN_MEM_READ) != 0; writeable = (sectionData.characteristics & IMAGE_SCN_MEM_WRITE) != 0; protect = ProtectionFlags[executable ? 1 : 0, readable ? 1 : 0, writeable ? 1 : 0]; if ((sectionData.characteristics & IMAGE_SCN_MEM_NOT_CACHED) != 0) protect |= PAGE_NOCACHE; // change memory access flags if (!VirtualProtect(sectionData.address, sectionData.size, protect, &oldProtect)) return false; return true; }
private static bool FinalizeSections(MEMORYMODULE module) { int i; void *imageOffset; IMAGE_SECTION_HEADER *section = IMAGE_FIRST_SECTION(module.headers); // "PhysicalAddress" might have been truncated to 32bit above, expand to // 64bits again. imageOffset = WIN64 ? (void *)(((IMAGE_NT_HEADERS64 *)module.headers)->OptionalHeader.ImageBase & 0xffffffff00000000) : null; SECTIONFINALIZEDATA sectionData = new SECTIONFINALIZEDATA { address = (void *)(section->PhysicalAddress | (ulong)imageOffset), size = GetRealSectionSize(module, section), characteristics = section->Characteristics, last = false }; sectionData.alignedAddress = AlignAddressDown(sectionData.address, (void *)module.pageSize); section++; // loop through all sections and change access flags for (i = 1; i < (WIN64 ? ((IMAGE_NT_HEADERS64 *)module.headers)->FileHeader.NumberOfSections : ((IMAGE_NT_HEADERS32 *)module.headers)->FileHeader.NumberOfSections); i++, section++) { void *sectionAddress = (void *)(section->PhysicalAddress | (ulong)imageOffset); void *alignedAddress = AlignAddressDown(sectionAddress, (void *)module.pageSize); void *sectionSize = GetRealSectionSize(module, 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 || (ulong)sectionData.address + (ulong)sectionData.size > (ulong)alignedAddress) { // Section shares page with previous if ((section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0 || (sectionData.characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) { sectionData.characteristics = (sectionData.characteristics | section->Characteristics) & ~IMAGE_SCN_MEM_DISCARDABLE; } else { sectionData.characteristics |= section->Characteristics; } sectionData.size = (void *)((ulong)sectionAddress + (ulong)sectionSize - (ulong)sectionData.address); continue; } if (!FinalizeSection(module, sectionData)) { return(false); } sectionData.address = sectionAddress; sectionData.alignedAddress = alignedAddress; sectionData.size = sectionSize; sectionData.characteristics = section->Characteristics; } sectionData.last = true; if (!FinalizeSection(module, sectionData)) { return(false); } return(true); }