binfarce/
lib.rs

1#![forbid(unsafe_code)]
2
3//! Extremely minimal parser for ELF/PE/Mach-o/ar.
4//!
5//! This crate is used mostly for sharing code between `cargo-bloat` and `auditable-extract` crates.
6//! It implements just enough features for those tools to work.
7//! If you're looking for a fully-featured parser, see [`goblin`](https://crates.io/crates/goblin).
8
9// Style lints on which pre-existing code disagrees with Clippy
10#![allow(clippy::single_match)]
11#![allow(clippy::while_let_loop)]
12#![allow(clippy::single_char_pattern)]
13#![allow(clippy::many_single_char_names)]
14
15// I find this more readable
16#![allow(clippy::skip_while_next)]
17
18pub mod ar;
19pub mod demangle;
20pub mod elf32;
21pub mod elf64;
22pub mod macho;
23pub mod pe;
24mod parser;
25mod error;
26
27pub use crate::error::ParseError;
28pub use crate::parser::UnexpectedEof;
29
30#[derive(Clone, Copy, PartialEq, Debug)]
31pub enum ByteOrder {
32    LittleEndian,
33    BigEndian,
34}
35
36pub enum Format {
37    Elf32 {byte_order: ByteOrder},
38    Elf64 {byte_order: ByteOrder},
39    Macho,
40    PE,
41    Unknown,
42}
43
44pub fn detect_format(data: &[u8]) -> Format {
45    if data.len() < 8 {return Format::Unknown};
46    let macho_signatures = [
47        b"\xCA\xFE\xBA\xBE", // multi-architecture macOS
48        b"\xFE\xED\xFA\xCE", // 32-bit macOS
49        b"\xFE\xED\xFA\xCF", // 64-bit macOS
50        b"\xCE\xFA\xED\xFE", // and now the same in reverse order
51        b"\xCF\xFA\xED\xFE", // because they could
52    ];
53    if data.starts_with(b"\x7FELF") {
54        let byte_order = match data[5] {
55            1 => ByteOrder::LittleEndian,
56            2 => ByteOrder::BigEndian,
57            _ => return Format::Unknown,
58        };
59        return match data[4] {
60            1 => Format::Elf32{byte_order},
61            2 => Format::Elf64{byte_order},
62            _ => Format::Unknown,
63        };
64    } else if data.starts_with(b"MZ") {
65        return Format::PE;
66    } else {
67        for signature in &macho_signatures {
68            if data.starts_with(*signature) {
69                return Format::Macho;
70            }
71        }
72    }
73    Format::Unknown
74}