Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  pe.rs   Sprache: unbekannt

 
//! Helper for writing PE files.
use alloc::string::String;
use alloc::vec::Vec;
use core::mem;

use crate::endian::{LittleEndian as LE, *};
use crate::pe;
use crate::write::util;
use crate::write::{Error, Result, WritableBuffer};

/// A helper for writing PE files.
///
/// Writing uses a two phase approach. The first phase reserves file ranges and virtual
/// address ranges for everything in the order that they will be written.
///
/// The second phase writes everything out in order. Thus the caller must ensure writing
/// is in the same order that file ranges were reserved.
#[allow(missing_debug_implementations)]
pub struct Writer<'a> {
    is_64: bool,
    section_alignment: u32,
    file_alignment: u32,

    buffer: &'a mut dyn WritableBuffer,
    len: u32,
    virtual_len: u32,
    headers_len: u32,

    code_address: u32,
    data_address: u32,
    code_len: u32,
    data_len: u32,
    bss_len: u32,

    nt_headers_offset: u32,
    data_directories: Vec<DataDirectory>,
    section_header_num: u16,
    sections: Vec<Section>,

    symbol_offset: u32,
    symbol_num: u32,

    reloc_blocks: Vec<RelocBlock>,
    relocs: Vec<U16<LE>>,
    reloc_offset: u32,
}

impl<'a> Writer<'a> {
    /// Create a new `Writer`.
    ///
    /// The alignment values must be powers of two.
    pub fn new(
        is_64: bool,
        section_alignment: u32,
        file_alignment: u32,
        buffer: &'a mut dyn WritableBuffer,
    ) -> Self {
        Writer {
            is_64,
            section_alignment,
            file_alignment,

            buffer,
            len: 0,
            virtual_len: 0,
            headers_len: 0,

            code_address: 0,
            data_address: 0,
            code_len: 0,
            data_len: 0,
            bss_len: 0,

            nt_headers_offset: 0,
            data_directories: Vec::new(),
            section_header_num: 0,
            sections: Vec::new(),

            symbol_offset: 0,
            symbol_num: 0,

            reloc_blocks: Vec::new(),
            relocs: Vec::new(),
            reloc_offset: 0,
        }
    }

    /// Return the current virtual address size that has been reserved.
    ///
    /// This is only valid after section headers have been reserved.
    pub fn virtual_len(&self) -> u32 {
        self.virtual_len
    }

    /// Reserve a virtual address range with the given size.
    ///
    /// The reserved length will be increased to match the section alignment.
    ///
    /// Returns the aligned offset of the start of the range.
    pub fn reserve_virtual(&mut self, len: u32) -> u32 {
        let offset = self.virtual_len;
        self.virtual_len += len;
        self.virtual_len = util::align_u32(self.virtual_len, self.section_alignment);
        offset
    }

    /// Reserve up to the given virtual address.
    ///
    /// The reserved length will be increased to match the section alignment.
    pub fn reserve_virtual_until(&mut self, address: u32) {
        debug_assert!(self.virtual_len <= address);
        self.virtual_len = util::align_u32(address, self.section_alignment);
    }

    /// Return the current file length that has been reserved.
    pub fn reserved_len(&self) -> u32 {
        self.len
    }

    /// Return the current file length that has been written.
    #[allow(clippy::len_without_is_empty)]
    pub fn len(&self) -> usize {
        self.buffer.len()
    }

    /// Reserve a file range with the given size and starting alignment.
    ///
    /// Returns the aligned offset of the start of the range.
    pub fn reserve(&mut self, len: u32, align_start: u32) -> u32 {
        if len == 0 {
            return self.len;
        }
        self.reserve_align(align_start);
        let offset = self.len;
        self.len += len;
        offset
    }

    /// Reserve a file range with the given size and using the file alignment.
    ///
    /// Returns the aligned offset of the start of the range.
    pub fn reserve_file(&mut self, len: u32) -> u32 {
        self.reserve(len, self.file_alignment)
    }

    /// Write data.
    pub fn write(&mut self, data: &[u8]) {
        self.buffer.write_bytes(data);
    }

    /// Reserve alignment padding bytes.
    pub fn reserve_align(&mut self, align_start: u32) {
        self.len = util::align_u32(self.len, align_start);
    }

