Big update!

- Source code added
- Readme, gitignore, banner and the license are updated
This commit is contained in:
*Nix Fanboy
2024-10-19 19:40:28 +03:00
parent 4f42fe49e2
commit 3336ab8365
32 changed files with 2320 additions and 511 deletions

43
src/archive.rs Executable file
View File

@@ -0,0 +1,43 @@
use crate::{
debug::{debug_objects, find_error_type, merge_members},
parse_objects,
structs::{CharVec, Debugging, ParsingError, StringPtr, ULDDObj, ULDDObjResult},
};
use goblin::archive::Archive;
pub(crate) fn parse_archive<'a>(
file_name: &'a str,
buffer: &'a [u8],
archive: Archive<'a>,
member_names: &mut Vec<&'a str>,
objects: &mut Vec<ULDDObjResult>,
debugging: bool,
) {
for member in archive.members() {
member_names.push(file_name);
let member_buffer = match archive.extract(member, buffer) {
Ok(buf) => buf,
Err(error) => {
Debugging::Error(format!("Error while extracting the bytes of the member named '{}' from buffer of the file named '{}'{}\nDetails:\n{}",
member,
file_name,
merge_members(member_names),
error)).print(debugging);
return objects.push(ULDDObjResult {
error: ParsingError {
code: find_error_type(&error),
explanation: StringPtr::from(error.to_string()).0,
},
obj: ULDDObj {
file_name: StringPtr::from(file_name).0,
member_name: CharVec::from(member_names),
file_type: StringPtr::from("Archive").0,
..Default::default()
},
});
}
};
debug_objects(file_name, member_names, "an archive file", debugging);
parse_objects(member, member_buffer, member_names, objects, debugging);
}
}

40
src/coff.rs Executable file
View File

@@ -0,0 +1,40 @@
use crate::{
debug::debug_objects,
structs::{CharVec, ParsingError, StringPtr, ULDDObj, ULDDObjResult},
types::PE_ARCH,
};
use goblin::pe::{
characteristic::{IMAGE_FILE_32BIT_MACHINE, IMAGE_FILE_DEBUG_STRIPPED},
Coff,
};
use std::ptr::null_mut;
pub(crate) fn parse_coff(
file_name: &str,
coff: Coff,
member_names: &mut Vec<&str>,
debugging: bool,
) -> ULDDObjResult {
// Thanks to developers of goblin for making me to find out that I can "bitwise and" characteristics and wanted characteristics to find out if the COFF file has the one we want
let is_64 = coff.header.characteristics & IMAGE_FILE_32BIT_MACHINE != IMAGE_FILE_32BIT_MACHINE;
let is_stripped =
coff.header.characteristics & IMAGE_FILE_DEBUG_STRIPPED == IMAGE_FILE_DEBUG_STRIPPED;
let cpu_type = StringPtr::from(PE_ARCH.get(&coff.header.machine)).0;
debug_objects(file_name, member_names, "a COFF binary", debugging);
ULDDObjResult {
error: ParsingError::default(),
obj: ULDDObj {
file_name: StringPtr::from(file_name).0,
member_name: CharVec::from(member_names),
executable_format: StringPtr::from("COFF").0,
is_64,
os_type: StringPtr::from("Windows").0,
file_type: StringPtr::from("Windows object file").0,
is_stripped,
cpu_type,
cpu_subtype: null_mut(),
interpreter: null_mut(),
libraries: CharVec::default(),
},
}
}

37
src/debug.rs Normal file
View File

@@ -0,0 +1,37 @@
use goblin::error::Error as ObjectError;
use crate::structs::Debugging;
pub(crate) fn find_error_type(error: &ObjectError) -> i64 {
match error {
ObjectError::Malformed(_) => -1,
ObjectError::BadMagic(_) => -2,
ObjectError::Scroll(_) => -3,
ObjectError::BufferTooShort(_, _) => -4,
ObjectError::IO(_) => -5,
_ => -6,
}
}
pub(crate) fn merge_members(member_names: &mut [&str]) -> String {
if !member_names.is_empty() {
format!(" (Member of: {})", member_names.join(" -> "))
} else {
String::new()
}
}
pub(crate) fn debug_objects(
file_name: &str,
member_names: &mut [&str],
object_name: &str,
debugging: bool,
) {
Debugging::Info(format!(
"The binary named '{}'{} is {}",
file_name,
merge_members(member_names),
object_name
))
.print(debugging)
}

133
src/elf.rs Executable file
View File

@@ -0,0 +1,133 @@
use std::ptr::null_mut;
use crate::{
debug::debug_objects,
structs::{CharVec, ParsingError, StringPtr, ULDDObj, ULDDObjResult},
types::{ElfFileType, ElfOS, E_MACHINE, E_TYPE},
};
use goblin::elf::Elf;
fn find_os_from_strtab_elf(elf: &Elf<'_>, pat: &[&str]) -> bool {
[
elf.strtab.to_vec().unwrap_or(vec![""]),
elf.shdr_strtab.to_vec().unwrap_or(vec![""]),
elf.dynstrtab.to_vec().unwrap_or(vec![""]),
]
.iter()
.flatten()
.any(|s| pat.iter().any(|i| s.to_lowercase().contains(i)))
}
fn find_os_elf(elf: &Elf<'_>, os_abi: u8) -> (ElfOS, *mut i8) {
let os = {
match os_abi {
0x00 => match true {
_ if find_os_from_strtab_elf(elf, &["fbsd"]) => ElfOS::FreeBSD,
_ if find_os_from_strtab_elf(elf, &["openbsd"]) => ElfOS::OpenBSD,
_ if find_os_from_strtab_elf(elf, &["musl", "glibc", "linux"]) => ElfOS::Linux,
_ if find_os_from_strtab_elf(elf, &["android"]) => ElfOS::Android,
_ if find_os_from_strtab_elf(elf, &["netbsd"]) => ElfOS::NetBSD,
_ if find_os_from_strtab_elf(elf, &["solaris"]) => ElfOS::Solaris,
_ if find_os_from_strtab_elf(elf, &["illumos"]) => ElfOS::Illumos,
_ if elf.interpreter.is_some_and(|v| v.contains("Loader.so")) => ElfOS::SerenityOS,
_ => return (ElfOS::Undefined, null_mut()),
},
0x01 => ElfOS::HPUX,
0x02 => ElfOS::NetBSD,
0x03 => ElfOS::Linux,
0x04 => ElfOS::GNUHurd,
0x06 => {
if find_os_from_strtab_elf(elf, &["illumos"]) {
ElfOS::Illumos
} else {
ElfOS::Solaris
}
}
0x07 => ElfOS::AIXMonterey,
0x08 => ElfOS::IRIX,
0x09 => ElfOS::FreeBSD,
0x10 => ElfOS::FenixOS,
0x11 => ElfOS::CloudABI,
0x12 => ElfOS::OpenVOS,
0x0A => ElfOS::Tru64,
0x0B => ElfOS::NovellModesto,
0x0C => ElfOS::OpenBSD,
0x0D => ElfOS::OpenVMS,
0x0E => ElfOS::NonStopKernel,
0x0F => ElfOS::AROS,
_ => return (ElfOS::Undefined, null_mut()),
}
};
(os, StringPtr::from(os.to_string()).0)
}
fn find_linux_vdso(e_machine: u16, bit_type: bool) -> Option<&'static str> {
match e_machine {
0x3E => Some("linux-vdso.so.1"),
0x03 => Some("linux-vdso.so.1"),
0x2A => Some("linux-gate.so.1"),
0x16 => {
if bit_type {
Some("linux-vdso64.so.1")
} else {
Some("linux-vdso32.so.1")
}
}
0xF3 => Some("linux-vdso.so.1"),
0x15 => Some("linux-vdso64.so.1"),
0x14 => Some("linux-vdso32.so.1"),
0x08 => Some("linux-vdso.so.1"),
0x32 => Some("linux-gate.so.1"),
0x28 => Some("linux-vdso.so.1"),
0xB7 => Some("linux-vdso.so.1"),
_ => None,
}
}
fn convert_libraries_into_char_vec(elf: &mut Elf, os_abi: u8) -> CharVec {
let mut vector = std::mem::take(&mut elf.libraries);
if let (Some(vdso), ElfOS::Linux) = (
find_linux_vdso(elf.header.e_machine, elf.is_64),
find_os_elf(elf, os_abi).0,
) {
vector.push(vdso)
}
CharVec::from(vector)
}
pub(crate) fn parse_elf(
file_name: &str,
elf: Elf,
os_abi: u8,
member_names: &mut Vec<&str>,
debugging: bool,
) -> ULDDObjResult {
let mut elf = elf;
let cpu_type = StringPtr::from(E_MACHINE.get(&elf.header.e_machine)).0;
let file_type = match E_TYPE.get(&elf.header.e_type) {
_ if elf.header.e_type == 0x03 && elf.interpreter.is_some() => {
StringPtr::from(ElfFileType::Executable.to_string()).0
}
rest => StringPtr::from(rest).0,
};
let interpreter = StringPtr::from(elf.interpreter).0;
debug_objects(file_name, member_names, "an ELF binary", debugging);
ULDDObjResult {
error: ParsingError::default(),
obj: ULDDObj {
file_name: StringPtr::from(file_name).0,
member_name: CharVec::from(member_names),
executable_format: StringPtr::from("ELF").0,
is_64: elf.is_64,
os_type: find_os_elf(&elf, os_abi).1,
file_type,
is_stripped: elf.syms.is_empty(),
cpu_type,
cpu_subtype: null_mut(),
interpreter,
libraries: convert_libraries_into_char_vec(&mut elf, os_abi),
},
}
}

