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


Quelle  coff.rs   Sprache: unbekannt

 
//! Just as much COFF object file support as is needed to write a resource data segment
//! for GNU Windows targets. Inspired by the `write::Object` code from the `object` crate.
//!
//! Integers are converted from u64 to u32 and added without checking because the manifest
//! data cannot get anywhere close to overflowing unless the supplied application name or
//! number of dependencies was extremely long. If this code was used more generally or if
//! the input was less trustworthy then more checked conversions and checked arithmetic
//! would be needed.

use std::io::{self, Seek, SeekFrom, Write};
use std::time::SystemTime;

#[derive(Debug, Clone, Copy)]
pub enum MachineType {
    I386,
    X86_64,
    Aarch64,
}

impl MachineType {
    pub fn machine(&self) -> u16 {
        match self {
            Self::I386 => 0x014c,
            Self::X86_64 => 0x8664,
            Self::Aarch64 => 0xaa64,
        }
    }

    pub fn relocation_type(&self) -> u16 {
        match self {
            Self::I386 => 7,
            Self::X86_64 => 3,
            Self::Aarch64 => 2,
        }
    }
}

pub struct CoffWriter<W> {
    /// wrapped writer or buffer
    writer: W,
    /// machine type for file header
    machine_type: MachineType,
    // size in bytes of resource section data
    size_of_raw_data: u32,
    // number of relocations at the end of the section
    number_of_relocations: u16,
}

impl<W: Write + Seek> CoffWriter<W> {
    /// Create a new instance wrapping a writer.
    pub fn new(mut writer: W, machine_type: MachineType) -> io::Result<Self> {
        // Add space for file header and section table.
        writer.write_all(&[0; 60])?;
        Ok(Self {
            writer,
            machine_type,
            size_of_raw_data: 0,
            number_of_relocations: 0,
        })
    }

    /// Add data to a section and return its offset within the section.
    pub fn add_data(&mut self, data: &[u8]) -> io::Result<u32> {
        let start = self.size_of_raw_data;
        self.writer.write_all(data)?;
        self.size_of_raw_data = start + data.len() as u32;
        Ok(start)
    }

    // Pad the resource data to a multiple of `n` bytes.
    pub fn align_to(&mut self, n: u32) -> io::Result<()> {
        let offset = self.size_of_raw_data % n;
        if offset != 0 {
            let padding = n - offset;
            for _ in 0..padding {
                self.writer.write_all(&[0])?;
            }
            self.size_of_raw_data += padding;
        }
        Ok(())
    }

    /// Write a relocation for a symbol at the end of the section.
    pub fn add_relocation(&mut self, address: u32) -> io::Result<()> {
        self.number_of_relocations += 1;
        self.writer.write_all(&address.to_le_bytes())?;
        self.writer.write_all(&[0, 0, 0, 0])?;
        self.writer.write_all(&self.machine_type.relocation_type().to_le_bytes())
    }

    /// Write the object and section headers and write the symbol table.
    pub fn finish(mut self) -> io::Result<W> {
        // Get the timestamp for the header. `as` is correct here, as the low 32 bits
        // should be used.
        let timestamp = SystemTime::now()
            .duration_since(SystemTime::UNIX_EPOCH)
            .map_or(0, |d| d.as_secs() as u32);

        // Copy file location of the symbol table.
        let pointer_to_symbol_table = self.writer.stream_position()? as u32;

        // Write the symbols and auxiliary data for the section.
        self.writer.write_all(b".rsrc\0\0\0")?; // name
        self.writer.write_all(&[0, 0, 0, 0])?; // address
        self.writer.write_all(&[1, 0])?; // section number (1-based)
        self.writer.write_all(&[0, 0, 3, 1])?; // type = 0, class = static, aux symbols = 1
        self.writer.write_all(&self.size_of_raw_data.to_le_bytes())?;
        self.writer.write_all(&self.number_of_relocations.to_le_bytes())?;
        self.writer.write_all(&[0; 12])?;

        // Write the empty string table.
        self.writer.write_all(&[0; 4])?;

        // Write the object header.
        let end_of_file = self.writer.seek(SeekFrom::Start(0))?;
        self.writer.write_all(&self.machine_type.machine().to_le_bytes())?;
        self.writer.write_all(&[1, 0])?; // number of sections
        self.writer.write_all(×tamp.to_le_bytes())?;
        self.writer.write_all(&pointer_to_symbol_table.to_le_bytes())?;
        self.writer.write_all(&[2, 0, 0, 0])?; // number of symbol table entries
        self.writer.write_all(&[0; 4])?; // optional header size = 0, characteristics = 0

        // Write the section header.
        self.writer.write_all(b".rsrc\0\0\0")?;
        self.writer.write_all(&[0; 8])?; // virtual size = 0 and virtual address = 0
        self.writer.write_all(&self.size_of_raw_data.to_le_bytes())?;
        self.writer.write_all(&[60, 0, 0, 0])?; // pointer to raw data
        self.writer.write_all(&(self.size_of_raw_data + 60).to_le_bytes())?; // pointer to relocations
        self.writer.write_all(&[0; 4])?; // pointer to line numbers
        self.writer.write_all(&self.number_of_relocations.to_le_bytes())?;
        self.writer.write_all(&[0; 2])?; // number of line numbers
        self.writer.write_all(&[0x40, 0, 0x30, 0xc0])?; // characteristics

        // Return the inner writer and dispose of this object.
        self.writer.seek(SeekFrom::Start(end_of_file))?;
        Ok(self.writer)
    }
}

/// Returns the bytes for a resource directory table.
///
/// Most of the fields are set to zero, including the timestamp, to aid
/// with making builds reproducible.
///
/// ```c
/// typedef struct {
///     DWORD Characteristics,
///     DWORD TimeDateStamp,
///     WORD MajorVersion,
///     WORD MinorVersion,
///     WORD NumberOfNamedEntries,
///     WORD NumberOfIdEntries
/// } IMAGE_RESOURCE_DIRECTORY;
/// ```
pub fn resource_directory_table(number_of_id_entries: u16) -> [u8; 16] {
    let mut table = [0; 16];
    table[14..16].copy_from_slice(&number_of_id_entries.to_le_bytes());
    table
}

/// Returns the bytes for a resource directory entry for an ID.
///
/// ```c
/// typedef struct {
///     DWORD Name,
///     DWORD OffsetToData
/// } IMAGE_RESOURCE_DIRECTORY_ENTRY;
/// ```
pub fn resource_directory_id_entry(id: u32, offset: u32, subdirectory: bool) -> [u8; 8] {
    let mut entry = [0; 8];
    entry[0..4].copy_from_slice(&id.to_le_bytes());
    let flag: u32 = if subdirectory { 0x80000000 } else { 0 };
    entry[4..8].copy_from_slice(&((offset & 0x7fffffff) | flag).to_le_bytes());
    entry
}

/// Returns the bytes for a resource data entry.
///
/// ```c
/// typedef struct {
///     DWORD OffsetToData,
///     DWORD Size,
///     DWORD CodePage,
///     DWORD Reserved
/// } IMAGE_RESOURCE_DATA_ENTRY;
/// ```
pub fn resource_data_entry(rva: u32, size: u32) -> [u8; 16] {
    let mut entry = [0; 16];
    entry[0..4].copy_from_slice(&rva.to_le_bytes());
    entry[4..8].copy_from_slice(&size.to_le_bytes());
    entry
}

[ Dauer der Verarbeitung: 0.23 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