    /// Write alignment padding bytes.
    pub fn write_align(&mut self, align_start: u32) {
        util::write_align(self.buffer, align_start as usize);
    }

    /// Write padding up to the next multiple of file alignment.
    pub fn write_file_align(&mut self) {
        self.write_align(self.file_alignment);
    }

    /// Reserve the file range up to the given file offset.
    pub fn reserve_until(&mut self, offset: u32) {
        debug_assert!(self.len <= offset);
        self.len = offset;
    }

    /// Write padding up to the given file offset.
    pub fn pad_until(&mut self, offset: u32) {
        debug_assert!(self.buffer.len() <= offset as usize);
        self.buffer.resize(offset as usize);
    }

    /// Reserve the range for the DOS header.
    ///
    /// This must be at the start of the file.
    ///
    /// When writing, you may use `write_custom_dos_header` or `write_empty_dos_header`.
    pub fn reserve_dos_header(&mut self) {
        debug_assert_eq!(self.len, 0);
        self.reserve(mem::size_of::<pe::ImageDosHeader>() as u32, 1);
    }

    /// Write a custom DOS header.
    ///
    /// This must be at the start of the file.
    pub fn write_custom_dos_header(&mut self, dos_header: &pe::ImageDosHeader) -> Result<()> {
        debug_assert_eq!(self.buffer.len(), 0);

        // Start writing.
        self.buffer
            .reserve(self.len as usize)
            .map_err(|_| Error(String::from("Cannot allocate buffer")))?;

        self.buffer.write(dos_header);
        Ok(())
    }

    /// Write the DOS header for a file without a stub.
    ///
    /// This must be at the start of the file.
    ///
    /// Uses default values for all fields.
    pub fn write_empty_dos_header(&mut self) -> Result<()> {
        self.write_custom_dos_header(&pe::ImageDosHeader {
            e_magic: U16::new(LE, pe::IMAGE_DOS_SIGNATURE),
            e_cblp: U16::new(LE, 0),
            e_cp: U16::new(LE, 0),
            e_crlc: U16::new(LE, 0),
            e_cparhdr: U16::new(LE, 0),
            e_minalloc: U16::new(LE, 0),
            e_maxalloc: U16::new(LE, 0),
            e_ss: U16::new(LE, 0),
            e_sp: U16::new(LE, 0),
            e_csum: U16::new(LE, 0),
            e_ip: U16::new(LE, 0),
            e_cs: U16::new(LE, 0),
            e_lfarlc: U16::new(LE, 0),
            e_ovno: U16::new(LE, 0),
            e_res: [U16::new(LE, 0); 4],
            e_oemid: U16::new(LE, 0),
            e_oeminfo: U16::new(LE, 0),
            e_res2: [U16::new(LE, 0); 10],
            e_lfanew: U32::new(LE, self.nt_headers_offset),
        })
    }

    /// Reserve a fixed DOS header and stub.
    ///
    /// Use `reserve_dos_header` and `reserve` if you need a custom stub.
    pub fn reserve_dos_header_and_stub(&mut self) {
        self.reserve_dos_header();
        self.reserve(64, 1);
    }

    /// Write a fixed DOS header and stub.
    ///
    /// Use `write_custom_dos_header` and `write` if you need a custom stub.
    pub fn write_dos_header_and_stub(&mut self) -> Result<()> {
        self.write_custom_dos_header(&pe::ImageDosHeader {
            e_magic: U16::new(LE, pe::IMAGE_DOS_SIGNATURE),
            e_cblp: U16::new(LE, 0x90),
            e_cp: U16::new(LE, 3),
            e_crlc: U16::new(LE, 0),
            e_cparhdr: U16::new(LE, 4),
            e_minalloc: U16::new(LE, 0),
            e_maxalloc: U16::new(LE, 0xffff),
            e_ss: U16::new(LE, 0),
            e_sp: U16::new(LE, 0xb8),
            e_csum: U16::new(LE, 0),
            e_ip: U16::new(LE, 0),
            e_cs: U16::new(LE, 0),
            e_lfarlc: U16::new(LE, 0x40),
            e_ovno: U16::new(LE, 0),
            e_res: [U16::new(LE, 0); 4],
            e_oemid: U16::new(LE, 0),
            e_oeminfo: U16::new(LE, 0),
            e_res2: [U16::new(LE, 0); 10],
            e_lfanew: U32::new(LE, self.nt_headers_offset),
        })?;

        #[rustfmt::skip]
        self.buffer.write_bytes(&[
            0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd,
            0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
            0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,
            0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
            0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e,
            0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
            0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a,
            0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        ]);

        Ok(())
    }