152
src/impls.rs Executable file
View File

@@ -0,0 +1,152 @@
use crate::{
structs::{CharVec, Debugging, ParsingError, StringPtr, ULDDObj},
ULDDObjResult, ULDDObjResultVec,
};
use anstream::{eprintln as a_eprintln, println as a_println};
use owo_colors::OwoColorize;
use std::{fmt::Display, mem::ManuallyDrop, ptr::null_mut, ffi::{c_char, CString}};
impl From<Vec<*mut c_char>> for CharVec {
fn from(value: Vec<*mut c_char>) -> Self {
CharVec {
capacity: value.capacity(),
length: value.len(),
vec: if value.is_empty() {
null_mut()
} else {
ManuallyDrop::new(value).as_mut_ptr()
},
}
}
}
impl From<Vec<ULDDObjResult>> for ULDDObjResultVec {
fn from(value: Vec<ULDDObjResult>) -> Self {
ULDDObjResultVec {
capacity: value.capacity(),
length: value.len(),
vec: if value.is_empty() {
null_mut()
} else {
ManuallyDrop::new(value).as_mut_ptr()
},
}
}
}
impl Default for CharVec {
fn default() -> Self {
Self {
capacity: 0,
length: 0,
vec: null_mut(),
}
}
}
impl From<Vec<&str>> for CharVec {
fn from(val: Vec<&str>) -> Self {
let vector: Vec<*mut c_char> = val
.into_iter()
.map(|item| unsafe {
CString::from_vec_unchecked(item.to_string().into_bytes()).into_raw()
})
.collect();
CharVec::from(vector)
}
}
impl From<&mut Vec<&str>> for CharVec {
fn from(val: &mut Vec<&str>) -> Self {
let vector: Vec<*mut c_char> = std::mem::take(val)
.into_iter()
.map(|item| unsafe {
CString::from_vec_unchecked(item.to_string().into_bytes()).into_raw()
})
.collect();
CharVec::from(vector)
}
}
impl From<String> for StringPtr {
fn from(value: String) -> Self {
let mut value = value;
value.push('\0');
let c_string = match CString::from_vec_with_nul(value.into_bytes()) {
Ok(string) => string,
Err(error) => {
Debugging::Fatal("converting the string into a C string".to_owned()).print(true);
panic!("{}", error)
}
};
StringPtr(c_string.into_raw())
}
}
impl From<&str> for StringPtr {
fn from(value: &str) -> Self {
StringPtr::from(value.to_owned())
}
}
impl<T> From<Option<T>> for StringPtr
where
T: Display,
{
fn from(value: Option<T>) -> Self {
let Some(t) = value else {
return StringPtr(null_mut());
};
StringPtr::from(t.to_string())
}
}
impl Default for ParsingError {
fn default() -> Self {
Self {
code: 0,
explanation: null_mut(),
}
}
}
impl Default for ULDDObj {
fn default() -> Self {
Self {
file_name: null_mut(),
member_name: Default::default(),
executable_format: null_mut(),
is_64: false,
os_type: null_mut(),
file_type: null_mut(),
is_stripped: false,
cpu_type: null_mut(),
cpu_subtype: null_mut(),
interpreter: null_mut(),
libraries: Default::default(),
}
}
}
impl Debugging {
pub(crate) fn print(self, debugging: bool) {
if debugging {
match self {
Debugging::Info(msg) => {
a_println!("{} {}", "[INFO]".yellow().bold(), msg);
}
Debugging::Affirmative(msg) => {
a_println!("{} {}", "[OK]".green().bold(), msg);
}
Debugging::Error(msg) => {
a_eprintln!("{} {}", "[ERROR]".red().bold(), msg);
}
Debugging::Fatal(msg) => {
a_eprintln!("{} Library got a fatal error while {}. Panic function will halt the library and provide a stacktrace.", "[FATAL]".red().bold(), msg);
}
}
}
}
}

286
src/lib.rs Executable file
View File

@@ -0,0 +1,286 @@
#![doc(
html_favicon_url = "https://github.com/nix-enthusiast/unildd/blob/main/media/emblems/UniLDD-%25100.png?raw=true"
)]
#![doc(
html_logo_url = "https://github.com/nix-enthusiast/unildd/blob/main/media/emblems/UniLDD-%25400.png?raw=true"
)]
#![doc(html_playground_url = "https://play.rust-lang.org/")]
//!
//! ![banner](https://github.com/nix-enthusiast/unildd/blob/main/media/banner/UniLDD%20Banner.png?raw=true)
//!
//! ### UniLDD is designed for bringing parsing objects to any language (has a C FFI library).
//!
//! ### ⭐️ Features:
//! - Detailed information! Some of them are:
//! - Name of the OS
//! - File type (Core dump, shared library, executable, etc.)
//! - ISA type (X86_64, Aarch64, RISC-V, etc.)
//! - CPU Subtype[^1]
//! - Name of the linker[^2]
//! - Which libraries are linked
//! - Parses without loading objects. Therefore, you can even parse shady objects like malwares![^3]
//! - Error codes and explanations to make error handling easier.
//! - A Basic and built-in logger to get real-time information.
//!
//! [^1]: CPU subtype is a macOS-only feature which tells what kind of CPU model the code is optimized for.
//!
//! [^2]: It has some caveats. See [`ULDDObj`] for further details.
//!
//! [^3]: That doesn't mean I am liable for any damages done by this project and files you parsed. Take your own risk!
//!
use archive::parse_archive;
use coff::parse_coff;
use debug::{find_error_type, merge_members};
use elf::parse_elf;
use goblin::Object;
use mach::parse_mach;
use owo_colors::OwoColorize;
use pe::parse_pe;
use std::ffi::{c_char, CStr, CString};
use structs::{
CharVec, Debugging, ParsingError, StringPtr, ULDDObj, ULDDObjResult, ULDDObjResultVec,
};
#[doc(hidden)]
pub mod archive;
#[doc(hidden)]
pub mod coff;
#[doc(hidden)]
pub mod debug;
#[doc(hidden)]
pub mod elf;
#[doc(hidden)]
pub mod impls;
#[doc(hidden)]
pub mod mach;
#[doc(hidden)]
pub mod pe;
pub mod structs;
pub mod types;
fn parse_objects<'a>(
file_name: &'a str,
buffer: &'a [u8],
member_names: &mut Vec<&'a str>,
objects: &mut Vec<ULDDObjResult>,
debugging: bool,
) {
match Object::parse(buffer) {
Ok(Object::Archive(archive)) => {
parse_archive(file_name, buffer, archive, member_names, objects, debugging)
}
Ok(Object::Mach(mach)) => {
parse_mach(file_name, buffer, mach, member_names, objects, debugging)
}
Ok(Object::Elf(elf)) => {
objects.push(parse_elf(
file_name,
elf,
buffer[0x7],
member_names,
debugging,
));
}
Ok(Object::PE(pe)) => objects.push(parse_pe(file_name, pe, member_names, debugging)),
Ok(Object::COFF(coff)) => {
objects.push(parse_coff(file_name, coff, member_names, debugging));
}
Ok(Object::Unknown(magic_number)) => {
let msg = format!(
"The binary named '{}'{} has a unknown magic number (in big-endian): {}",
file_name,
merge_members(member_names),
format!("{:02X?}", magic_number.to_be_bytes()).replace(['[', ']', ','], "")
);
Debugging::Error(msg.to_owned()).print(debugging);
objects.push(ULDDObjResult {
error: ParsingError {
code: magic_number as i64,
explanation: StringPtr::from(msg).0,
},
obj: ULDDObj {
file_name: StringPtr::from(file_name).0,
member_name: CharVec::from(member_names),
..Default::default()
},
})
}
Ok(_) => {
let msg = format!(
"The executable format of the file named '{}'{} is not yet implemented",
file_name,
merge_members(member_names),
);
Debugging::Error(msg.to_string()).print(debugging);
Debugging::Info(format!(
"First 16 bytes of the file named '{}' are {}",
file_name,
format!("{:02X?}", &buffer[0..17]).replace(['[', ']', ','], "")
))
.print(debugging);
objects.push(ULDDObjResult {
error: ParsingError {
code: -7,
explanation: StringPtr::from(msg).0,
},
obj: ULDDObj {
file_name: StringPtr::from(file_name).0,
member_name: CharVec::from(member_names),
..Default::default()
},
})
}
Err(error) => {
Debugging::Error(format!(
"Error while parsing the bytes of the given file named '{}'{}\nDetails:\n{}",
file_name,
merge_members(member_names),
error
))
.print(debugging);
objects.push(ULDDObjResult {
error: ParsingError {
code: find_error_type(&error),
explanation: StringPtr::from(error.to_string()).0,
},
obj: ULDDObj {
file_name: StringPtr::from(file_name).0,
member_name: CharVec::from(member_names),
..Default::default()
},
})
}
};
}
///
/// Parses the given buffer and returns a vector of parsed binaries.
///
/// # Safety
///
/// This function is null pointer-safe. If the file name is an invalid UTF-8 string and/or buffer pointer is a null pointer it will panic.
///
/// Since the function returns a [`ULDDObjResultVec`] created by rust it has to be [deallocated](free_obj) by rust if it is done by other languages errors may occur.
///
#[no_mangle]
pub unsafe extern "C" fn read_obj(
file_name: *const c_char,
buffer: *const u8,
buffer_size: usize,
debugging: bool,
) -> ULDDObjResultVec {
let (buf, f_name) = unsafe {
let s = match CStr::from_ptr(file_name).to_str() {
Ok(string_slice) => string_slice,
Err(error) => {
Debugging::Fatal("converting the C string to a &str".to_owned()).print(true);
panic!("{}", error)
}
};
let b = std::slice::from_raw_parts(buffer, buffer_size);
(b, s)
};
let mut objects = vec![];
parse_objects(f_name, buf, &mut vec![], &mut objects, debugging);
let (total, success, failed): (usize, usize, usize) = {
let t = objects.len();
let (mut s, mut f) = (0, 0);
objects.iter().for_each(|o| {
if o.error.code != 0 {
f += 1;
} else {
s += 1
}
});
(t, s, f)
};
Debugging::Affirmative(format!(
"{} binaries from the file(s) are parsed. Success/Fail rate of parsing(s) is {}/{}",
total,
success.green(),
failed.red()
))
.print(debugging);
ULDDObjResultVec::from(objects)
}
unsafe fn drop_c_string(ptr: *mut i8) {
if !ptr.is_null() {
let _ = CString::from_raw(ptr);
}
}
///
/// # Safety
///
/// This function is designed for deallocating [`ULDDObjResultVec`] created by rust. Trying to deallocating [`ULDDObjResultVec`] created by other languages may result with errors.
///
/// It is null pointer-safe.
///
/// ## Error codes:
/// - 0: No errors
/// - 1: `vec` field of [`ULDDObjResultVec`] is a null pointer
///
#[no_mangle]
pub unsafe extern "C" fn free_obj(obj: ULDDObjResultVec, debugging: bool) -> u8 {
if obj.vec.is_null() {
Debugging::Error("Given object vector is invalid".to_owned()).print(debugging);
Debugging::Error("Deallocation(s) is failed".to_owned()).print(debugging);
return 1;
};
let object_vector = Vec::from_raw_parts(obj.vec, obj.length, obj.capacity);
for (index, object) in object_vector.into_iter().enumerate() {
Debugging::Info(format!("{}. object is being deallocated", index + 1)).print(debugging);
let o = object.obj;
drop_c_string(object.error.explanation);
drop_c_string(o.file_name);
drop_c_string(o.executable_format);
drop_c_string(o.os_type);
drop_c_string(o.file_type);
drop_c_string(o.cpu_type);
drop_c_string(o.cpu_subtype);
drop_c_string(o.interpreter);
if !o.member_name.vec.is_null() {
let member_names = Vec::from_raw_parts(
o.member_name.vec,
o.member_name.length,
o.member_name.capacity,
);
for name in member_names {
drop_c_string(name)
}
};
if !o.libraries.vec.is_null() {
let libraries =
Vec::from_raw_parts(o.libraries.vec, o.libraries.length, o.libraries.capacity);
for library in libraries {
drop_c_string(library)
}
};
Debugging::Affirmative(format!("{}. object is deallocated", index + 1)).print(debugging);
}
Debugging::Affirmative(format!(
"Deallocation(s) is successful. {} object(s) is freed.",
obj.length
))
.print(debugging);
0
}

