//! 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;
pubstruct 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. pubfn 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. pubfn add_data(&mutself, 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. pubfn align_to(&mutself, n: u32) -> io::Result<()> { let offset = self.size_of_raw_data % n; if offset != 0 { let padding = n - offset; for _ in0..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. pubfn add_relocation(&mutself, 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. pubfn finish(mutself) -> 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; /// ``` pubfn resource_directory_table(number_of_id_entries: u16) -> [u8; 16] { letmut 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; /// ``` pubfn resource_directory_id_entry(id: u32, offset: u32, subdirectory: bool) -> [u8; 8] { letmut 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
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.