    fn nt_headers_size(&self) -> u32 {
        if self.is_64 {
            mem::size_of::<pe::ImageNtHeaders64>() as u32
        } else {
            mem::size_of::<pe::ImageNtHeaders32>() as u32
        }
    }

    fn optional_header_size(&self) -> u32 {
        let size = if self.is_64 {
            mem::size_of::<pe::ImageOptionalHeader64>() as u32
        } else {
            mem::size_of::<pe::ImageOptionalHeader32>() as u32
        };
        size + self.data_directories.len() as u32 * mem::size_of::<pe::ImageDataDirectory>() as u32
    }

    /// Return the offset of the NT headers, if reserved.
    pub fn nt_headers_offset(&self) -> u32 {
        self.nt_headers_offset
    }

    /// Reserve the range for the NT headers.
    pub fn reserve_nt_headers(&mut self, data_directory_num: usize) {
        debug_assert_eq!(self.nt_headers_offset, 0);
        self.nt_headers_offset = self.reserve(self.nt_headers_size(), 8);
        self.data_directories = vec![DataDirectory::default(); data_directory_num];
        self.reserve(
            data_directory_num as u32 * mem::size_of::<pe::ImageDataDirectory>() as u32,
            1,
        );
    }

    /// Set the virtual address and size of a data directory.
    pub fn set_data_directory(&mut self, index: usize, virtual_address: u32, size: u32) {
        self.data_directories[index] = DataDirectory {
            virtual_address,
            size,
        }
    }