206
src/mach.rs Executable file
View File

@@ -0,0 +1,206 @@
use crate::{
debug::{debug_objects, find_error_type, merge_members},
structs::{CharVec, Debugging, ParsingError, StringPtr, ULDDObj, ULDDObjResult},
types::{
MachOCpuType, MachOOs, MACH_O_ARM_CPU_SUBTYPE, MACH_O_CPUTYPE, MACH_O_FILE_TYPE,
MACH_O_X86_CPU_SUBTYPE,
},
};
use goblin::mach::{load_command::CommandVariant::BuildVersion, Mach, MachO};
use std::ptr::null_mut;
fn find_os_mach(mach: &MachO<'_>) -> *mut i8 {
for lc in &mach.load_commands {
if let BuildVersion(build_version) = lc.command {
let os = match build_version.platform {
0x01 => MachOOs::MacOS,
0x02 => MachOOs::IOS,
0x03 => MachOOs::AppleTVBox,
0x04 => MachOOs::AppleWatch,
0x05 => MachOOs::BridgeOS,
0x06 => MachOOs::MacCatalyst,
0x07 => MachOOs::IOSSimulator,
0x08 => MachOOs::AppleTVSimulator,
0x09 => MachOOs::AppleWatchSimulator,
0x0A => MachOOs::DriverKit,
0x0B => MachOOs::AppleVisionPro,
0x0C => MachOOs::AppleVisionProSimulator,
_ => return null_mut(),
};
return StringPtr::from(os.to_string()).0;
}
}
null_mut()
}
/*
I will leave it there because I may use later
fn decode_further(mach: &MachO<'_>) {
for lc in &mach.load_commands {
if let BuildVersion(build_version) = lc.command {
let os = match build_version.platform {
0x01 => MachOOs::MacOS,
0x02 => MachOOs::IOS,
0x03 => MachOOs::AppleTVBox,
0x04 => MachOOs::AppleWatch,
0x05 => MachOOs::BridgeOS,
0x06 => MachOOs::MacCatalyst,
0x07 => MachOOs::IOSSimulator,
0x08 => MachOOs::AppleTVSimulator,
0x09 => MachOOs::AppleWatchSimulator,
0x0A => MachOOs::DriverKit,
0x0B => MachOOs::AppleVisionPro,
0x0C => MachOOs::AppleVisionProSimulator,
_ => MachOOs::Undefined,
};
let os_ver = {
let [_, x, y, z] = build_version.minos.to_be_bytes();
format!("{x}.{y}.{z}")
};
let sdk_ver = {
let [_, x, y, z] = build_version.sdk.to_be_bytes();
format!("{x}.{y}.{z}")
};
let tool_type = match build_version.ntools {
0x1 => "Clang",
0x2 => "Swift",
0x3 => "Linked with ld",
_ => "Unknown"
};
}
}
}
*/
pub(crate) fn parse_mach<'a>(
file_name: &'a str,
buffer: &[u8],
mach: Mach,
member_names: &mut Vec<&'a str>,
objects: &mut Vec<ULDDObjResult>,
debugging: bool,
) {
match mach {
Mach::Fat(fat) => {
debug_objects(
file_name,
member_names,
"a multi architecture Mach-O",
debugging,
);
let fat_arches = match fat.arches() {
Ok(arches) => arches,
Err(error) => {
Debugging::Error(format!("Error while reading the multi architecture Mach-O binary named '{}'{}\nDetails:\n{}",
file_name,
merge_members(member_names),
error)).print(debugging);
return objects.push(ULDDObjResult {
error: ParsingError {
code: find_error_type(&error),
explanation: StringPtr::from(error.to_string()).0,
},
obj: ULDDObj {
file_name: StringPtr::from(file_name).0,
member_name: CharVec::from(member_names),
executable_format: StringPtr::from("Mach-O").0,
..Default::default()
},
});
}
};
for (index, arch) in fat_arches.iter().enumerate() {
match MachO::parse(buffer, arch.offset as usize) {
Ok(mach_o) => {
member_names.push(file_name);
objects.push(parse_mach_o(
&format!("{}. file", index + 1),
member_names,
mach_o,
debugging,
))
}
Err(error) => {
Debugging::Error(format!("Error while processing the multi architecture Mach-O binary named '{}'{}\nDetails:\n{}", file_name, merge_members(member_names),
error)).print(debugging);
objects.push(ULDDObjResult {
error: ParsingError {
code: find_error_type(&error),
explanation: StringPtr::from(error.to_string()).0,
},
obj: ULDDObj {
file_name: StringPtr::from(file_name).0,
member_name: CharVec::from(member_names.clone()),
executable_format: StringPtr::from("Mach-O").0,
..Default::default()
},
})
}
}
}
}
Mach::Binary(binary) => {
objects.push(parse_mach_o(file_name, member_names, binary, debugging))
}
}
}
fn parse_mach_o(
file_name: &str,
member_names: &mut Vec<&str>,
mach_o: MachO,
debugging: bool,
) -> ULDDObjResult {
let mut mach_o = mach_o;
let file_type = StringPtr::from(MACH_O_FILE_TYPE.get(&mach_o.header.filetype)).0;
let (cpu_type, cpu_subtype) = {
if let Some(mach_o_cpu_type) = MACH_O_CPUTYPE.get(&mach_o.header.cputype) {
let mach_o_cpu_subtype = {
match mach_o_cpu_type {
MachOCpuType::ARM | MachOCpuType::ARM64 => {
StringPtr::from(MACH_O_ARM_CPU_SUBTYPE.get(&mach_o.header.cpusubtype)).0
}
MachOCpuType::X86 | MachOCpuType::X86_64 => {
StringPtr::from(MACH_O_X86_CPU_SUBTYPE.get(&mach_o.header.cpusubtype)).0
}
_ => null_mut(),
}
};
(
StringPtr::from(mach_o_cpu_type.to_string()).0,
mach_o_cpu_subtype,
)
} else {
(null_mut(), null_mut())
}
};
let is_stripped = !mach_o
.symbols
.as_ref()
.is_some_and(|v| v.iter().any(|s| s.is_ok_and(|(x, _)| x.contains("debug"))));
mach_o.libs.retain(|lib| lib != &"self");
debug_objects(file_name, member_names, "a Mach-O binary", debugging);
ULDDObjResult {
error: ParsingError::default(),
obj: ULDDObj {
file_name: StringPtr::from(file_name).0,
member_name: CharVec::from(member_names),
executable_format: StringPtr::from("Mach-O").0,
is_64: mach_o.is_64,
os_type: find_os_mach(&mach_o),
file_type,
is_stripped,
cpu_type,
cpu_subtype,
interpreter: null_mut(),
libraries: CharVec::from(mach_o.libs),
},
}
}

