Extract Linux kernel and initrd filenames from PE binary

This commit is contained in:
Julian Stecklina 2022-11-23 15:40:52 +01:00
parent 788a112050
commit 4dab5f7b8f
2 changed files with 51 additions and 6 deletions

View File

@ -9,18 +9,20 @@ mod linux_loader;
mod pe_section; mod pe_section;
mod uefi_helpers; mod uefi_helpers;
use pe_section::pe_section_as_string;
use uefi::{ use uefi::{
prelude::*, prelude::*,
proto::{ proto::{
console::text::Output, console::text::Output,
loaded_image::LoadedImage, loaded_image::LoadedImage,
media::file::{File, FileAttribute, FileMode}, media::file::{File, FileAttribute, FileMode, RegularFile},
}, },
CString16,
}; };
use crate::{ use crate::{
linux_loader::InitrdLoader, linux_loader::InitrdLoader,
uefi_helpers::{booted_image_cmdline, read_all}, uefi_helpers::{booted_image_cmdline, booted_image_file, read_all},
}; };
fn print_logo(output: &mut Output) { fn print_logo(output: &mut Output) {
@ -41,27 +43,61 @@ fn print_logo(output: &mut Output) {
.unwrap(); .unwrap();
} }
struct EmbeddedConfiguration {
kernel_filename: CString16,
initrd_filename: CString16,
}
impl TryFrom<&mut RegularFile> for EmbeddedConfiguration {
type Error = uefi::Error;
fn try_from(file: &mut RegularFile) -> Result<Self, Self::Error> {
file.set_position(0)?;
let file_data = read_all(file)?;
let kernel_filename =
pe_section_as_string(&file_data, ".kernelp").ok_or(Status::INVALID_PARAMETER)?;
let initrd_filename =
pe_section_as_string(&file_data, ".initrdp").ok_or(Status::INVALID_PARAMETER)?;
Ok(Self {
kernel_filename: CString16::try_from(kernel_filename.as_str()).unwrap(),
initrd_filename: CString16::try_from(initrd_filename.as_str()).unwrap(),
})
}
}
#[entry] #[entry]
fn main(handle: Handle, mut system_table: SystemTable<Boot>) -> Status { fn main(handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
uefi_services::init(&mut system_table).unwrap(); uefi_services::init(&mut system_table).unwrap();
print_logo(system_table.stdout()); print_logo(system_table.stdout());
let config: EmbeddedConfiguration = {
let mut booted_image = booted_image_file(system_table.boot_services()).unwrap();
(&mut booted_image).try_into().unwrap()
};
let mut file_system = system_table let mut file_system = system_table
.boot_services() .boot_services()
.get_image_file_system(handle) .get_image_file_system(handle)
.unwrap(); .unwrap();
let mut root = file_system.open_volume().unwrap(); let mut root = file_system.open_volume().unwrap();
let mut file = root let mut kernel_file = root
.open(cstr16!("linux.efi"), FileMode::Read, FileAttribute::empty()) .open(
&config.kernel_filename,
FileMode::Read,
FileAttribute::empty(),
)
.unwrap() .unwrap()
.into_regular_file() .into_regular_file()
.unwrap(); .unwrap();
let initrd = root let initrd = root
.open( .open(
cstr16!("initrd.efi"), &config.initrd_filename,
FileMode::Read, FileMode::Read,
FileAttribute::empty(), FileAttribute::empty(),
) )
@ -75,7 +111,7 @@ fn main(handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
let kernel_cmdline = booted_image_cmdline(system_table.boot_services()).unwrap(); let kernel_cmdline = booted_image_cmdline(system_table.boot_services()).unwrap();
let kernel_data = read_all(&mut file).unwrap(); let kernel_data = read_all(&mut kernel_file).unwrap();
let kernel_handle = system_table let kernel_handle = system_table
.boot_services() .boot_services()
.load_image( .load_image(

View File

@ -1,3 +1,6 @@
use alloc::{borrow::ToOwned, string::String};
/// Extracts the data of a section of a PE file.
pub fn pe_section<'a>(file_data: &'a [u8], section_name: &str) -> Option<&'a [u8]> { pub fn pe_section<'a>(file_data: &'a [u8], section_name: &str) -> Option<&'a [u8]> {
let pe_binary = goblin::pe::PE::parse(file_data).ok()?; let pe_binary = goblin::pe::PE::parse(file_data).ok()?;
@ -12,3 +15,9 @@ pub fn pe_section<'a>(file_data: &'a [u8], section_name: &str) -> Option<&'a [u8
Some(&file_data[section_start..section_end]) Some(&file_data[section_start..section_end])
}) })
} }
/// Extracts the data of a section of a PE file and returns it as a string.
pub fn pe_section_as_string<'a>(file_data: &'a [u8], section_name: &str) -> Option<String> {
pe_section(file_data, section_name)
.and_then(|data| Some(core::str::from_utf8(data).unwrap().to_owned()))
}