/// <summary> /// Get section object from name /// </summary> /// <param name="name">section name</param> /// <returns>the result section object, return null if not found</returns> public SectionEntry getSection(string name) { SectionEntry result = null; this.sectionEntries.ForEach(s => { if (s.header.name.ToString() == name) { result = s; } }); return(result); }
/// <summary> /// Get section object from ordinal /// </summary> /// <param name="ordinal">section ordinal</param> /// <returns>the result section object, return null if not found</returns> public SectionEntry getSection(int ordinal) { SectionEntry result = null; this.sectionEntries.ForEach(s => { if (s.sectionId == ordinal) { result = s; } }); return(result); }
/* * // I keep it for later * // TODO : clean the code * private int calcVirtualAddressDynamic(SectionTypes type) * { * List<SectionEntry> selectedSections = type == SectionTypes.CODE_SECTION ? getCodeSections() : getDataSections(); * * SectionEntry lastSection = selectedSections[selectedSections.Count - 1]; * * return lastSection.header.virtualAddress.getValue() + calcVirtualAddressPadding(type); * } */ /// <summary> /// Set the entrypoint in the executable /// </summary> /// <param name="codeSection"></param> /// <param name="entrypointOffsetInSection"></param> public void setEntrypoint(SectionEntry codeSection, int entrypointOffsetInSection) { if (codeSection.type != SectionTypes.CODE_SECTION) { throw new Exception("Trying to set the entrypoint on a section that is not a code section"); } int entrypointVirtual = codeSection.header.virtualAddress.getValue() + entrypointOffsetInSection; // set the entrypoint this.header.optionalHeader.AddressOfEntryPoint.setValue(entrypointVirtual); }
/// <summary> /// Get a section from a file offset /// </summary> /// <param name="address">The file address</param> /// <returns>The section that contain this address, return null if not found</returns> public SectionEntry getSectionFromFileAddress(int address) { SectionEntry section = null; this.sectionEntries.ForEach(s => { if (address >= s.header.pointerToRawData.getValue() && address < (s.header.pointerToRawData.getValue() + s.header.sizeOfRawData.getValue())) { section = s; } }); return(section); }
/// <summary> /// Get a section from a vitual address that is in the mapped virtual memory /// </summary> /// <param name="address">The virtual address</param> /// <returns>The section that contain this address, return null if not found</returns> public SectionEntry getSectionFromVirtualAddress(int address) { SectionEntry section = null; this.sectionEntries.ForEach(s => { if (address >= s.header.virtualAddress.getValue() && address < (s.header.virtualAddress.getValue() + s.header.virtualSize.getValue())) { section = s; } }); return(section); }
/// <summary> /// Export all the data of the section block /// </summary> /// <returns>Array of byte that represent the sections</returns> public List <byte> exportSectionsData() { if (this.header.peHeader.NumberOfSection.getValue() < 1) { throw new Exception("Trying to export sections without sections"); } List <byte> section = new List <byte>(); int sectionHeaderSize = exportHeaders().Count; // 16 bytes before sections Utils.addArrayToList <byte>(section, new byte[16]); int sectionStartAddress = this.header.sectionHeaderBaseAddress + section.Count + sectionHeaderSize; SectionEntry lastSection = this.getLastEntry(); int sectionBufferEndAddress = (int)lastSection.header.pointerToRawData.getValue() + (int)lastSection.header.sizeOfRawData.getValue(); int sectionBufferSize = sectionBufferEndAddress - sectionStartAddress; // a buffer to write all sections intro it byte[] sectionBuffers = new byte[sectionBufferSize]; // sections foreach (SectionEntry item in sectionEntries) { byte[] sectionBuffer = item.getSectionBuffer(); // the raw address already respect the file alignment int rawAddress = item.header.pointerToRawData.getValue() - sectionStartAddress; // write section in the right address for (int i = 0; i < sectionBuffer.Length; i++) { sectionBuffers[rawAddress + i] = sectionBuffer[i]; } } // add the sections buffer Utils.addArrayToList <byte>(section, sectionBuffers); return(section); }
// TODO private void removeSection(SectionEntry section) { this.sectionEntries.Remove(section); // this.header.peHeader.NumberOfSection - 1 }
/// <summary> /// Add a new section to executable /// NOTE : if is the first section the user has to handle the virtualAddress /// </summary> /// <param name="name"></param> /// <param name="data"></param> /// <param name="type"></param> /// <returns></returns> public SectionEntry addSection(string name, byte[] data, SectionTypes type) { // setup the virtual address of the section int virtualAddressBase = this.header.optionalHeader.BaseOfCode.getValue(); // BaseOfData doesn't exist in x64 if (this.header.is32Bit) { virtualAddressBase = type == SectionTypes.CODE_SECTION ? this.header.optionalHeader.BaseOfCode.getValue() : this.header.optionalHeader.BaseOfData.getValue(); } // create the section SectionEntry section = new SectionEntry(this.entries, this.header); // set the name section.header.setName(name); bool isFirstSection = this.header.peHeader.NumberOfSection.getValue() < 1; // there is already a section if (!isFirstSection) { SectionEntry lastSection = this.getLastEntry(); int newSectionAddress = lastSection.header.pointerToRawData.getValue() + lastSection.header.sizeOfRawData.getValue(); // set the new section address section.header.pointerToRawData.setValue(newSectionAddress); } // the PE is empty else { // 16 bytes of padding before section's data int newSectionAddress = this.sectionHeaderBaseAddress + section.header.export().Count + 16; // set the new section address section.header.pointerToRawData.setValue(newSectionAddress); } // set the section size section.header.sizeOfRawData.setValue(data.Length); // zero if there is no relocation section.header.pointerToRelocations.setValue(0); section.header.numberOfRelocations.setValue(0); section.header.numberOfLinenumbers.setValue(0); // set the virtual address if (!isFirstSection) { SectionEntry lastSection = this.getLastEntry(); int virtualAddress = calcVirtualAddress(lastSection.header.virtualAddress.getValue(), lastSection.header.virtualSize.getValue(), this.header.optionalHeader.SectionAlignment.getValue()); section.header.virtualAddress.setValue(virtualAddress); } else { // set the virtualAddressBase to BaseOfCode or BaseOfData by default section.header.virtualAddress.setValue(virtualAddressBase); } // set the section virtual size as the same as raw size // not optimized but I can't find an accurate size without analysing the data section.header.virtualSize.setValue(data.Length); // set characteristics // TODO : fix uint // the section should be read by default section.header.characteristics += (int)SectionFlags.IMAGE_SCN_MEM_READ; // flag related to code sections if (type == SectionTypes.CODE_SECTION) { section.header.characteristics += (int)SectionFlags.IMAGE_SCN_CNT_CODE; section.header.characteristics += (int)SectionFlags.IMAGE_SCN_MEM_EXECUTE; } // flag related to "data" sections (not specificly ".data" sections) else { section.header.characteristics += (int)SectionFlags.IMAGE_SCN_CNT_INITIALIZED_DATA; } // set the type // TODO : fix order characteristics check (see how it handle .data dir) section.type = type; // set the data of the section section.rawData = data; // adding the section to the list this.sectionEntries.Add(section); // increase number of section this.header.peHeader.NumberOfSection += 1; // header fixing part updateHeader(type); // return the section object return(section); }
/// <summary> /// Checks if a memory offset is in the section /// NOTE : useless if ASLR /// </summary> /// <param name="offset"></param> /// <param name="section"></param> /// <returns></returns> public bool isVirtualAddressInSection(int offset, SectionEntry section) { return(offset >= section.header.virtualAddress.getValue() && offset <= (section.header.virtualAddress.getValue() + section.header.virtualSize.getValue())); }
/// <summary> /// Checks if a file offset is in the section /// </summary> /// <param name="offset"></param> /// <param name="section"></param> /// <returns></returns> public bool isFileOffsetInSection(int offset, SectionEntry section) { return(offset >= section.header.pointerToRawData.getValue() && offset <= (section.header.pointerToRawData.getValue() + section.header.sizeOfRawData.getValue())); }