88
src/pe.rs Executable file
View File

@@ -0,0 +1,88 @@
use crate::{
debug::debug_objects,
structs::{CharVec, ParsingError, StringPtr, ULDDObj, ULDDObjResult},
types::{PeOS, PeSubsystem, PE_ARCH, PE_SUBSYSTEM},
};
use goblin::pe::{characteristic::IMAGE_FILE_DEBUG_STRIPPED, PE};
use std::ptr::null_mut;
fn find_os_pe(pe: &PE<'_>) -> *mut i8 {
let Some(optional_header) = pe
.header
.optional_header
.and_then(|h| PE_SUBSYSTEM.get(&h.windows_fields.subsystem))
else {
return null_mut();
};
let os = match optional_header {
PeSubsystem::Xbox => PeOS::Xbox,
PeSubsystem::EFIApplication
| PeSubsystem::EFIBootServiceDriver
| PeSubsystem::EFIRom
| PeSubsystem::EFIRuntimeDriver => PeOS::UEFI,
PeSubsystem::WindowsCUI
| PeSubsystem::WindowsGUI
| PeSubsystem::Native
| PeSubsystem::OS2CUI
| PeSubsystem::PosixCUI
| PeSubsystem::NativeWindows
| PeSubsystem::WindowsCEGUI
| PeSubsystem::WindowsBootApplication => PeOS::Windows,
PeSubsystem::Unknown => return null_mut(),
};
StringPtr::from(os.to_string()).0
}
pub(crate) fn parse_pe(
file_name: &str,
pe: PE,
member_names: &mut Vec<&str>,
debugging: bool,
) -> ULDDObjResult {
let is_stripped = pe.header.coff_header.characteristics & IMAGE_FILE_DEBUG_STRIPPED
== IMAGE_FILE_DEBUG_STRIPPED;
let cpu_type = StringPtr::from(PE_ARCH.get(&pe.header.coff_header.machine)).0;
let file_type = pe
.header
.optional_header
.and_then(|h| PE_SUBSYSTEM.get(&h.windows_fields.subsystem));
let interpreter = {
if let Some(optional_header) = pe.header.optional_header {
let linker_major_version = optional_header
.windows_fields
.major_operating_system_version;
let linker_minor_version = optional_header
.windows_fields
.minor_operating_system_version;
let linker_version = format!("{}.{}", linker_major_version, linker_minor_version);
StringPtr::from(linker_version).0
} else {
null_mut()
}
};
let executable_format = if pe.is_64 {
debug_objects(file_name, member_names, "a PE32+ binary", debugging);
StringPtr::from("PE32+").0
} else {
debug_objects(file_name, member_names, "a PE32 binary", debugging);
StringPtr::from("PE32").0
};
ULDDObjResult {
error: ParsingError::default(),
obj: ULDDObj {
file_name: StringPtr::from(file_name).0,
member_name: CharVec::from(member_names),
executable_format,
is_64: pe.is_64,
os_type: find_os_pe(&pe),
file_type: StringPtr::from(file_type).0,
is_stripped,
cpu_type,
cpu_subtype: null_mut(),
interpreter,
libraries: CharVec::from(pe.libraries),
},
}
}

111
src/structs.rs Executable file
View File

@@ -0,0 +1,111 @@
use std::ffi::c_char;
/// A C-compatible vector for `Vec<String>`.
#[repr(C)]
pub struct CharVec {
pub capacity: usize,
pub length: usize,
pub vec: *mut *mut c_char,
}
///
/// An error struct for making error handling easy.
///
/// ## Error Codes
/// - \>0: Magic number of the unknown object (as `i64` (or `ìnt64_t))
/// - -1: Binary is corrupted
/// - -2: Unknown/Bad magic number
/// - -3: Error at reading and interpreting bytes
/// - -4: I/O Error at parsing the object
/// - -5: Buffer is too short to hold
/// - -6: Unknown error[^1]
/// - -7: Unimplemented executable format
///
/// [^1]: All errors thrown by goblin crate and my code are covered. Because of matching goblin's [`Error`](goblin::error::Error) is non-exhaustive, I included non-exhaustive path too.
///
#[repr(C)]
pub struct ParsingError {
pub code: i64,
pub explanation: *mut c_char,
}
///
/// A struct contains detailed information about the object.
///
/// It contains some information even the object is an erroneous one to make error handling more verbose.
///
/// If the error occurs on parsing:
/// - A file: `file_name` and `member_name`
/// - A Muti Architecture Mach-O file: `file_name`, `member_name` and `executable_format`
/// - An archive: `file_name`, `member_name` and `file_type`
///
/// fields will be filled correctly and the rest will be:
/// - null (the fields which are string)
/// - blank (`member_name` and `libraries`)
/// - `false` (`is_64` and `is_stripped`).
///
#[repr(C)]
pub struct ULDDObj {
/// The name of the object.
///
/// Objects inside Muti Architecture Mach-O files will be named as "n. file" due to they don't have file names.
pub file_name: *mut c_char,
/// The location of objects in recursive files.
///
/// This field is empty if the object is not in a recursive file (Like: Archives and Muti Architecture Mach-O files).
///
/// The names in the vector is sorted as outer to inner.
pub member_name: CharVec,
/// The type of the executable format of the object.
pub executable_format: *mut c_char,
/// The field is true if the object is 64 bit otherwise it is 32 bit or the object is an erroneous one.
pub is_64: bool,
/// The name of the OS it was compiled for.
pub os_type: *mut c_char,
/// The type of the object.
pub file_type: *mut c_char,
/// The field is true if the object was stripped from debug symbols otherwise it is not stripped or the object is an erroneous one .
pub is_stripped: bool,
/// The ISA (CPU Architecture) the object compiled for.
pub cpu_type: *mut c_char,
/// The specific CPU model the object compiled for.
///
/// macOS only field. It is null pointer in other executable formats.
pub cpu_subtype: *mut c_char,
/// The name/version of the linker.
///
/// ELF/PE only field. It is null pointer in other executable formats.
///
/// It returns the version of the linker in PE files.
pub interpreter: *mut c_char,
/// A vector of libraries linked against the object.
///
/// It is blank in COFF files because they are mostly PE object files therefore they don't have linked libraries against them.
pub libraries: CharVec,
}
/// A struct packs (empty or filled) error and (successfully or not) read object.
#[repr(C)]
pub struct ULDDObjResult {
pub error: ParsingError,
pub obj: ULDDObj,
}
/// A C-compatible vector for [`ULDDObjResult`].
#[repr(C)]
pub struct ULDDObjResultVec {
pub capacity: usize,
pub length: usize,
pub vec: *mut ULDDObjResult,
}
#[doc(hidden)]
pub struct StringPtr(pub *mut i8);
#[doc(hidden)]
pub(crate) enum Debugging {
Info(String),
Affirmative(String),
Error(String),
Fatal(String),
}

897
src/types.rs Executable file
View File

