Files
unildd/src/mach.rs
*Nix Fanboy 96beb607c9 Further Small Fixes
- Some improvements which is same as what has been made in the former commit has made
2024-10-25 15:32:11 +03:00

210 lines
7.5 KiB
Rust

use std::ffi::c_char;
use crate::{
debug::{debug_objects, merge_members},
structs::{CharVec, Debugging, ParsingError, 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;
use crate::debug::option_to_c_string;
use crate::impls::{ErrorToInt, StringToCString};
fn find_os_mach(mach: &MachO<'_>) -> *mut c_char {
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 os.to_c_string();
}
}
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: error.to_int(),
explanation: error.to_c_string(),
},
obj: ULDDObj {
file_name: file_name.to_c_string(),
member_name: CharVec::from(member_names),
executable_format: "Mach-O".to_c_string(),
..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: error.to_int(),
explanation: error.to_c_string(),
},
obj: ULDDObj {
file_name: file_name.to_c_string(),
member_name: CharVec::from(member_names.clone()),
executable_format: "Mach-O".to_c_string(),
..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 = option_to_c_string(MACH_O_FILE_TYPE.get(&mach_o.header.filetype));
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 => {
option_to_c_string(MACH_O_ARM_CPU_SUBTYPE.get(&mach_o.header.cpusubtype))
}
MachOCpuType::X86 | MachOCpuType::X86_64 => {
option_to_c_string(MACH_O_X86_CPU_SUBTYPE.get(&mach_o.header.cpusubtype))
}
_ => null_mut(),
}
};
(
mach_o_cpu_type.to_c_string(),
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: file_name.to_c_string(),
member_name: CharVec::from(member_names),
executable_format: "Mach-O".to_c_string(),
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),
},
}
}