    /// Write the NT headers.
    pub fn write_nt_headers(&mut self, nt_headers: NtHeaders) {
        self.pad_until(self.nt_headers_offset);
        self.buffer.write(&U32::new(LE, pe::IMAGE_NT_SIGNATURE));
        let file_header = pe::ImageFileHeader {
            machine: U16::new(LE, nt_headers.machine),
            number_of_sections: U16::new(LE, self.section_header_num),
            time_date_stamp: U32::new(LE, nt_headers.time_date_stamp),
            pointer_to_symbol_table: U32::new(LE, self.symbol_offset),
            number_of_symbols: U32::new(LE, self.symbol_num),
            size_of_optional_header: U16::new(LE, self.optional_header_size() as u16),
            characteristics: U16::new(LE, nt_headers.characteristics),
        };
        self.buffer.write(&file_header);
        if self.is_64 {
            let optional_header = pe::ImageOptionalHeader64 {
                magic: U16::new(LE, pe::IMAGE_NT_OPTIONAL_HDR64_MAGIC),
                major_linker_version: nt_headers.major_linker_version,
                minor_linker_version: nt_headers.minor_linker_version,
                size_of_code: U32::new(LE, self.code_len),
                size_of_initialized_data: U32::new(LE, self.data_len),
                size_of_uninitialized_data: U32::new(LE, self.bss_len),
                address_of_entry_point: U32::new(LE, nt_headers.address_of_entry_point),
                base_of_code: U32::new(LE, self.code_address),
                image_base: U64::new(LE, nt_headers.image_base),
                section_alignment: U32::new(LE, self.section_alignment),
                file_alignment: U32::new(LE, self.file_alignment),
                major_operating_system_version: U16::new(
                    LE,
                    nt_headers.major_operating_system_version,
                ),
                minor_operating_system_version: U16::new(
                    LE,
                    nt_headers.minor_operating_system_version,
                ),
                major_image_version: U16::new(LE, nt_headers.major_image_version),
                minor_image_version: U16::new(LE, nt_headers.minor_image_version),
                major_subsystem_version: U16::new(LE, nt_headers.major_subsystem_version),
                minor_subsystem_version: U16::new(LE, nt_headers.minor_subsystem_version),
                win32_version_value: U32::new(LE, 0),
                size_of_image: U32::new(LE, self.virtual_len),
                size_of_headers: U32::new(LE, self.headers_len),
                check_sum: U32::new(LE, 0),
                subsystem: U16::new(LE, nt_headers.subsystem),
                dll_characteristics: U16::new(LE, nt_headers.dll_characteristics),
                size_of_stack_reserve: U64::new(LE, nt_headers.size_of_stack_reserve),
                size_of_stack_commit: U64::new(LE, nt_headers.size_of_stack_commit),
                size_of_heap_reserve: U64::new(LE, nt_headers.size_of_heap_reserve),
                size_of_heap_commit: U64::new(LE, nt_headers.size_of_heap_commit),
                loader_flags: U32::new(LE, 0),
                number_of_rva_and_sizes: U32::new(LE, self.data_directories.len() as u32),
            };
            self.buffer.write(&optional_header);
        } else {
            let optional_header = pe::ImageOptionalHeader32 {
                magic: U16::new(LE, pe::IMAGE_NT_OPTIONAL_HDR32_MAGIC),
                major_linker_version: nt_headers.major_linker_version,
                minor_linker_version: nt_headers.minor_linker_version,
                size_of_code: U32::new(LE, self.code_len),
                size_of_initialized_data: U32::new(LE, self.data_len),
                size_of_uninitialized_data: U32::new(LE, self.bss_len),
                address_of_entry_point: U32::new(LE, nt_headers.address_of_entry_point),
                base_of_code: U32::new(LE, self.code_address),
                base_of_data: U32::new(LE, self.data_address),
                image_base: U32::new(LE, nt_headers.image_base as u32),
                section_alignment: U32::new(LE, self.section_alignment),
                file_alignment: U32::new(LE, self.file_alignment),
                major_operating_system_version: U16::new(
                    LE,
                    nt_headers.major_operating_system_version,
                ),
                minor_operating_system_version: U16::new(
                    LE,
                    nt_headers.minor_operating_system_version,
                ),
                major_image_version: U16::new(LE, nt_headers.major_image_version),
                minor_image_version: U16::new(LE, nt_headers.minor_image_version),
                major_subsystem_version: U16::new(LE, nt_headers.major_subsystem_version),
                minor_subsystem_version: U16::new(LE, nt_headers.minor_subsystem_version),
                win32_version_value: U32::new(LE, 0),
                size_of_image: U32::new(LE, self.virtual_len),
                size_of_headers: U32::new(LE, self.headers_len),
                check_sum: U32::new(LE, 0),
                subsystem: U16::new(LE, nt_headers.subsystem),
                dll_characteristics: U16::new(LE, nt_headers.dll_characteristics),
                size_of_stack_reserve: U32::new(LE, nt_headers.size_of_stack_reserve as u32),
                size_of_stack_commit: U32::new(LE, nt_headers.size_of_stack_commit as u32),
                size_of_heap_reserve: U32::new(LE, nt_headers.size_of_heap_reserve as u32),
                size_of_heap_commit: U32::new(LE, nt_headers.size_of_heap_commit as u32),
                loader_flags: U32::new(LE, 0),
                number_of_rva_and_sizes: U32::new(LE, self.data_directories.len() as u32),
            };
            self.buffer.write(&optional_header);
        }

        for dir in &self.data_directories {
            self.buffer.write(&pe::ImageDataDirectory {
                virtual_address: U32::new(LE, dir.virtual_address),
                size: U32::new(LE, dir.size),
            })
        }
    }

    /// Reserve the section headers.
    ///
    /// The number of reserved section headers must be the same as the number of sections that
    /// are later reserved.
    // TODO: change this to a maximum number of sections?
    pub fn reserve_section_headers(&mut self, section_header_num: u16) {
        debug_assert_eq!(self.section_header_num, 0);
        self.section_header_num = section_header_num;
        self.reserve(
            u32::from(section_header_num) * mem::size_of::<pe::ImageSectionHeader>() as u32,
            1,
        );
        // Padding before sections must be included in headers_len.
        self.reserve_align(self.file_alignment);
        self.headers_len = self.len;
        self.reserve_virtual(self.len);
    }