@@ -0,0 +1,897 @@
use phf::phf_map;
use std::fmt::{Display, Formatter, Result as FmtResult};
/*
Source:
https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
https://en.wikipedia.org/wiki/Cell_(processor)
https://en.wikipedia.org/wiki/ETRAX_CRIS
https://developer.fedoraproject.org/deployment/secondary_architectures/s390.html#:~:text=s390%20is%2031%2Dbit%2Daddress,known%20as%20IBM%20System%20z.
https://www.infineon.com/cms/en/product/microcontroller/
*/
/// MP Stands for Microprocessor
/// BPF Stands for Berkeley Packet Filter
#[allow(clippy::upper_case_acronyms)]
#[derive(Debug)]
pub enum ElfInstructionSet {
Undefined,
WE32100,
SPARC,
X86,
M68k,
M88k,
IntelMCU,
I860,
MIPS,
IBMSystem370,
MIPSRS3000Le,
FutureUse,
HPPPRISC,
I960,
PPC,
PPC64,
S390,
S390x,
// Wikipedia or Google doesn't provide healthy info about what IBM SPU/SPC is
IBMSPUSPC,
NECV800,
FR20,
RH32,
MotorolaRCE,
Arm32,
DigitalAlpha,
SuperH,
SPARCVersion9,
SiemensTriCore,
ArgonautRISCCore,
H8300,
H8300H,
H8S,
H8500,
IA64,
StanfordMIPSX,
MotorolaColdFire,
MotorolaM68HC12,
FujitsuMMA,
SiemensPCP,
SonyCellCPU,
DensoNDR1,
MotorolaStarCore,
ToyotaME16,
STMicroelectronicsST100,
AdvancedLogicCorpTinyJ,
X86_64,
SonyDSP,
PDP10,
PDP11,
SiemensFX66,
STMicroelectronicsST9Plus,
STMicroelectronicsST7,
MC68HC16,
MC68HC11,
MC68HC08,
MC68HC05,
SiliconGraphicsSVx,
STMicroelectronicsST19,
DigitalVAX,
ETRAXCRIS,
InfineonTechnologiesMP32,
Element14DSP64,
LSILogicDSP16,
TMS320C6000,
MCSTElbrusE2k,
Arm64,
ZilogZ80,
RISCV,
BPF,
WDC65C816,
}
// Source: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
pub const E_MACHINE: phf::Map<u16, ElfInstructionSet> = phf_map! {
0x00_u16 => ElfInstructionSet::Undefined,
0x01_u16 => ElfInstructionSet::WE32100,
0x02_u16 => ElfInstructionSet::SPARC,
0x03_u16 => ElfInstructionSet::X86,
0x04_u16 => ElfInstructionSet::M68k,
0x05_u16 => ElfInstructionSet::M88k,
0x06_u16 => ElfInstructionSet::IntelMCU,
0x07_u16 => ElfInstructionSet::I860,
0x08_u16 => ElfInstructionSet::MIPS,
0x09_u16 => ElfInstructionSet::IBMSystem370,
0x0A_u16 => ElfInstructionSet::MIPSRS3000Le,
0x0B_u16 => ElfInstructionSet::FutureUse,
0x0C_u16 => ElfInstructionSet::FutureUse,
0x0D_u16 => ElfInstructionSet::FutureUse,
0x0E_u16 => ElfInstructionSet::FutureUse,
0x0F_u16 => ElfInstructionSet::HPPPRISC,
0x13_u16 => ElfInstructionSet::I960,
0x14_u16 => ElfInstructionSet::PPC,
0x15_u16 => ElfInstructionSet::PPC64,
0x16_u16 => ElfInstructionSet::S390,
0x17_u16 => ElfInstructionSet::S390x,
0x18_u16 => ElfInstructionSet::FutureUse,
0x19_u16 => ElfInstructionSet::FutureUse,
0x20_u16 => ElfInstructionSet::FutureUse,
0x21_u16 => ElfInstructionSet::FutureUse,
0x22_u16 => ElfInstructionSet::FutureUse,
0x23_u16 => ElfInstructionSet::FutureUse,
0x24_u16 => ElfInstructionSet::NECV800,
0x25_u16 => ElfInstructionSet::FR20,
0x26_u16 => ElfInstructionSet::RH32,
0x27_u16 => ElfInstructionSet::MotorolaRCE,
0x28_u16 => ElfInstructionSet::Arm32,
0x29_u16 => ElfInstructionSet::DigitalAlpha,
0x2A_u16 => ElfInstructionSet::SuperH,
0x2B_u16 => ElfInstructionSet::SPARCVersion9,
0x2C_u16 => ElfInstructionSet::SiemensTriCore,
0x2D_u16 => ElfInstructionSet::ArgonautRISCCore,
0x2E_u16 => ElfInstructionSet::H8300,
0x2F_u16 => ElfInstructionSet::H8300H,
0x30_u16 => ElfInstructionSet::H8S,
0x31_u16 => ElfInstructionSet::H8500,
0x32_u16 => ElfInstructionSet::IA64,
0x33_u16 => ElfInstructionSet::StanfordMIPSX,
0x34_u16 => ElfInstructionSet::MotorolaColdFire,
0x35_u16 => ElfInstructionSet::MotorolaM68HC12,
0x36_u16 => ElfInstructionSet::FujitsuMMA,
0x37_u16 => ElfInstructionSet::SiemensPCP,
0x38_u16 => ElfInstructionSet::SonyCellCPU,
0x39_u16 => ElfInstructionSet::DensoNDR1,
0x3A_u16 => ElfInstructionSet::MotorolaStarCore,
0x3B_u16 => ElfInstructionSet::ToyotaME16,
0x3C_u16 => ElfInstructionSet::STMicroelectronicsST100,
0x3D_u16 => ElfInstructionSet::AdvancedLogicCorpTinyJ,
0x3E_u16 => ElfInstructionSet::X86_64,
0x3F_u16 => ElfInstructionSet::SonyDSP,
0x40_u16 => ElfInstructionSet::PDP10,
0x41_u16 => ElfInstructionSet::PDP11,
0x42_u16 => ElfInstructionSet::SiemensFX66,
0x43_u16 => ElfInstructionSet::STMicroelectronicsST9Plus,
0x44_u16 => ElfInstructionSet::STMicroelectronicsST7,
0x45_u16 => ElfInstructionSet::MC68HC16,
0x46_u16 => ElfInstructionSet::MC68HC11,
0x47_u16 => ElfInstructionSet::MC68HC08,
0x48_u16 => ElfInstructionSet::MC68HC05,
0x49_u16 => ElfInstructionSet::SiliconGraphicsSVx,
0x4A_u16 => ElfInstructionSet::STMicroelectronicsST19,
0x4B_u16 => ElfInstructionSet::DigitalVAX,
0x4C_u16 => ElfInstructionSet::ETRAXCRIS,
0x4D_u16 => ElfInstructionSet::InfineonTechnologiesMP32,
0x4E_u16 => ElfInstructionSet::Element14DSP64,
0x4F_u16 => ElfInstructionSet::LSILogicDSP16,
0x8C_u16 => ElfInstructionSet::TMS320C6000,
0xAF_u16 => ElfInstructionSet::MCSTElbrusE2k,
0xB7_u16 => ElfInstructionSet::Arm64,
0xDC_u16 => ElfInstructionSet::ZilogZ80,
0xF3_u16 => ElfInstructionSet::RISCV,
0xF7_u16 => ElfInstructionSet::BPF,
0x101_u16 => ElfInstructionSet::WDC65C816,
};
// Source: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
#[allow(clippy::upper_case_acronyms)]
#[derive(Clone, Copy, Debug)]
pub enum ElfOS {
SystemV,
HPUX,
NetBSD,
Linux,
GNUHurd,
Solaris,
AIXMonterey,
IRIX,
FreeBSD,
Tru64,
NovellModesto,
OpenBSD,
OpenVMS,
NonStopKernel,
AROS,
FenixOS,
CloudABI,
OpenVOS,
Illumos,
SerenityOS,
Android,
Undefined,
}
/*
Source:
https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
https://stackoverflow.com/a/49248689
*/
#[derive(Debug)]
pub enum ElfFileType {
Undefined,
Relocatable,
Executable,
SharedObject,
CoreFile,
OsSpecific,
ProcessorSpecific,
}
// Source: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
pub const E_TYPE: phf::Map<u16, ElfFileType> = phf_map! {
0x00_u16 => ElfFileType::Undefined,
0x01_u16 => ElfFileType::Relocatable,
0x02_u16 => ElfFileType::Executable,
0x03_u16 => ElfFileType::SharedObject,
0x04_u16 => ElfFileType::CoreFile,
0xFE00_u16 => ElfFileType::OsSpecific,
0xFEFF_u16 => ElfFileType::OsSpecific,
0xFF00_u16 => ElfFileType::ProcessorSpecific,
0xFFFF_u16 => ElfFileType::ProcessorSpecific,
};
// Source: https://en.wikipedia.org/wiki/Mach-O
#[derive(Debug)]
pub enum MachOCpuType {
VAX,
ROMP,
NS32032,
NS32332,
MC680x0,
X86,
MIPS,
NS32352,
MC98000,
HPPA,
ARM,
MC88000,
SPARC,
I860Be,
I860Le,
RS6000,
PPC,
ARM64,
X86_64,
Unknown,
}
/*
Source:
https://en.wikipedia.org/wiki/Mach-O
https://www.jviotti.com/2021/07/23/a-deep-dive-on-macos-universal-binaries.html
*/
pub const MACH_O_CPUTYPE: phf::Map<u32, MachOCpuType> = phf_map! {
0x01_u32 => MachOCpuType::VAX,
0x02_u32 => MachOCpuType::ROMP,
0x04_u32 => MachOCpuType::NS32032,
0x05_u32 => MachOCpuType::NS32332,
0x06_u32 => MachOCpuType::MC680x0,
0x07_u32 => MachOCpuType::X86,
0x08_u32 => MachOCpuType::MIPS,
0x09_u32 => MachOCpuType::NS32352,
0x0A_u32 => MachOCpuType::MC98000,
0x0B_u32 => MachOCpuType::HPPA,
0x0C_u32 => MachOCpuType::ARM,
0x0D_u32 => MachOCpuType::MC88000,
0x0E_u32 => MachOCpuType::SPARC,
0x0F_u32 => MachOCpuType::I860Be,
0x10_u32 => MachOCpuType::I860Le,
0x11_u32 => MachOCpuType::RS6000,
0x12_u32 => MachOCpuType::PPC,
0x1000007_u32 => MachOCpuType::X86_64,
0x100000C_u32 => MachOCpuType::ARM64,
};
// Source: https://en.wikipedia.org/wiki/Mach-O
#[derive(Debug)]
pub enum MachOArmSubType {
All,
A500ArchOrNewer,
A500OrNewer,
A440OrNewer,
M4OrNewer,
V4TOrNewer,
V6OrNewer,
V5TEJOrNewer,
XScaleOrNewer,
V7OrNewer,
V7FCortexA9OrNewer,
V7SSwiftOrNewer,
V7KKirkwood40OrNewer,
V8OrNewer,
V6MOrNewer,
V7MOrNewer,
V7EMOrNewer,
Unknown,
}
// Source: https://en.wikipedia.org/wiki/Mach-O
pub const MACH_O_ARM_CPU_SUBTYPE: phf::Map<u32, MachOArmSubType> = phf_map! {
0x00_u32 => MachOArmSubType::All,
0x01_u32 => MachOArmSubType::A500ArchOrNewer,
0x02_u32 => MachOArmSubType::A500OrNewer,
0x03_u32 => MachOArmSubType::A440OrNewer,
0x04_u32 => MachOArmSubType::M4OrNewer,
0x05_u32 => MachOArmSubType::V4TOrNewer,
0x06_u32 => MachOArmSubType::V6OrNewer,
0x07_u32 => MachOArmSubType::V5TEJOrNewer,
0x08_u32 => MachOArmSubType::XScaleOrNewer,
0x09_u32 => MachOArmSubType::V7OrNewer,
0x0A_u32 => MachOArmSubType::V7FCortexA9OrNewer,
0x0B_u32 => MachOArmSubType::V7SSwiftOrNewer,
0x0C_u32 => MachOArmSubType::V7KKirkwood40OrNewer,
0x0D_u32 => MachOArmSubType::V8OrNewer,
0x0E_u32 => MachOArmSubType::V6MOrNewer,
0x0F_u32 => MachOArmSubType::V7MOrNewer,
0x10_u32 => MachOArmSubType::V7EMOrNewer,
};
// Source: https://en.wikipedia.org/wiki/Mach-O
#[derive(Debug)]
pub enum MachOX86SubType {
All,
I486OrNewer,
I486SXOrNewer,
PentiumM5OrNewer,
CeleronOrNewer,
CeleronMobile,
Pentium3OrNewer,
Pentium3MOrNewer,
Pentium3XeonOrNewer,
Pentium4OrNewer,
ItaniumOrNewer,
Itanium2OrNewer,
XeonOrNewer,
XeonMPOrNewer,
Undefined,
}
// Source: https://en.wikipedia.org/wiki/Mach-O
pub const MACH_O_X86_CPU_SUBTYPE: phf::Map<u32, MachOX86SubType> = phf_map! {
0x03_u32 => MachOX86SubType::All,
0x04_u32 => MachOX86SubType::I486OrNewer,
0x84_u32 => MachOX86SubType::I486SXOrNewer,
0x56_u32 => MachOX86SubType::PentiumM5OrNewer,
0x67_u32 => MachOX86SubType::CeleronOrNewer,
0x77_u32 => MachOX86SubType::CeleronMobile,
0x08_u32 => MachOX86SubType::Pentium3OrNewer,
0x18_u32 => MachOX86SubType::Pentium3MOrNewer,
0x28_u32 => MachOX86SubType::Pentium3XeonOrNewer,
0x0A_u32 => MachOX86SubType::Pentium4OrNewer,
0x0B_u32 => MachOX86SubType::ItaniumOrNewer,
0x1B_u32 => MachOX86SubType::Itanium2OrNewer,
0x0C_u32 => MachOX86SubType::XeonOrNewer,
0x1C_u32 => MachOX86SubType::XeonMPOrNewer,
};
#[derive(Debug)]
pub enum MachOCpuSubType {
Arm(MachOArmSubType),
X86(MachOX86SubType),
}
// Source: https://en.wikipedia.org/wiki/Mach-O
#[derive(Debug)]
pub enum MachOOs {
MacOS,
IOS,
AppleTVBox,
AppleWatch,
BridgeOS,
MacCatalyst,
IOSSimulator,
AppleTVSimulator,
AppleWatchSimulator,
DriverKit,
AppleVisionPro,
AppleVisionProSimulator,
Undefined,
}
// Source: https://en.wikipedia.org/wiki/Mach-O
pub const MACH_O_OS: phf::Map<u32, MachOOs> = phf_map! {
0x1_u32 => MachOOs::MacOS,
0x2_u32 => MachOOs::IOS,
0x3_u32 => MachOOs::AppleTVBox,
0x4_u32 => MachOOs::AppleWatch,
0x5_u32 => MachOOs::BridgeOS,
0x6_u32 => MachOOs::MacCatalyst,
0x7_u32 => MachOOs::IOSSimulator,
0x8_u32 => MachOOs::AppleTVSimulator,
0x9_u32 => MachOOs::AppleWatchSimulator,
0xA_u32 => MachOOs::DriverKit,
0xB_u32 => MachOOs::AppleVisionPro,
0xC_u32 => MachOOs::AppleVisionProSimulator,
};
// Source: https://en.wikipedia.org/wiki/Mach-O
#[derive(Debug)]
pub enum MachOFileType {
RelocatableObjectFile,
DemandPagedExecutableFile,
FixedVMSharedLibraryFile,
CoreFile,
PreloadedExecutableFile,
DynamicallyBoundSharedLibraryFile,
DynamicLinkEditor,
DynamicallyBoundBundleFile,
SharedLibraryStub,
CompanionFileWithDebugSections,
X86_64Kexts,
ComposedFile,
Undefined,
}
// Source: https://en.wikipedia.org/wiki/Mach-O
pub const MACH_O_FILE_TYPE: phf::Map<u32, MachOFileType> = phf_map! {
0x1_u32 => MachOFileType::RelocatableObjectFile,
0x2_u32 => MachOFileType::DemandPagedExecutableFile,
0x3_u32 => MachOFileType::FixedVMSharedLibraryFile,
0x4_u32 => MachOFileType::CoreFile,
0x5_u32 => MachOFileType::PreloadedExecutableFile,
0x6_u32 => MachOFileType::DynamicallyBoundSharedLibraryFile,
0x7_u32 => MachOFileType::DynamicLinkEditor,
0x8_u32 => MachOFileType::DynamicallyBoundBundleFile,
0x9_u32 => MachOFileType::SharedLibraryStub,
0xA_u32 => MachOFileType::CompanionFileWithDebugSections,
0xB_u32 => MachOFileType::X86_64Kexts,
0xC_u32 => MachOFileType::ComposedFile,
};
// Source: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format
#[derive(Debug)]
pub enum PeArch {
Unknown,
AlphaAXP32,
AlphaAXP64,
MatsushitaAM33,
X64,
ARM,
ARM64,
ARMNT,
AXP64,
EBC,
I386,
IA64,
LoongArch32,
LoongArch64,
MitsubishiM32R,
MIPS16,
MIPSFPU,
MIPSFPU16,
PowerPC,
PowerPCFP,
MIPS,
RISCV32,
RISCV64,
RISCV128,
HitachiSH3,
HitachiSH3DSP,
HitachiSH4,
HitachiSH5,
Thumb,
MIPSWCE,
}
// Source: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format
pub const PE_ARCH: phf::Map<u16, PeArch> = phf_map! {
0x0000_u16 => PeArch::Unknown,
0x0184_u16 => PeArch::AlphaAXP32,
0x0284_u16 => PeArch::AlphaAXP64,
0x01d3_u16 => PeArch::MatsushitaAM33,
0x8664_u16 => PeArch::X64,
0x01c0_u16 => PeArch::ARM,
0xaa64_u16 => PeArch::ARM64,
0x01c4_u16 => PeArch::ARMNT,
// Look at source to learn why there is a duplicate value
//0x0284_u16 => PeArch::AXP64,
0xebc_u16 => PeArch::EBC,
0x014c_u16 => PeArch::I386,
0x0200_u16 => PeArch::IA64,
0x6232_u16 => PeArch::LoongArch32,
0x6264_u16 => PeArch::LoongArch64,
0x9041_u16 => PeArch::MitsubishiM32R,
0x0266_u16 => PeArch::MIPS16,
0x0366_u16 => PeArch::MIPSFPU,
0x0466_u16 => PeArch::MIPSFPU16,
0x01f0_u16 => PeArch::PowerPC,
0x01f1_u16 => PeArch::PowerPCFP,
0x0166_u16 => PeArch::MIPS,
0x5032_u16 => PeArch::RISCV32,
0x5064_u16 => PeArch::RISCV64,
0x5128_u16 => PeArch::RISCV128,
0x01a2_u16 => PeArch::HitachiSH3,
0x01a3_u16 => PeArch::HitachiSH3DSP,
0x01a6_u16 => PeArch::HitachiSH4,
0x01a8_u16 => PeArch::HitachiSH5,
0x01c2_u16 => PeArch::Thumb,
0x0169_u16 => PeArch::MIPSWCE,
};
// Source: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format
#[derive(Debug)]
pub enum PeSubsystem {
Unknown,
Native,
WindowsGUI,
WindowsCUI,
OS2CUI,
PosixCUI,
NativeWindows,
WindowsCEGUI,
EFIApplication,
EFIBootServiceDriver,
EFIRuntimeDriver,
EFIRom,
Xbox,
WindowsBootApplication,
}
// Source: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format
pub const PE_SUBSYSTEM: phf::Map<u16, PeSubsystem> = phf_map! {
0x0000_u16 => PeSubsystem::Unknown,
0x0001_u16 => PeSubsystem::Native,
0x0002_u16 => PeSubsystem::WindowsGUI,
0x0003_u16 => PeSubsystem::WindowsCUI,
0x0005_u16 => PeSubsystem::OS2CUI,
0x0007_u16 => PeSubsystem::PosixCUI,
0x0008_u16 => PeSubsystem::NativeWindows,
0x0009_u16 => PeSubsystem::WindowsCEGUI,
0x000A_u16 => PeSubsystem::EFIApplication,
0x000B_u16 => PeSubsystem::EFIBootServiceDriver,
0x000C_u16 => PeSubsystem::EFIRuntimeDriver,
0x000D_u16 => PeSubsystem::EFIRom,
0x000E_u16 => PeSubsystem::Xbox,
0x0010_u16 => PeSubsystem::WindowsBootApplication,
};
#[derive(Debug)]
pub enum PeOS {
Xbox,
Windows,
UEFI,
Undefined,
}
// Source of the names: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
impl Display for ElfOS {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
ElfOS::SystemV => write!(f, "System V"),
ElfOS::HPUX => write!(f, "HP-UX"),
ElfOS::NetBSD => write!(f, "NetBSD"),
ElfOS::Linux => write!(f, "Linux"),
ElfOS::GNUHurd => write!(f, "GNU Hurd"),
ElfOS::Solaris => write!(f, "Solaris"),
ElfOS::AIXMonterey => write!(f, "AIX (Monterey)"),
ElfOS::IRIX => write!(f, "IRIX"),
ElfOS::FreeBSD => write!(f, "FreeBSD"),
ElfOS::Tru64 => write!(f, "Tru64"),
ElfOS::NovellModesto => write!(f, "Novell Modesto"),
ElfOS::OpenBSD => write!(f, "OpenBSD"),
ElfOS::OpenVMS => write!(f, "OpenVMS"),
ElfOS::NonStopKernel => write!(f, "NonStop Kernel"),
ElfOS::AROS => write!(f, "AROS"),
ElfOS::FenixOS => write!(f, "FenixOS"),
ElfOS::CloudABI => write!(f, "Nuxi CloudABI"),
ElfOS::OpenVOS => write!(f, "OpenVOS"),
ElfOS::Illumos => write!(f, "Illumos"),
ElfOS::SerenityOS => write!(f, "SerenityOS"),
ElfOS::Android => write!(f, "Android"),
ElfOS::Undefined => write!(f, "Undefined"),
}
}
}
// Source of the names: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
impl Display for ElfInstructionSet {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
ElfInstructionSet::Undefined => write!(f, "Undefined"), //0x00 no specific instruction set is defined
ElfInstructionSet::WE32100 => write!(f, "AT&T WE 32100"),
ElfInstructionSet::SPARC => write!(f, "SPARC"),
ElfInstructionSet::X86 => write!(f, "x86"),
ElfInstructionSet::M68k => write!(f, "Motorola 68000 (M68k)"),
ElfInstructionSet::M88k => write!(f, "Motorola 88000 (M88k)"),
ElfInstructionSet::IntelMCU => write!(f, "Intel MCU"),
ElfInstructionSet::I860 => write!(f, "Intel 80860"),
ElfInstructionSet::MIPS => write!(f, "MIPS"),
ElfInstructionSet::IBMSystem370 => write!(f, "IBM System/370"),
ElfInstructionSet::MIPSRS3000Le => write!(f, "MIPS RS3000 (Little-endian)"),
ElfInstructionSet::FutureUse => write!(f, "Reserved for future use"),
ElfInstructionSet::HPPPRISC => write!(f, "HP PA-RISC"),
ElfInstructionSet::I960 => write!(f, "Intel 80960"),
ElfInstructionSet::PPC => write!(f, "PowerPC"),
ElfInstructionSet::PPC64 => write!(f, "PowerPC (64-Bit)"),
ElfInstructionSet::S390 => write!(f, "S390"),
ElfInstructionSet::S390x => write!(f, "S390x"),
ElfInstructionSet::NECV800 => write!(f, "NEC V800"),
ElfInstructionSet::FR20 => write!(f, "Fujitsu FR20"),
ElfInstructionSet::RH32 => write!(f, "TRW RH-32"),
ElfInstructionSet::MotorolaRCE => write!(f, "Motorola RCE"),
ElfInstructionSet::Arm32 => write!(f, "Arm (32-Bit)"),
ElfInstructionSet::DigitalAlpha => write!(f, "Digital Alpha"),
ElfInstructionSet::SuperH => write!(f, "SuperH"),
ElfInstructionSet::SPARCVersion9 => write!(f, "SPARC version 9"),
ElfInstructionSet::SiemensTriCore => write!(f, "Siemens TriCore"),
ElfInstructionSet::ArgonautRISCCore => write!(f, "Argonaut RISC Core"),
ElfInstructionSet::H8300 => write!(f, "Hitachi H8/300"),
ElfInstructionSet::H8300H => write!(f, "Hitachi H8/300H"),
ElfInstructionSet::H8S => write!(f, "Hitachi H8S"),
ElfInstructionSet::H8500 => write!(f, "Hitachi H8/500"),
ElfInstructionSet::IA64 => write!(f, "Intel Itanium"),
ElfInstructionSet::StanfordMIPSX => write!(f, "Stanford MIPS-X"),
ElfInstructionSet::MotorolaColdFire => write!(f, "Motorola ColdFire"),
ElfInstructionSet::MotorolaM68HC12 => write!(f, "Motorola M68HC12"),
ElfInstructionSet::FujitsuMMA => write!(f, "Fujitsu MMA multimedia accelerator"),
ElfInstructionSet::SiemensPCP => write!(f, "Siemens PCP"),
ElfInstructionSet::SonyCellCPU => write!(f, "Sony nCPU Embedded RISC"),
ElfInstructionSet::DensoNDR1 => write!(f, "Denso NDR1"),
ElfInstructionSet::MotorolaStarCore => write!(f, "Motorola Star*Core"),
ElfInstructionSet::ToyotaME16 => write!(f, "Toyota ME16"),
ElfInstructionSet::STMicroelectronicsST100 => {
write!(f, "STMicroelectronics ST100")
}
ElfInstructionSet::AdvancedLogicCorpTinyJ => {
write!(f, "Advanced Logic Corp. TinyJ")
}
ElfInstructionSet::X86_64 => write!(f, "x86-64"),
ElfInstructionSet::SonyDSP => write!(f, "Sony DSP processor"),
ElfInstructionSet::PDP10 => write!(f, "Digital Equipment Corp. PDP-10"),
ElfInstructionSet::PDP11 => write!(f, "Digital Equipment Corp. PDP-11"),
ElfInstructionSet::SiemensFX66 => write!(f, "Siemens FX66 microcontroller"),
ElfInstructionSet::STMicroelectronicsST9Plus => {
write!(f, "STMicroelectronics ST9+ 8/16-Bit microcontroller")
}
ElfInstructionSet::STMicroelectronicsST7 => {
write!(f, "STMicroelectronics ST7 8-Bit microcontroller")
}
ElfInstructionSet::MC68HC16 => write!(f, "Motorola MC68HC16 microcontroller"),
ElfInstructionSet::MC68HC11 => write!(f, "Motorola MC68HC11 microcontroller"),
ElfInstructionSet::MC68HC08 => write!(f, "Motorola MC68HC08 microcontroller"),
ElfInstructionSet::MC68HC05 => write!(f, "Motorola MC68HC05 microcontroller"),
ElfInstructionSet::SiliconGraphicsSVx => write!(f, "Silicon Graphics SVx"),
ElfInstructionSet::STMicroelectronicsST19 => {
write!(f, "STMicroelectronics ST19 8-Bit microcontroller")
}
ElfInstructionSet::DigitalVAX => write!(f, "Digital VAX"),
ElfInstructionSet::ETRAXCRIS => {
write!(f, "Axis Communications (32-Bit) embedded processor")
}
ElfInstructionSet::InfineonTechnologiesMP32 => {
write!(f, "Infineon Technologies (32-Bit) embedded processor")
}
ElfInstructionSet::Element14DSP64 => write!(f, "Element 14 (64-Bit) DSP processor"),
ElfInstructionSet::LSILogicDSP16 => write!(f, "LSI Logic 16-Bit DSP processor"),
ElfInstructionSet::TMS320C6000 => write!(f, "TMS320C6000 family"),
ElfInstructionSet::MCSTElbrusE2k => write!(f, "MCST Elbrus e2k"),
ElfInstructionSet::Arm64 => write!(f, "Arm (64-Bit)"),
ElfInstructionSet::ZilogZ80 => write!(f, "Zilog Z80"),
ElfInstructionSet::RISCV => write!(f, "RISC-V"),
ElfInstructionSet::BPF => write!(f, "Berkeley packet filter"),
ElfInstructionSet::IBMSPUSPC => write!(f, "IBM SPU/SPC"),
ElfInstructionSet::WDC65C816 => write!(f, "WDC 65C816"),
}
}
}
/*
Sources:
https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
https://refspecs.linuxbase.org/elf/gabi4+/ch4.intro.html
*/
impl Display for ElfFileType {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
ElfFileType::Undefined => write!(f, "Undefined"),
ElfFileType::Relocatable => write!(f, "Object file"),
ElfFileType::Executable => write!(f, "Executable"),
ElfFileType::SharedObject => write!(f, "Shared object"),
ElfFileType::CoreFile => write!(f, "Core file"),
// I couldn't get healthy info. about "OS/CPU specific"
ElfFileType::OsSpecific => write!(f, "OS-specific"),
ElfFileType::ProcessorSpecific => write!(f, "CPU-specific"),
}
}
}
// Source: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format
impl Display for PeArch {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
PeArch::Unknown => write!(f, "Unknown"),
PeArch::AlphaAXP32 => write!(f, "Alpha AXP (32-Bit)"),
PeArch::AlphaAXP64 | PeArch::AXP64 => write!(f, "Alpha 64 (64-Bit)"),
PeArch::MatsushitaAM33 => write!(f, "Matsushita AM33"),
PeArch::X64 => write!(f, "x64"),
PeArch::ARM => write!(f, "Arm"),
PeArch::ARM64 => write!(f, "Arm (64-Bit)"),
PeArch::ARMNT => write!(f, "ARM Thumb-2"),
PeArch::EBC => write!(f, "EFI bytecode"),
PeArch::I386 => write!(f, "Intel 386"),
PeArch::IA64 => write!(f, "Intel Itanium"),
PeArch::LoongArch32 => write!(f, "LoongArch (32-Bit)"),
PeArch::LoongArch64 => write!(f, "LoongArch (64-Bit)"),
PeArch::MitsubishiM32R => write!(f, "Mitsubishi M32R"),
PeArch::MIPS16 => write!(f, "MIPS16"),
PeArch::MIPSFPU => write!(f, "MIPS with FPU"),
PeArch::MIPSFPU16 => write!(f, "MIPS16 with FPU"),
PeArch::PowerPC => write!(f, "PowerPC"),
PeArch::PowerPCFP => write!(f, "PowerPC with floating point support"),
PeArch::MIPS => write!(f, "MIPS"),
PeArch::RISCV32 => write!(f, "RISC-V (32-Bit)"),
PeArch::RISCV64 => write!(f, "RISC-V (64-Bit)"),
PeArch::RISCV128 => write!(f, "RISC-V 128-Bit"),
PeArch::HitachiSH3 => write!(f, "Hitachi SH3"),
PeArch::HitachiSH3DSP => write!(f, "Hitachi SH3 DSP"),
PeArch::HitachiSH4 => write!(f, "Hitachi SH4"),
PeArch::HitachiSH5 => write!(f, "Hitachi SH5"),
PeArch::Thumb => write!(f, "Thumb"),
PeArch::MIPSWCE => write!(f, "MIPS (Little-endian) WCE v2"),
}
}
}
/*
Sources:
https://learn.microsoft.com/en-us/windows/win32/debug/pe-format
CLI != CUI: https://github.com/avelino/awesome-go/issues/282#issuecomment-73395067
*/
impl Display for PeSubsystem {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
PeSubsystem::Unknown => write!(f, "Undefined"),
PeSubsystem::Native => write!(f, "Device drivers and native windows processes"),
PeSubsystem::WindowsGUI => write!(f, "GUI application"),
PeSubsystem::WindowsCUI => write!(f, "Windows CUI application"),
PeSubsystem::OS2CUI => write!(f, "OS/2 CUI application"),
PeSubsystem::PosixCUI => write!(f, "Posix CUI application"),
PeSubsystem::NativeWindows => write!(f, "Native Win9x driver"),
PeSubsystem::WindowsCEGUI => write!(f, "Windows CE application"),
PeSubsystem::EFIApplication => write!(f, "EFI application"),
PeSubsystem::EFIBootServiceDriver => write!(f, "EFI driver with boot services"),
PeSubsystem::EFIRuntimeDriver => write!(f, "EFI driver with runtime services"),
PeSubsystem::EFIRom => write!(f, "EFI ROM image"),
PeSubsystem::Xbox => write!(f, "XBOX"),
PeSubsystem::WindowsBootApplication => write!(f, "Windows boot application."),
}
}
}
// Source: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format
impl Display for PeOS {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
PeOS::Xbox => write!(f, "Xbox"),
PeOS::Windows => write!(f, "Windows"),
PeOS::UEFI => write!(f, "UEFI"),
PeOS::Undefined => write!(f, "Undefined"),
}
}
}
// Source: https://en.wikipedia.org/wiki/Mach-O
impl Display for MachOArmSubType {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
MachOArmSubType::All => write!(f, "All ARM processors"),
MachOArmSubType::A500ArchOrNewer => write!(f, "ARM-A500 ARCH or newer"),
MachOArmSubType::A500OrNewer => write!(f, "ARM-A500 or newer"),
MachOArmSubType::A440OrNewer => write!(f, "ARM-A440 or newer"),
MachOArmSubType::M4OrNewer => write!(f, "ARM-M4 or newer"),
MachOArmSubType::V4TOrNewer => write!(f, "ARM-V4T or newer"),
MachOArmSubType::V6OrNewer => write!(f, "ARM-V6 or newer"),
MachOArmSubType::V5TEJOrNewer => write!(f, "ARM-V5TEJ or newer"),
MachOArmSubType::XScaleOrNewer => write!(f, "ARM-XSCALE or newer"),
MachOArmSubType::V7OrNewer => write!(f, "ARM-V7 or newer"),
MachOArmSubType::V7FCortexA9OrNewer => write!(f, "ARM-V7F (Cortex A9) or newer"),
MachOArmSubType::V7SSwiftOrNewer => write!(f, "ARM-V7S (Swift) or newer"),
MachOArmSubType::V7KKirkwood40OrNewer => write!(f, "ARM-V7K (Kirkwood40) or newer"),
MachOArmSubType::V8OrNewer => write!(f, "ARM-V8 or newer"),
MachOArmSubType::V6MOrNewer => write!(f, "ARM-V6M or newer"),
MachOArmSubType::V7MOrNewer => write!(f, "ARM-V7M or newer"),
MachOArmSubType::V7EMOrNewer => write!(f, "ARM-V7EM or newer"),
MachOArmSubType::Unknown => write!(f, "Unknown"),
}
}
}
// Source: https://en.wikipedia.org/wiki/Mach-O
impl Display for MachOX86SubType {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
MachOX86SubType::All => write!(f, "All x86 processors"),
MachOX86SubType::I486OrNewer => write!(f, "486 or newer"),
MachOX86SubType::I486SXOrNewer => write!(f, "486SX or newer"),
MachOX86SubType::PentiumM5OrNewer => write!(f, "Pentium M5 or newer"),
MachOX86SubType::CeleronOrNewer => write!(f, "Celeron or newer"),
MachOX86SubType::CeleronMobile => write!(f, "Celeron Mobile"),
MachOX86SubType::Pentium3OrNewer => write!(f, "Pentium 3 or newer"),
MachOX86SubType::Pentium3MOrNewer => write!(f, "Pentium 3-M or newer"),
MachOX86SubType::Pentium3XeonOrNewer => write!(f, "Pentium 3-XEON or newer"),
MachOX86SubType::Pentium4OrNewer => write!(f, "Pentium-4 or newer"),
MachOX86SubType::ItaniumOrNewer => write!(f, "Itanium or newer"),
MachOX86SubType::Itanium2OrNewer => write!(f, "Itanium-2 or newer"),
MachOX86SubType::XeonOrNewer => write!(f, "XEON or newer"),
MachOX86SubType::XeonMPOrNewer => write!(f, "XEON-MP or newer"),
MachOX86SubType::Undefined => write!(f, "Undefined"),
}
}
}
// Source: https://en.wikipedia.org/wiki/Mach-O
impl Display for MachOCpuSubType {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
MachOCpuSubType::Arm(arm) => write!(f, "{}", arm),
MachOCpuSubType::X86(x86) => write!(f, "{}", x86),
}
}
}
// Source: https://en.wikipedia.org/wiki/Mach-O
impl Display for MachOCpuType {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
MachOCpuType::VAX => write!(f, "VAX"),
MachOCpuType::ROMP => write!(f, "ROMP"),
MachOCpuType::NS32032 => write!(f, "NS32032"),
MachOCpuType::NS32332 => write!(f, "NS32332"),
MachOCpuType::MC680x0 => write!(f, "MC680x0"),
MachOCpuType::X86 => write!(f, "x86"),
MachOCpuType::MIPS => write!(f, "MIPS"),
MachOCpuType::NS32352 => write!(f, "NS32352"),
MachOCpuType::MC98000 => write!(f, "MC98000"),
MachOCpuType::HPPA => write!(f, "HP-PA"),
MachOCpuType::ARM => write!(f, "ARM"),
MachOCpuType::MC88000 => write!(f, "MC88000"),
MachOCpuType::SPARC => write!(f, "SPARC"),
MachOCpuType::I860Be => write!(f, "i860 (Big-endian)"),
MachOCpuType::I860Le => write!(f, "i860 (Little-endian)"),
MachOCpuType::RS6000 => write!(f, "RS/6000"),
MachOCpuType::PPC => write!(f, "PowerPC"),
MachOCpuType::ARM64 => write!(f, "ARM64"),
MachOCpuType::X86_64 => write!(f, "x86_64"),
MachOCpuType::Unknown => write!(f, "Unknown"),
}
}
}
// Source: https://en.wikipedia.org/wiki/Mach-O
impl Display for MachOFileType {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
MachOFileType::RelocatableObjectFile => write!(f, "Object file"),
MachOFileType::DemandPagedExecutableFile => write!(f, "Executable"),
MachOFileType::FixedVMSharedLibraryFile => write!(f, "Fixed VM shared library file"),
MachOFileType::CoreFile => write!(f, "Core file"),
MachOFileType::PreloadedExecutableFile => write!(f, "Preloaded executable file"),
MachOFileType::DynamicallyBoundSharedLibraryFile => write!(f, "Shared object"),
MachOFileType::DynamicLinkEditor => write!(f, "Dynamic link editor"),
MachOFileType::DynamicallyBoundBundleFile => write!(f, "Dynamically bound bundle file"),
MachOFileType::SharedLibraryStub => write!(f, "Shared library stub for static linking only, no section contents"),
MachOFileType::CompanionFileWithDebugSections => write!(f, "Companion file with only debug sections"),
MachOFileType::X86_64Kexts => write!(f, "x86_64 kext"),
MachOFileType::ComposedFile => write!(f, "File composed of other Mach-Os to be run in the same userspace sharing a single linkedit"),
MachOFileType::Undefined => write!(f, "Undefined"),
}
}
}
// Source: https://en.wikipedia.org/wiki/Mach-O
impl Display for MachOOs {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
MachOOs::MacOS => write!(f, "MacOS"),
MachOOs::IOS => write!(f, "IOS"),
MachOOs::AppleTVBox => write!(f, "Apple TV Box"),
MachOOs::AppleWatch => write!(f, "Apple Watch"),
MachOOs::BridgeOS => write!(f, "Bridge OS"),
MachOOs::MacCatalyst => write!(f, "Mac Catalyst"),
MachOOs::IOSSimulator => write!(f, "IOS simulator"),
MachOOs::AppleTVSimulator => write!(f, "Apple TV simulator"),
MachOOs::AppleWatchSimulator => write!(f, "Apple watch simulator"),
MachOOs::DriverKit => write!(f, "Driver KIT"),
MachOOs::AppleVisionPro => write!(f, "Apple Vision Pro"),
MachOOs::AppleVisionProSimulator => write!(f, "Apple Vision Pro simulator"),
MachOOs::Undefined => write!(f, "Undefined"),
}
}
}