summaryrefslogtreecommitdiffstats
path: root/third_party/rust/goblin/examples
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/rust/goblin/examples/ar.rs45
-rw-r--r--third_party/rust/goblin/examples/automagic.rs23
-rw-r--r--third_party/rust/goblin/examples/dotnet_pe_analysis.rs75
-rw-r--r--third_party/rust/goblin/examples/dyldinfo.rs162
-rw-r--r--third_party/rust/goblin/examples/lipo.rs68
-rw-r--r--third_party/rust/goblin/examples/rdr.rs25
-rw-r--r--third_party/rust/goblin/examples/scroll.rs31
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(&sect.segname), name_to_str(&sect.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(&sect.segname), name_to_str(&sect.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(&sections, &imports);
+ }
+ if lazy_bind {
+ print_lazy_binds(&sections, &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();
+}