    /// Write the section headers.
    ///
    /// This uses information that was recorded when the sections were reserved.
    pub fn write_section_headers(&mut self) {
        debug_assert_eq!(self.section_header_num as usize, self.sections.len());
        for section in &self.sections {
            let section_header = pe::ImageSectionHeader {
                name: section.name,
                virtual_size: U32::new(LE, section.range.virtual_size),
                virtual_address: U32::new(LE, section.range.virtual_address),
                size_of_raw_data: U32::new(LE, section.range.file_size),
                pointer_to_raw_data: U32::new(LE, section.range.file_offset),
                pointer_to_relocations: U32::new(LE, 0),
                pointer_to_linenumbers: U32::new(LE, 0),
                number_of_relocations: U16::new(LE, 0),
                number_of_linenumbers: U16::new(LE, 0),
                characteristics: U32::new(LE, section.characteristics),
            };
            self.buffer.write(§ion_header);
        }
    }

    /// Reserve a section.
    ///
    /// Returns the file range and virtual address range that are reserved
    /// for the section.
    pub fn reserve_section(
        &mut self,
        name: [u8; 8],
        characteristics: u32,
        virtual_size: u32,
        data_size: u32,
    ) -> SectionRange {
        let virtual_address = self.reserve_virtual(virtual_size);

        // Padding after section must be included in section file size.
        let file_size = util::align_u32(data_size, self.file_alignment);
        let file_offset = if file_size != 0 {
            self.reserve(file_size, self.file_alignment)
        } else {
            0
        };

        // Sizes in optional header use the virtual size with the file alignment.
        let aligned_virtual_size = util::align_u32(virtual_size, self.file_alignment);
        if characteristics & pe::IMAGE_SCN_CNT_CODE != 0 {
            if self.code_address == 0 {
                self.code_address = virtual_address;
            }
            self.code_len += aligned_virtual_size;
        } else if characteristics & pe::IMAGE_SCN_CNT_INITIALIZED_DATA != 0 {
            if self.data_address == 0 {
                self.data_address = virtual_address;
            }
            self.data_len += aligned_virtual_size;
        } else if characteristics & pe::IMAGE_SCN_CNT_UNINITIALIZED_DATA != 0 {
            if self.data_address == 0 {
                self.data_address = virtual_address;
            }
            self.bss_len += aligned_virtual_size;
        }

        let range = SectionRange {
            virtual_address,
            virtual_size,
            file_offset,
            file_size,
        };
        self.sections.push(Section {
            name,
            characteristics,
            range,
        });
        range
    }

    /// Write the data for a section.
    pub fn write_section(&mut self, offset: u32, data: &[u8]) {
        if data.is_empty() {
            return;
        }
        self.pad_until(offset);
        self.write(data);
        self.write_align(self.file_alignment);
    }

    /// Reserve a `.text` section.
    ///
    /// Contains executable code.
    pub fn reserve_text_section(&mut self, size: u32) -> SectionRange {
        self.reserve_section(
            *b".text\0\0\0",
            pe::IMAGE_SCN_CNT_CODE | pe::IMAGE_SCN_MEM_EXECUTE | pe::IMAGE_SCN_MEM_READ,
            size,
            size,
        )
    }

    /// Reserve a `.data` section.
    ///
    /// Contains initialized data.
    ///
    /// May also contain uninitialized data if `virtual_size` is greater than `data_size`.
    pub fn reserve_data_section(&mut self, virtual_size: u32, data_size: u32) -> SectionRange {
        self.reserve_section(
            *b".data\0\0\0",
            pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ | pe::IMAGE_SCN_MEM_WRITE,
            virtual_size,
            data_size,
        )
    }

    /// Reserve a `.rdata` section.
    ///
    /// Contains read-only initialized data.
    pub fn reserve_rdata_section(&mut self, size: u32) -> SectionRange {
        self.reserve_section(
            *b".rdata\0\0",
            pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ,
            size,
            size,
        )
    }

    /// Reserve a `.bss` section.
    ///
    /// Contains uninitialized data.
    pub fn reserve_bss_section(&mut self, size: u32) -> SectionRange {
        self.reserve_section(
            *b".bss\0\0\0\0",
            pe::IMAGE_SCN_CNT_UNINITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ | pe::IMAGE_SCN_MEM_WRITE,
            size,
            0,
        )
    }

