From 5449543501ac42aa6227538bd49a978ccc67d21f Mon Sep 17 00:00:00 2001 From: Eric-Paul Ickhorn Date: Tue, 18 Apr 2023 08:56:51 +0200 Subject: [PATCH] Tools for creating MBR --- crmbr/Cargo.toml | 8 ++ crmbr/src/main.rs | 235 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 243 insertions(+) create mode 100644 crmbr/Cargo.toml create mode 100644 crmbr/src/main.rs diff --git a/crmbr/Cargo.toml b/crmbr/Cargo.toml new file mode 100644 index 0000000..9074703 --- /dev/null +++ b/crmbr/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "crmbr" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/crmbr/src/main.rs b/crmbr/src/main.rs new file mode 100644 index 0000000..d66c007 --- /dev/null +++ b/crmbr/src/main.rs @@ -0,0 +1,235 @@ +use std::fs::File; +use std::io::Read; +use std::io::Write; +use std::env; +use std::vec::*; +use std::string::*; + +struct MBRPartTableEntry { + part_type: u8, + first_sector: u64, + last_sector: u64, + bootable: bool, +} + +fn serialize_mbr_partition_table_entry(info: MBRPartTableEntry) -> Vec { + + let mut buffer = Vec::::new(); + buffer.resize(16, 0x00); + + if info.bootable { + buffer[0] = 0x80; + } + buffer[5] = info.part_type; + + buffer[8] = ((info.first_sector & 0xff000000) >> 24) as u8; + buffer[9] = ((info.first_sector & 0x00ff0000) >> 16) as u8; + buffer[10] = ((info.first_sector & 0x0000ff00) >> 8) as u8; + buffer[11] = (info.first_sector & 0x000000ff) as u8; + + buffer[12] = ((info.last_sector & 0xff000000) >> 24) as u8; + buffer[13] = ((info.last_sector & 0x00ff0000) >> 16) as u8; + buffer[14] = ((info.last_sector & 0x0000ff00) >> 8) as u8; + buffer[15] = (info.last_sector & 0x000000ff) as u8; + + return buffer; +} + +fn parse_command_line_partition_table_entry(input: Vec) -> MBRPartTableEntry { + if input.len() != 4 { + panic!("Wrong number of fields in partition table entry"); + } + let part_type = resolve_text_to_partition_type(&input[0]); + let first_sector: u64 = match input[1].parse() { + Ok(val) => val, + Err(_) => { + panic!("Invalid partition start sector in '-p1'!"); + } + }; + let last_sector: u64 = match input[2].parse() { + Ok(val) => val, + Err(_) => { + panic!("Invalid partition end sector in '-p1'!"); + } + }; + let mut is_bootable: bool = false; + if input[3] == "true" { + is_bootable = true; + } + + return MBRPartTableEntry { + part_type: part_type, + first_sector: first_sector, + last_sector: last_sector, + bootable: is_bootable + } +} + +fn resolve_text_to_partition_type(text: &String) -> u8 { + return match text.as_str() { + "empty" => 0x00, + "fat12" => 0x01, + "fat16" => 0x04, + "ext" => 0x05, + "fat16_big" => 0x06, + "ntfs" => 0x07, + "fat32_chs" => 0x0b, + "fat32_lba" => 0x0c, + "fat16_big_lba" => 0x0e, + "ext_lba" => 0x0f, + "win_lvm" => 0x42, + "gpfs" => 0x75, + "swap" => 0x82, + "linux" => 0x83, + "linux_lvm" => 0x8e, + "freebsd" => 0xa5, + "openbsd" => 0xa6, + "netbsd" => 0xa9, + "macos" => 0xaf, + &_ => 0xff + }; +} + +fn main() { + + let mut buffer = Vec::::new(); + buffer.resize(512, 0x00); + buffer[510] = 0x55; + buffer[511] = 0xAA; + + let mut has_bootcode = false; + let mut bootcode: [u8; 440] = [0x00; 440]; + + let mut has_output_path = false; + let mut output_path: String = "".to_string(); + + let args: Vec = env::args().collect(); + + let mut index: usize = 0; + while index < args.len() { + + let arg = &args[index]; + + if arg == "-h" { + + } + if arg == "-mbc" { + index += 1; + if index >= args.len() { + panic!("Failed reading stage 1 bootloader: No path provided!"); + } + let mut file = match File::open(args[index].as_str()) { + Ok(val) => val, + Err(err) => { + panic!("Failed reading Master Boot Code from file: {}", err); + } + }; + + let file_len = match file.read(&mut bootcode) { + Ok(val) => val, + Err(err) => { + panic!("Failed reading stage 1 bootloader from '{}': {}", args[index], err); + } + }; + if file_len > 440 { + panic!("The stage 1 bootloader can be at most 440 bytes in size!"); + } + index += 1; + has_bootcode = true; + continue; + } + if arg == "-out" { + index += 1; + output_path = args[index].clone(); + has_output_path = true; + index += 1; + continue; + } + if arg == "-p1" { + if args.len() <= (index + 4) { + println!("Too short input near '-p1': This argument has 4 fields!"); + return; + } + index += 1; + + let entry = serialize_mbr_partition_table_entry( + parse_command_line_partition_table_entry(args[index..index+4].to_vec()) + ); + buffer[446..446+16].clone_from_slice(entry.as_slice()); + + index += 4; + continue; + } + if arg == "-p2" { + if args.len() <= (index + 4) { + println!("Too short input near '-p2': This argument has 4 fields!"); + return; + } + index += 1; + + let entry = serialize_mbr_partition_table_entry( + parse_command_line_partition_table_entry(args[index..index+4].to_vec()) + ); + buffer[462..462+16].clone_from_slice(entry.as_slice()); + + index += 4; + continue; + } + if arg == "-p3" { + if args.len() <= (index + 4) { + println!("Too short input near '-p3': This argument has 4 fields!"); + return; + } + index += 1; + + let entry = serialize_mbr_partition_table_entry( + parse_command_line_partition_table_entry(args[index..index+4].to_vec()) + ); + buffer[478..478+16].clone_from_slice(entry.as_slice()); + + index += 4; + continue; + } + if arg == "-p4" { + if args.len() <= (index + 4) { + println!("Too short input near '-p4': This argument has 4 fields!"); + return; + } + index += 1; + + let entry = serialize_mbr_partition_table_entry( + parse_command_line_partition_table_entry(args[index..index+4].to_vec()) + ); + buffer[494..494+16].clone_from_slice(entry.as_slice()); + + index += 4; + continue; + } + index += 1; + } + + if !has_output_path { + panic!("No output path defined!"); + } + + if !has_bootcode { + panic!("No bootcode defined!"); + } + + buffer[0..440].clone_from_slice(bootcode.as_slice()); + + let mut output_file = match File::create(output_path) { + Ok(val) => val, + Err(err) => { + panic!("Failed opening output file: {}", err); + } + }; + match output_file.write_all(&buffer) { + Ok(len) => len, + Err(err) => { + panic!("Failed writing output: {}", err); + } + } + + +}