use std::env; use std::process; use std::io::{self, Write}; const VB2_SHA256_DIGEST_SIZE: usize = 32; const MAX_HEX_LENGTH: usize = 10; #[repr(C, packed)] struct Vb2SecdataKernelV0 { struct_version: u8, uid: u32, kernver: u32, reserved: [u8; 3], crc8: u8, } #[repr(C, packed)] struct Vb2SecdataKernelV1 { struct_version: u8, struct_size: u8, crc8: u8, flags: u8, kernver: u32, ec_hash: [u8; VB2_SHA256_DIGEST_SIZE], } struct Vb2Context<'a> { secdata_kernel: &'a [u8], } fn vb2_crc8(data: &[u8]) -> u8 { let mut crc: u16 = 0; for byte in data { crc ^= (*byte as u16) << 8; for _ in 0..8 { if crc & 0x8000 != 0 { crc ^= 0x1070 << 3; } crc <<= 1; } } (crc >> 8) as u8 } fn is_v0(context: &Vb2Context) -> bool { let major_version = (context.secdata_kernel[0] & 0xf0) >> 4; major_version == 0 } fn secdata_kernel_crc(context: &Vb2Context) -> u8 { if is_v0(context) { let size = std::mem::size_of::() - 1; vb2_crc8(&context.secdata_kernel[0..size]) } else { let struct_size = context.secdata_kernel[1] as usize; let offset = 3; vb2_crc8(&context.secdata_kernel[offset..struct_size]) } } fn is_valid_hex(input: &str) -> bool { if input.len() > MAX_HEX_LENGTH { return false; } if let Some(stripped) = input.strip_prefix("0x") { stripped.chars().all(|c| c.is_digit(16)) } else { false } } fn sanitize_input(input: &str) -> String { input.replace('\n', "\0") } fn convert_to_u32(input: &str) -> u32 { u32::from_str_radix(input.trim_start_matches("0x"), 16).unwrap_or_else(|_| { eprintln!( "The entered kernver, {}, was not valid hexadecimal. Please try again.", input ); process::exit(1); }) } fn print_hex(data: &[u8]) { for byte in data { print!("{:02x} ", byte); } println!(); } fn main() { let args: Vec = env::args().collect(); if args.len() < 2 || args.contains(&"--help".to_string()) { println!( "USAGE: {} \n\ e.g.: {} 0x00010001 --raw\n\ --raw - prints the output as raw hex bytes\n\ --ver=<0/1> - specifies the kernver struct version to use\n\ --help - shows this message\n\ KVG was created by kxtzownsu\n\ (now written in Rust)", args[0], args[0] ); process::exit(0); } let kernver = sanitize_input(&args[1]); if !is_valid_hex(&kernver) { eprintln!( "The entered kernver: {}, wasn't detected as valid hexadecimal (max 10 characters). Please try again.", kernver ); process::exit(1); } let kvarg = convert_to_u32(&kernver); let version = args.iter().find(|arg| arg.starts_with("--ver=")).map_or("", |v| &v[6..]); if version != "0" && version != "1" { eprintln!( "The entered struct version: {}, wasn't valid (see --help). Please try again.", version ); process::exit(1); } let mut buffer = Vec::new(); if version == "0" { let mut secdata0 = Vb2SecdataKernelV0 { struct_version: 0x02, uid: 0x4752574c, kernver: kvarg, reserved: [0x00; 3], crc8: 0, }; let ctx = Vb2Context { secdata_kernel: unsafe { std::slice::from_raw_parts( &secdata0 as *const _ as *const u8, std::mem::size_of::(), ) }, }; secdata0.crc8 = secdata_kernel_crc(&ctx); buffer.extend_from_slice(unsafe { std::slice::from_raw_parts( &secdata0 as *const _ as *const u8, std::mem::size_of::(), ) }); } else if version == "1" { let mut secdata1 = Vb2SecdataKernelV1 { struct_version: 0x10, struct_size: std::mem::size_of::() as u8, crc8: 0, flags: 0x0, kernver: kvarg, ec_hash: [0; VB2_SHA256_DIGEST_SIZE], }; let ctx = Vb2Context { secdata_kernel: unsafe { std::slice::from_raw_parts( &secdata1 as *const _ as *const u8, std::mem::size_of::(), ) }, }; secdata1.crc8 = secdata_kernel_crc(&ctx); buffer.extend_from_slice(unsafe { std::slice::from_raw_parts( &secdata1 as *const _ as *const u8, std::mem::size_of::(), ) }); } if args.contains(&"--raw".to_string()) { io::stdout().write_all(&buffer).unwrap(); } else { print_hex(&buffer); } }