    /// Reserve an `.idata` section.
    ///
    /// Contains import tables. Note that it is permissible to store import tables in a different
    /// section.
    ///
    /// This also sets the `pe::IMAGE_DIRECTORY_ENTRY_IMPORT` data directory.
    pub fn reserve_idata_section(&mut self, size: u32) -> SectionRange {
        let range = self.reserve_section(
            *b".idata\0\0",
            pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ | pe::IMAGE_SCN_MEM_WRITE,
            size,
            size,
        );
        let dir = &mut self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_IMPORT];
        debug_assert_eq!(dir.virtual_address, 0);
        *dir = DataDirectory {
            virtual_address: range.virtual_address,
            size,
        };
        range
    }

    /// Reserve an `.edata` section.
    ///
    /// Contains export tables.
    ///
    /// This also sets the `pe::IMAGE_DIRECTORY_ENTRY_EXPORT` data directory.
    pub fn reserve_edata_section(&mut self, size: u32) -> SectionRange {
        let range = self.reserve_section(
            *b".edata\0\0",
            pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ,
            size,
            size,
        );
        let dir = &mut self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_EXPORT];
        debug_assert_eq!(dir.virtual_address, 0);
        *dir = DataDirectory {
            virtual_address: range.virtual_address,
            size,
        };
        range
    }

    /// Reserve a `.pdata` section.
    ///
    /// Contains exception information.
    ///
    /// This also sets the `pe::IMAGE_DIRECTORY_ENTRY_EXCEPTION` data directory.
    pub fn reserve_pdata_section(&mut self, size: u32) -> SectionRange {
        let range = self.reserve_section(
            *b".pdata\0\0",
            pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ,
            size,
            size,
        );
        let dir = &mut self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_EXCEPTION];
        debug_assert_eq!(dir.virtual_address, 0);
        *dir = DataDirectory {
            virtual_address: range.virtual_address,
            size,
        };
        range
    }

    /// Reserve a `.xdata` section.
    ///
    /// Contains exception information.
    pub fn reserve_xdata_section(&mut self, size: u32) -> SectionRange {
        self.reserve_section(
            *b".xdata\0\0",
            pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ,
            size,
            size,
        )
    }

    /// Reserve a `.rsrc` section.
    ///
    /// Contains the resource directory.
    ///
    /// This also sets the `pe::IMAGE_DIRECTORY_ENTRY_RESOURCE` data directory.
    pub fn reserve_rsrc_section(&mut self, size: u32) -> SectionRange {
        let range = self.reserve_section(
            *b".rsrc\0\0\0",
            pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ,
            size,
            size,
        );
        let dir = &mut self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_RESOURCE];
        debug_assert_eq!(dir.virtual_address, 0);
        *dir = DataDirectory {
            virtual_address: range.virtual_address,
            size,
        };
        range
    }

    /// Add a base relocation.
    ///
    /// `typ` must be one of the `IMAGE_REL_BASED_*` constants.
    pub fn add_reloc(&mut self, mut virtual_address: u32, typ: u16) {
        let reloc = U16::new(LE, typ << 12 | (virtual_address & 0xfff) as u16);
        virtual_address &= !0xfff;
        if let Some(block) = self.reloc_blocks.last_mut() {
            if block.virtual_address == virtual_address {
                self.relocs.push(reloc);
                block.count += 1;
                return;
            }
            // Blocks must have an even number of relocations.
            if block.count & 1 != 0 {
                self.relocs.push(U16::new(LE, 0));
                block.count += 1;
            }
            debug_assert!(block.virtual_address < virtual_address);
        }
        self.relocs.push(reloc);
        self.reloc_blocks.push(RelocBlock {
            virtual_address,
            count: 1,
        });
    }

    /// Return true if a base relocation has been added.
    pub fn has_relocs(&mut self) -> bool {
        !self.relocs.is_empty()
    }

    /// Reserve a `.reloc` section.
    ///
    /// This contains the base relocations that were added with `add_reloc`.
    ///
    /// This also sets the `pe::IMAGE_DIRECTORY_ENTRY_BASERELOC` data directory.
    pub fn reserve_reloc_section(&mut self) -> SectionRange {
        if let Some(block) = self.reloc_blocks.last_mut() {
            // Blocks must have an even number of relocations.
            if block.count & 1 != 0 {
                self.relocs.push(U16::new(LE, 0));
                block.count += 1;
            }
        }
        let size = self.reloc_blocks.iter().map(RelocBlock::size).sum();
        let range = self.reserve_section(
            *b".reloc\0\0",
            pe::IMAGE_SCN_CNT_INITIALIZED_DATA
                | pe::IMAGE_SCN_MEM_READ
                | pe::IMAGE_SCN_MEM_DISCARDABLE,
            size,
            size,
        );
        let dir = &mut self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_BASERELOC];
        debug_assert_eq!(dir.virtual_address, 0);
        *dir = DataDirectory {
            virtual_address: range.virtual_address,
            size,
        };
        self.reloc_offset = range.file_offset;
        range
    }

    /// Write a `.reloc` section.
    ///
    /// This contains the base relocations that were added with `add_reloc`.
    pub fn write_reloc_section(&mut self) {
        if self.reloc_offset == 0 {
            return;
        }
        self.pad_until(self.reloc_offset);

        let mut total = 0;
        for block in &self.reloc_blocks {
            self.buffer.write(&pe::ImageBaseRelocation {
                virtual_address: U32::new(LE, block.virtual_address),
                size_of_block: U32::new(LE, block.size()),
            });
            self.buffer
                .write_slice(&self.relocs[total..][..block.count as usize]);
            total += block.count as usize;
        }
        debug_assert_eq!(total, self.relocs.len());

        self.write_align(self.file_alignment);
    }

    /// Reserve the certificate table.
    ///
    /// This also sets the `pe::IMAGE_DIRECTORY_ENTRY_SECURITY` data directory.
    // TODO: reserve individual certificates
    pub fn reserve_certificate_table(&mut self, size: u32) {
        let size = util::align_u32(size, 8);
        let offset = self.reserve(size, 8);
        let dir = &mut self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_SECURITY];
        debug_assert_eq!(dir.virtual_address, 0);
        *dir = DataDirectory {
            virtual_address: offset,
            size,
        };
    }

    /// Write the certificate table.
    // TODO: write individual certificates
    pub fn write_certificate_table(&mut self, data: &[u8]) {
        let dir = self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_SECURITY];
        self.pad_until(dir.virtual_address);
        self.write(data);
        self.pad_until(dir.virtual_address + dir.size);
    }
}

