diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/goblin/examples | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | third_party/rust/goblin/examples/ar.rs | 45 | ||||
-rw-r--r-- | third_party/rust/goblin/examples/automagic.rs | 23 | ||||
-rw-r--r-- | third_party/rust/goblin/examples/dotnet_pe_analysis.rs | 75 | ||||
-rw-r--r-- | third_party/rust/goblin/examples/dyldinfo.rs | 162 | ||||
-rw-r--r-- | third_party/rust/goblin/examples/lipo.rs | 68 | ||||
-rw-r--r-- | third_party/rust/goblin/examples/rdr.rs | 25 | ||||
-rw-r--r-- | third_party/rust/goblin/examples/scroll.rs | 31 |
7 files changed, 429 insertions, 0 deletions
diff --git a/third_party/rust/goblin/examples/ar.rs b/third_party/rust/goblin/examples/ar.rs new file mode 100644 index 0000000000..9346e3e045 --- /dev/null +++ b/third_party/rust/goblin/examples/ar.rs @@ -0,0 +1,45 @@ +//cargo run --example=ar -- crt1.a + +use goblin::elf; +use goblin::archive; +use std::env; +use std::path::Path; +use std::fs::File; +use std::io::Read; + +pub fn main () { + let len = env::args().len(); + if len <= 2 { + println!("usage: ar <path to archive> member") + } else { + let mut path = String::default(); + let mut member = String::default(); + for (i, arg) in env::args().enumerate() { + if i == 1 { + path = arg.as_str().to_owned(); + } else if i == 2 { + member = arg.as_str().to_owned(); + } + } + let path = Path::new(&path); + let buffer = { let mut v = Vec::new(); let mut f = File::open(&path).unwrap(); f.read_to_end(&mut v).unwrap(); v}; + match archive::Archive::parse(&buffer) { + Ok(archive) => { + println!("{:#?}", &archive); + println!("start: {:?}", archive.member_of_symbol("_start")); + match archive.extract(&member, &buffer) { + Ok(bytes) => { + match elf::Elf::parse(&bytes) { + Ok(elf) => { + println!("got elf: {:#?}", elf); + }, + Err(err) => println!("Err: {:?}", err) + } + }, + Err(err) => println!("Extraction Error: {:?}", err) + } + }, + Err(err) => println!("Err: {:?}", err) + } + } +} diff --git a/third_party/rust/goblin/examples/automagic.rs b/third_party/rust/goblin/examples/automagic.rs new file mode 100644 index 0000000000..cd31fdeb92 --- /dev/null +++ b/third_party/rust/goblin/examples/automagic.rs @@ -0,0 +1,23 @@ +use std::default::Default; + +// demonstrates "automagical" elf32/64 switches via cfg on arch and pub use hacks. +// SIZEOF_* will change depending on whether it's an x86_64 system or 32-bit x86, or really any cfg you can think of. +// similarly the printers will be different, since they have different impls. #typepuns4life + +#[cfg(target_pointer_width = "64")] +pub use goblin::elf64 as elf; + +#[cfg(target_pointer_width = "32")] +pub use goblin::elf32 as elf; + +#[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))] +use crate::elf::{header, sym}; + +#[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))] +fn main() { + let header: header::Header = Default::default(); + let sym: sym::Sym = Default::default(); + println!("header: {:?}, sym: {:?}", header, sym); + println!("sizeof header: {}", header::SIZEOF_EHDR); + println!("sizeof sym: {}", sym::SIZEOF_SYM); +} diff --git a/third_party/rust/goblin/examples/dotnet_pe_analysis.rs b/third_party/rust/goblin/examples/dotnet_pe_analysis.rs new file mode 100644 index 0000000000..00568e9f50 --- /dev/null +++ b/third_party/rust/goblin/examples/dotnet_pe_analysis.rs @@ -0,0 +1,75 @@ +/// Demonstrates how to read additional metadata (i.e. .Net runtime ones) from PE context + +use goblin::container::Endian; +use goblin::pe::data_directories::DataDirectory; +use goblin::pe::PE; +use goblin::pe::utils::get_data; +use scroll::ctx::TryFromCtx; +use scroll::Pread; + +#[repr(C)] +#[derive(Debug, Pread)] +pub struct CliHeader { + pub cb: u32, + pub major_version: u16, + pub minor_version: u16, + pub metadata: DataDirectory, + pub flags: u32, + pub entry_point_token: u32, +} + +#[repr(C)] +#[derive(Debug)] +struct MetadataRoot<'a> { + pub signature: u32, + pub major_version: u16, + pub minor_version: u16, + _reserved: u32, + pub length: u32, + pub version: &'a str, +} + +impl<'a> TryFromCtx<'a, Endian> for MetadataRoot<'a> { + type Error = scroll::Error; + fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { + let offset = &mut 0; + let signature = src.gread_with(offset, endian)?; + let major_version = src.gread_with(offset, endian)?; + let minor_version = src.gread_with(offset, endian)?; + let reserved = src.gread_with(offset, endian)?; + let length = src.gread_with(offset, endian)?; + let version = src.gread(offset)?; + Ok(( + Self { + signature, + major_version, + minor_version, + _reserved: reserved, + length, + version, + }, + *offset, + )) + } +} + +fn main() { + let file = include_bytes!("../assets/dotnet_executable_example.dll"); + let file = &file[..]; + let pe = PE::parse(file).unwrap(); + if pe.header.coff_header.machine != 0x14c { + panic!("Is not a .Net executable"); + } + let optional_header = pe.header.optional_header.expect("No optional header"); + let file_alignment = optional_header.windows_fields.file_alignment; + let cli_header = optional_header + .data_directories + .get_clr_runtime_header() + .expect("No CLI header"); + let sections = &pe.sections; + + let cli_header_value: CliHeader = get_data(file, sections, cli_header, file_alignment).unwrap(); + println!("{:#?}", cli_header_value); + let metadata_root: MetadataRoot = get_data(file, sections, cli_header_value.metadata, file_alignment).unwrap(); + println!("{:#?}", metadata_root); +} diff --git a/third_party/rust/goblin/examples/dyldinfo.rs b/third_party/rust/goblin/examples/dyldinfo.rs new file mode 100644 index 0000000000..384e5e59f2 --- /dev/null +++ b/third_party/rust/goblin/examples/dyldinfo.rs @@ -0,0 +1,162 @@ +use goblin::mach; +use std::env; +use std::process; +use std::path::Path; +use std::fs::File; +use std::io::Read; +use std::borrow::Cow; + +fn usage() -> ! { + println!("usage: dyldinfo <options> <mach-o file>"); + println!(" -bind print binds as seen by macho::imports()"); + println!(" -lazy_bind print lazy binds as seen by macho::imports()"); + process::exit(1); +} + +fn name_to_str(name: &[u8; 16]) -> Cow<'_, str> { + for i in 0..16 { + if name[i] == 0 { + return String::from_utf8_lossy(&name[0..i]) + } + } + String::from_utf8_lossy(&name[..]) +} + +fn dylib_name(name: &str) -> &str { + // observed behavior: + // "/usr/lib/libc++.1.dylib" => "libc++" + // "/usr/lib/libSystem.B.dylib" => "libSystem" + // "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation" => "CoreFoundation" + name + .rsplit('/').next().unwrap() + .split('.').next().unwrap() +} + +fn print_binds(sections: &[mach::segment::Section], imports: &[mach::imports::Import]) { + println!("bind information:"); + + println!( + "{:7} {:16} {:14} {:7} {:6} {:16} symbol", + "segment", + "section", + "address", + "type", + "addend", + "dylib", + ); + + for import in imports.iter().filter(|i| !i.is_lazy) { + // find the section that imported this symbol + let section = sections.iter() + .find(|s| import.address >= s.addr && import.address < (s.addr + s.size)); + + // get &strs for its name + let (segname, sectname) = section + .map(|sect| (name_to_str(§.segname), name_to_str(§.sectname))) + .unwrap_or((Cow::Borrowed("?"), Cow::Borrowed("?"))); + + println!( + "{:7} {:16} 0x{:<12X} {:7} {:6} {:16} {}{}", + segname, + sectname, + import.address, + "pointer", + import.addend, + dylib_name(import.dylib), + import.name, + if import.is_weak { " (weak import)" } else { "" } + ); + } +} + +fn print_lazy_binds(sections: &[mach::segment::Section], imports: &[mach::imports::Import]) { + println!("lazy binding information (from lazy_bind part of dyld info):"); + + println!( + "{:7} {:16} {:10} {:6} {:16} symbol", + "segment", + "section", + "address", + "index", + "dylib", + ); + + for import in imports.iter().filter(|i| i.is_lazy) { + // find the section that imported this symbol + let section = sections.iter() + .find(|s| import.address >= s.addr && import.address < (s.addr + s.size)); + + // get &strs for its name + let (segname, sectname) = section + .map(|sect| (name_to_str(§.segname), name_to_str(§.sectname))) + .unwrap_or((Cow::Borrowed("?"), Cow::Borrowed("?"))); + + println!( + "{:7} {:16} 0x{:<8X} {:<06} {:16} {}", + segname, + sectname, + import.address, + format!("0x{:04X}", import.start_of_sequence_offset), + dylib_name(import.dylib), + import.name + ); + } +} + +fn main () { + let len = env::args().len(); + + let mut bind = false; + let mut lazy_bind = false; + + if len <= 2 { + usage(); + } else { + // parse flags + { + let mut flags = env::args().collect::<Vec<_>>(); + flags.pop(); + flags.remove(0); + for option in flags { + match option.as_str() { + "-bind" => { bind = true } + "-lazy_bind" => { lazy_bind = true } + other => { + println!("unknown flag: {}", other); + println!(); + usage(); + } + } + } + } + + // open the file + let path = env::args_os().last().unwrap(); + let path = Path::new(&path); + let buffer = { let mut v = Vec::new(); let mut f = File::open(&path).unwrap(); f.read_to_end(&mut v).unwrap(); v}; + match mach::MachO::parse(&buffer, 0) { + Ok(macho) => { + // collect sections and sort by address + let mut sections: Vec<mach::segment::Section> = Vec::new(); + for sects in macho.segments.sections() { + sections.extend(sects.map(|r| r.expect("section").0)); + } + sections.sort_by_key(|s| s.addr); + + // get the imports + let imports = macho.imports().expect("imports"); + + if bind { + print_binds(§ions, &imports); + } + if lazy_bind { + print_lazy_binds(§ions, &imports); + } + }, + Err(err) => { + println!("err: {:?}", err); + process::exit(2); + } + } + } +} diff --git a/third_party/rust/goblin/examples/lipo.rs b/third_party/rust/goblin/examples/lipo.rs new file mode 100644 index 0000000000..72cf7a5107 --- /dev/null +++ b/third_party/rust/goblin/examples/lipo.rs @@ -0,0 +1,68 @@ +use goblin::mach::{self, Mach}; +use std::env; +use std::process; +use std::path::Path; +use std::fs::File; +use std::io::{Read, Write}; + +fn usage() -> ! { + println!("usage: lipo <options> <mach-o fat file>"); + println!(" -m64 Extracts and writes the 64-bit binary in this fat container, if any"); + process::exit(1); +} + +fn main () { + let len = env::args().len(); + + if len <= 1 { + usage(); + } else { + let mut m64 = false; + { + let mut flags = env::args().collect::<Vec<_>>(); + flags.pop(); + flags.remove(0); + for option in flags { + match option.as_str() { + "-m64" => { m64 = true } + other => { + println!("unknown flag: {}", other); + println!(); + usage(); + } + } + } + } + + let path_name = env::args_os().last().unwrap(); + let path = Path::new(&path_name); + let buffer = { let mut v = Vec::new(); let mut f = File::open(&path).unwrap(); f.read_to_end(&mut v).unwrap(); v}; + match mach::Mach::parse(&buffer) { + Ok(Mach::Binary(_macho)) => { + println!("Already a single arch binary"); + process::exit(2); + }, + Ok(Mach::Fat(fat)) => { + for (i, arch) in fat.iter_arches().enumerate() { + let arch = arch.unwrap(); + let name = format!("{}.{}", &path_name.to_string_lossy(), i); + let path = Path::new(&name); + if arch.is_64() && m64 { + let bytes = &buffer[arch.offset as usize..][..arch.size as usize]; + let mut file = File::create(path).unwrap(); + file.write_all(bytes).unwrap(); + break; + } else if !m64 { + let bytes = &buffer[arch.offset as usize..][..arch.size as usize]; + let mut file = File::create(path).unwrap(); + file.write_all(bytes).unwrap(); + } + } + }, + Err(err) => { + println!("err: {:?}", err); + process::exit(2); + } + } + } +} diff --git a/third_party/rust/goblin/examples/rdr.rs b/third_party/rust/goblin/examples/rdr.rs new file mode 100644 index 0000000000..b5aaefe2c0 --- /dev/null +++ b/third_party/rust/goblin/examples/rdr.rs @@ -0,0 +1,25 @@ +use goblin::error; +use std::path::Path; +use std::env; +use std::fs::File; +use std::io::Read; + +fn run () -> error::Result<()> { + for (i, arg) in env::args().enumerate() { + if i == 1 { + let path = Path::new(arg.as_str()); + let mut fd = File::open(path)?; + let buffer = { let mut v = Vec::new(); fd.read_to_end(&mut v).unwrap(); v}; + let res = goblin::Object::parse(&buffer)?; + println!("{:#?}", res); + } + } + Ok(()) +} + +pub fn main () { + match run() { + Ok(()) => (), + Err(err) => println!("{:#}", err) + } +} diff --git a/third_party/rust/goblin/examples/scroll.rs b/third_party/rust/goblin/examples/scroll.rs new file mode 100644 index 0000000000..a0f7beb61e --- /dev/null +++ b/third_party/rust/goblin/examples/scroll.rs @@ -0,0 +1,31 @@ +/// Demonstrates the magical powers of scroll + goblin +/// Goblin implements `TryFromCtx` for the header type +/// which means downstream crates/clients can just "parse" headers out of +/// arbitrary buffers, without learning new crate specific function names +/// I.e., all you need are Types + Pread = Happiness + +use goblin::{error, elf64, elf}; +use scroll::{Pwrite, Pread}; + +fn run () -> error::Result<()> { + let crt1: Vec<u8> = include!("../etc/crt1.rs"); + let header: elf64::header::Header = crt1.pread(0)?; + assert_eq!(header.e_type, elf64::header::ET_REL); + println!("header: {:?}", &header); + // now lets write the header into some bytes + let mut bytes = [0u8; elf64::header::SIZEOF_EHDR]; + bytes.pwrite(header, 0)?; + // read it back out + let header2: elf64::header::Header = bytes.pread(0)?; + // they're the same + assert_eq!(header, header2); + let elf: elf::Elf = crt1.pread(0)?; + println!("elf: {:#?}", &elf); + let elf = elf::Elf::parse(&crt1)?; + println!("elf: {:#?}", &elf); + Ok(()) +} + +fn main() { + run().unwrap(); +} |