/// Information required for writing [`pe::ImageNtHeaders32`] or [`pe::ImageNtHeaders64`].
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct NtHeaders {
    // ImageFileHeader
    pub machine: u16,
    pub time_date_stamp: u32,
    pub characteristics: u16,
    // ImageOptionalHeader
    pub major_linker_version: u8,
    pub minor_linker_version: u8,
    pub address_of_entry_point: u32,
    pub image_base: u64,
    pub major_operating_system_version: u16,
    pub minor_operating_system_version: u16,
    pub major_image_version: u16,
    pub minor_image_version: u16,
    pub major_subsystem_version: u16,
    pub minor_subsystem_version: u16,
    pub subsystem: u16,
    pub dll_characteristics: u16,
    pub size_of_stack_reserve: u64,
    pub size_of_stack_commit: u64,
    pub size_of_heap_reserve: u64,
    pub size_of_heap_commit: u64,
}

#[derive(Default, Clone, Copy)]
struct DataDirectory {
    virtual_address: u32,
    size: u32,
}

/// Information required for writing [`pe::ImageSectionHeader`].
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct Section {
    pub name: [u8; pe::IMAGE_SIZEOF_SHORT_NAME],
    pub characteristics: u32,
    pub range: SectionRange,
}

/// The file range and virtual address range for a section.
#[allow(missing_docs)]
#[derive(Debug, Default, Clone, Copy)]
pub struct SectionRange {
    pub virtual_address: u32,
    pub virtual_size: u32,
    pub file_offset: u32,
    pub file_size: u32,
}

struct RelocBlock {
    virtual_address: u32,
    count: u32,
}

impl RelocBlock {
    fn size(&self) -> u32 {
        mem::size_of::<pe::ImageBaseRelocation>() as u32 + self.count * mem::size_of::<u16>() as u32
    }
}

[ Dauer der Verarbeitung: 0.4 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge