use crate::error;
use core::fmt::{self, Display};
use scroll::{ctx, Endian};
use scroll::{Pread, Pwrite, IOread, IOwrite, SizeWith};
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, SizeWith)]
pub struct LoadCommandHeader {
pub cmd: u32,
pub cmdsize: u32,
}
impl Display for LoadCommandHeader {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "LoadCommandHeader: {} size: {}", cmd_to_str(self.cmd), self.cmdsize)
}
}
pub const SIZEOF_LOAD_COMMAND: usize = 8;
pub type LcStr = u32;
pub const SIZEOF_LC_STR: usize = 4;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct Section32 {
pub sectname: [u8; 16],
pub segname: [u8; 16],
pub addr: u32,
pub size: u32,
pub offset: u32,
pub align: u32,
pub reloff: u32,
pub nreloc: u32,
pub flags: u32,
pub reserved1: u32,
pub reserved2: u32,
}
pub const SIZEOF_SECTION_32: usize = 68;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct Section64 {
pub sectname: [u8; 16],
pub segname: [u8; 16],
pub addr: u64,
pub size: u64,
pub offset: u32,
pub align: u32,
pub reloff: u32,
pub nreloc: u32,
pub flags: u32,
pub reserved1: u32,
pub reserved2: u32,
pub reserved3: u32,
}
pub const SIZEOF_SECTION_64: usize = 80;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct SegmentCommand32 {
pub cmd: u32,
pub cmdsize: u32,
pub segname: [u8; 16],
pub vmaddr: u32,
pub vmsize: u32,
pub fileoff: u32,
pub filesize: u32,
pub maxprot: u32,
pub initprot: u32,
pub nsects: u32,
pub flags: u32,
}
pub const SIZEOF_SEGMENT_COMMAND_32: usize = 56;
impl SegmentCommand32 {
pub fn name(&self) -> error::Result<&str> {
Ok(self.segname.pread::<&str>(0)?)
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct SegmentCommand64 {
pub cmd: u32,
pub cmdsize: u32,
pub segname: [u8; 16],
pub vmaddr: u64,
pub vmsize: u64,
pub fileoff: u64,
pub filesize: u64,
pub maxprot: u32,
pub initprot: u32,
pub nsects: u32,
pub flags: u32,
}
pub const SIZEOF_SEGMENT_COMMAND_64: usize = 72;
impl SegmentCommand64 {
pub fn name(&self) -> error::Result<&str> {
Ok(self.segname.pread::<&str>(0)?)
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct Fvmlib {
pub name: u32,
pub minor_version: u32,
pub header_addr: u32,
}
pub const SIZEOF_FVMLIB: usize = 12;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct FvmlibCommand {
pub cmd: u32,
pub cmdsize: u32,
pub fvmlib: Fvmlib,
}
pub const SIZEOF_FVMLIB_COMMAND: usize = 20;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct Dylib {
pub name: LcStr,
pub timestamp: u32,
pub current_version: u32,
pub compatibility_version: u32,
}
pub const SIZEOF_DYLIB: usize = 16;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct DylibCommand {
pub cmd: u32,
pub cmdsize: u32,
pub dylib: Dylib,
}
pub const SIZEOF_DYLIB_COMMAND: usize = 20;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct SubFrameworkCommand {
pub cmd: u32,
pub cmdsize: u32,
pub umbrella: u32,
}
pub const SIZEOF_SUB_FRAMEWORK_COMMAND: usize = 12;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct SubClientCommand {
pub cmd: u32,
pub cmdsize: u32,
pub client: LcStr,
}
pub const SIZEOF_SUB_CLIENT_COMMAND: usize = 12;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct SubUmbrellaCommand {
pub cmd: u32,
pub cmdsize: u32,
pub sub_umbrella: LcStr,
}
pub const SIZEOF_SUB_UMBRELLA_COMMAND: usize = 12;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct SubLibraryCommand {
pub cmd: u32,
pub cmdsize: u32,
pub sub_library: LcStr,
}
pub const SIZEOF_SUB_LIBRARY_COMMAND: usize = 12;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct PreboundDylibCommand {
pub cmd: u32,
pub cmdsize: u32,
pub name: LcStr,
pub nmodules: u32,
pub linked_modules: LcStr,
}
pub const SIZEOF_PREBOUND_DYLIB_COMMAND: usize = 20;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct DylinkerCommand {
pub cmd: u32,
pub cmdsize: u32,
pub name: LcStr,
}
pub const SIZEOF_DYLINKER_COMMAND: usize = 12;
#[repr(C)]
#[derive(Copy)]
pub struct ThreadCommand {
pub cmd: u32,
pub cmdsize: u32,
pub flavor: u32,
pub count: u32,
pub thread_state: [u32; 70],
}
impl ThreadCommand {
pub fn instruction_pointer(&self, cputype: super::cputype::CpuType) -> error::Result<u64> {
match cputype {
super::cputype::CPU_TYPE_X86 => {
let eip: u32 = self.thread_state[10];
Ok(u64::from(eip))
},
super::cputype::CPU_TYPE_X86_64 => {
let rip: u64 =
(u64::from(self.thread_state[32]))
| ((u64::from(self.thread_state[33])) << 32);
Ok(rip)
}
super::cputype::CPU_TYPE_ARM => {
let pc: u32 = self.thread_state[15];
Ok(u64::from(pc))
}
super::cputype::CPU_TYPE_ARM64 | super::cputype::CPU_TYPE_ARM64_32 => {
let pc: u64 =
(u64::from(self.thread_state[64]))
| ((u64::from(self.thread_state[65])) << 32);
Ok(pc)
}
super::cputype::CPU_TYPE_POWERPC => {
Ok(u64::from(self.thread_state[0]))
},
_ => {
Err(error::Error::Malformed(format!("unable to find instruction pointer for cputype {:?}", cputype)))
}
}
}
}
impl<'a> ctx::TryFromCtx<'a, Endian> for ThreadCommand {
type Error = crate::error::Error;
fn try_from_ctx(bytes: &'a [u8], le: Endian) -> error::Result<(Self, usize)> {
let lc = bytes.pread_with::<LoadCommandHeader>(0, le)?;
let flavor: u32 = bytes.pread_with(8, le)?;
let count: u32 = bytes.pread_with(12, le)?;
let thread_state_byte_length = count as usize * 4;
let thread_state_bytes = &bytes[16..16+thread_state_byte_length];
if thread_state_bytes.len() < thread_state_byte_length {
return Err(error::Error::Malformed(format!("thread command specifies {} bytes for thread state but has only {}", thread_state_byte_length, thread_state_bytes.len())));
}
if count > 70 {
return Err(error::Error::Malformed(format!("thread command specifies {} longs for thread state but we handle only 70", count)));
}
let mut thread_state: [u32; 70] = [ 0; 70 ];
for (i, state) in thread_state.iter_mut().enumerate().take(count as usize) {
*state = thread_state_bytes.pread_with(i*4, le)?;
}
Ok((ThreadCommand{
cmd: lc.cmd,
cmdsize: lc.cmdsize,
flavor,
count,
thread_state,
}, lc.cmdsize as _))
}
}
impl Clone for ThreadCommand {
fn clone(&self) -> Self {
*self
}
}
impl fmt::Debug for ThreadCommand {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("ThreadCommand")
.field("cmd", &self.cmd)
.field("cmdsize", &self.cmdsize)
.field("flavor", &self.flavor)
.field("count", &self.count)
.field("thread_state", &&self.thread_state[..])
.finish()
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct RoutinesCommand32 {
pub cmd: u32,
pub cmdsize: u32,
pub init_address:u32,
pub init_module: u32,
pub reserved1: u32,
pub reserved2: u32,
pub reserved3: u32,
pub reserved4: u32,
pub reserved5: u32,
pub reserved6: u32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct RoutinesCommand64 {
pub cmd: u32,
pub cmdsize: u32,
pub init_address: u64,
pub init_module: u64,
pub reserved1: u64,
pub reserved2: u64,
pub reserved3: u64,
pub reserved4: u64,
pub reserved5: u64,
pub reserved6: u64,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct SymtabCommand {
pub cmd: u32,
pub cmdsize: u32,
pub symoff: u32,
pub nsyms: u32,
pub stroff: u32,
pub strsize: u32,
}
impl Default for SymtabCommand {
fn default() -> Self {
SymtabCommand {
cmd: LC_SYMTAB,
cmdsize: SIZEOF_SYMTAB_COMMAND as u32,
symoff: 0,
nsyms: 0,
stroff: 0,
strsize: 0,
}
}
}
impl SymtabCommand {
pub fn new() -> Self {
Default::default()
}
}
pub const SIZEOF_SYMTAB_COMMAND: usize = 24;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct DysymtabCommand {
pub cmd: u32,
pub cmdsize: u32,
pub ilocalsym: u32,
pub nlocalsym: u32,
pub iextdefsym: u32,
pub nextdefsym: u32,
pub iundefsym: u32,
pub nundefsym: u32,
pub tocoff: u32,
pub ntoc: u32,
pub modtaboff: u32,
pub nmodtab: u32,
pub extrefsymoff: u32,
pub nextrefsyms: u32,
pub indirectsymoff: u32,
pub nindirectsyms: u32,
pub extreloff: u32,
pub nextrel: u32,
pub locreloff: u32,
pub nlocrel: u32,
}
impl Default for DysymtabCommand {
fn default() -> Self {
DysymtabCommand {
cmd: LC_DYSYMTAB,
cmdsize: SIZEOF_DYSYMTAB_COMMAND as u32,
ilocalsym: 0,
nlocalsym: 0,
iextdefsym: 0,
nextdefsym: 0,
iundefsym: 0,
nundefsym: 0,
tocoff: 0,
ntoc: 0,
modtaboff: 0,
nmodtab: 0,
extrefsymoff: 0,
nextrefsyms: 0,
indirectsymoff: 0,
nindirectsyms: 0,
extreloff: 0,
nextrel: 0,
locreloff: 0,
nlocrel: 0,
}
}
}
impl DysymtabCommand {
pub fn new() -> Self {
Default::default()
}
}
pub const SIZEOF_DYSYMTAB_COMMAND: usize = 80;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct DylibTableOfContents {
pub symbol_index: u32,
pub module_index: u32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct DylibModule {
pub module_name: u32,
pub iextdefsym: u32,
pub nextdefsym: u32,
pub irefsym: u32,
pub nrefsym: u32,
pub ilocalsym: u32,
pub nlocalsym: u32,
pub iextrel: u32,
pub nextrel: u32,
pub iinit_iterm: u32,
pub ninit_nterm: u32,
pub objc_module_info_addr: u32,
pub objc_module_info_size: u32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct DylibModule64 {
pub module_name: u32,
pub iextdefsym: u32,
pub nextdefsym: u32,
pub irefsym: u32,
pub nrefsym: u32,
pub ilocalsym: u32,
pub nlocalsym: u32,
pub iextrel: u32,
pub nextrel: u32,
pub iinit_iterm: u32,
pub ninit_nterm: u32,
pub objc_module_info_size: u32,
pub objc_module_info_addr: u64,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct DylibReference {
pub isym: [u8; 24],
pub flags: u64,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct TwolevelHintsCommand {
pub cmd: u32,
pub cmdsize: u32,
pub offset: u32,
pub nhints: u32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct TwolevelHint {
pub isub_image: u64,
pub itoc: [u8; 24],
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct PrebindCksumCommand {
pub cmd: u32,
pub cmdsize: u32,
pub cksum: u32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct UuidCommand {
pub cmd: u32,
pub cmdsize: u32,
pub uuid: [u8; 16],
}
pub const SIZEOF_UUID_COMMAND: usize = 24;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct RpathCommand {
pub cmd: u32,
pub cmdsize: u32,
pub path: LcStr,
}
pub const SIZEOF_RPATH_COMMAND: usize = 12;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct LinkeditDataCommand {
pub cmd: u32,
pub cmdsize: u32,
pub dataoff: u32,
pub datasize: u32,
}
pub const SIZEOF_LINKEDIT_DATA_COMMAND: usize = 16;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct EncryptionInfoCommand32 {
pub cmd: u32,
pub cmdsize: u32,
pub cryptoff: u32,
pub cryptsize: u32,
pub cryptid: u32,
}
pub const SIZEOF_ENCRYPTION_INFO_COMMAND_32: usize = 20;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct EncryptionInfoCommand64 {
pub cmd: u32,
pub cmdsize: u32,
pub cryptoff: u32,
pub cryptsize: u32,
pub cryptid: u32,
pub pad: u32,
}
pub const SIZEOF_ENCRYPTION_INFO_COMMAND_64: usize = 24;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct VersionMinCommand {
pub cmd: u32,
pub cmdsize: u32,
pub version: u32,
pub sdk: u32,
}
impl VersionMinCommand {
pub fn new(is_ios: bool) -> Self {
VersionMinCommand {
cmd: if is_ios { LC_VERSION_MIN_IPHONEOS } else { LC_VERSION_MIN_MACOSX },
cmdsize: SIZEOF_VERSION_MIN_COMMAND as u32,
version: 0,
sdk: 0,
}
}
}
pub const SIZEOF_VERSION_MIN_COMMAND: usize = 16;
#[repr(C)]
#[derive(Default, Debug, Clone, Copy, Pread, Pwrite, SizeWith)]
pub struct DyldInfoCommand {
pub cmd: u32,
pub cmdsize: u32,
pub rebase_off: u32,
pub rebase_size: u32,
pub bind_off: u32,
pub bind_size: u32,
pub weak_bind_off: u32,
pub weak_bind_size: u32,
pub lazy_bind_off: u32,
pub lazy_bind_size: u32,
pub export_off: u32,
pub export_size: u32,
}
pub const SIZEOF_DYLIB_INFO_COMMAND: usize = 48;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct LinkerOptionCommand {
pub cmd: u32,
pub cmdsize: u32,
pub count: u32,
}
pub const SIZEOF_LINKER_OPTION_COMMAND: usize = 12;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct SymsegCommand {
pub cmd: u32,
pub cmdsize: u32,
pub offset: u32,
pub size: u32,
}
pub const SIZEOF_SYMSEG_COMMAND: usize = 16;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct IdentCommand {
pub cmd: u32,
pub cmdsize: u32,
}
pub const SIZEOF_IDENT_COMMAND: usize = 8;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct FvmfileCommand {
pub cmd: u32,
pub cmdsize: u32,
pub name: LcStr,
pub header_addr: u32,
}
pub const SIZEOF_FVMFILE_COMMAND: usize = 16;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct EntryPointCommand {
pub cmd: u32,
pub cmdsize: u32,
pub entryoff: u64,
pub stacksize: u64,
}
pub const SIZEOF_ENTRY_POINT_COMMAND: usize = 24;
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct SourceVersionCommand {
pub cmd: u32,
pub cmdsize: u32,
pub version: u64,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
pub struct DataInCodeEntry {
pub offset: u32,
pub length: u16,
pub kind: u16,
}
pub const LC_REQ_DYLD: u32 = 0x8000_0000;
pub const LC_LOAD_WEAK_DYLIB: u32 = 0x18 | LC_REQ_DYLD;
pub const LC_RPATH: u32 = 0x1c | LC_REQ_DYLD;
pub const LC_REEXPORT_DYLIB: u32 = 0x1f | LC_REQ_DYLD;
pub const LC_DYLD_INFO_ONLY: u32 = 0x22 | LC_REQ_DYLD;
pub const LC_LOAD_UPWARD_DYLIB: u32 = 0x23 | LC_REQ_DYLD;
pub const LC_MAIN: u32 = 0x28 | LC_REQ_DYLD;
pub const LC_SEGMENT: u32 = 0x1;
pub const LC_SYMTAB: u32 = 0x2;
pub const LC_SYMSEG: u32 = 0x3;
pub const LC_THREAD: u32 = 0x4;
pub const LC_UNIXTHREAD: u32 = 0x5;
pub const LC_LOADFVMLIB: u32 = 0x6;
pub const LC_IDFVMLIB: u32 = 0x7;
pub const LC_IDENT: u32 = 0x8;
pub const LC_FVMFILE: u32 = 0x9;
pub const LC_PREPAGE: u32 = 0xa;
pub const LC_DYSYMTAB: u32 = 0xb;
pub const LC_LOAD_DYLIB: u32 = 0xc;
pub const LC_ID_DYLIB: u32 = 0xd;
pub const LC_LOAD_DYLINKER: u32 = 0xe;
pub const LC_ID_DYLINKER: u32 = 0xf;
pub const LC_PREBOUND_DYLIB: u32 = 0x10;
pub const LC_ROUTINES: u32 = 0x11;
pub const LC_SUB_FRAMEWORK: u32 = 0x12;
pub const LC_SUB_UMBRELLA: u32 = 0x13;
pub const LC_SUB_CLIENT: u32 = 0x14;
pub const LC_SUB_LIBRARY: u32 = 0x15;
pub const LC_TWOLEVEL_HINTS: u32 = 0x16;
pub const LC_PREBIND_CKSUM: u32 = 0x17;
pub const LC_SEGMENT_64: u32 = 0x19;
pub const LC_ROUTINES_64: u32 = 0x1a;
pub const LC_UUID: u32 = 0x1b;
pub const LC_CODE_SIGNATURE: u32 = 0x1d;
pub const LC_SEGMENT_SPLIT_INFO: u32 = 0x1e;
pub const LC_LAZY_LOAD_DYLIB: u32 = 0x20;
pub const LC_ENCRYPTION_INFO: u32 = 0x21;
pub const LC_DYLD_INFO: u32 = 0x22;
pub const LC_VERSION_MIN_MACOSX: u32 = 0x24;
pub const LC_VERSION_MIN_IPHONEOS: u32 = 0x25;
pub const LC_FUNCTION_STARTS: u32 = 0x26;
pub const LC_DYLD_ENVIRONMENT: u32 = 0x27;
pub const LC_DATA_IN_CODE: u32 = 0x29;
pub const LC_SOURCE_VERSION: u32 = 0x2A;
pub const LC_DYLIB_CODE_SIGN_DRS: u32 = 0x2B;
pub const LC_ENCRYPTION_INFO_64: u32 = 0x2C;
pub const LC_LINKER_OPTION: u32 = 0x2D;
pub const LC_LINKER_OPTIMIZATION_HINT: u32 = 0x2E;
pub fn cmd_to_str(cmd: u32) -> &'static str {
match cmd {
LC_SEGMENT => "LC_SEGMENT",
LC_SYMTAB => "LC_SYMTAB",
LC_SYMSEG => "LC_SYMSEG",
LC_THREAD => "LC_THREAD",
LC_UNIXTHREAD => "LC_UNIXTHREAD",
LC_LOADFVMLIB => "LC_LOADFVMLIB",
LC_IDFVMLIB => "LC_IDFVMLIB",
LC_IDENT => "LC_IDENT",
LC_FVMFILE => "LC_FVMFILE",
LC_PREPAGE => "LC_PREPAGE",
LC_DYSYMTAB => "LC_DYSYMTAB",
LC_LOAD_DYLIB => "LC_LOAD_DYLIB",
LC_ID_DYLIB => "LC_ID_DYLIB",
LC_LOAD_DYLINKER => "LC_LOAD_DYLINKER",
LC_ID_DYLINKER => "LC_ID_DYLINKER",
LC_PREBOUND_DYLIB => "LC_PREBOUND_DYLIB",
LC_ROUTINES => "LC_ROUTINES",
LC_SUB_FRAMEWORK => "LC_SUB_FRAMEWORK",
LC_SUB_UMBRELLA => "LC_SUB_UMBRELLA",
LC_SUB_CLIENT => "LC_SUB_CLIENT",
LC_SUB_LIBRARY => "LC_SUB_LIBRARY",
LC_TWOLEVEL_HINTS => "LC_TWOLEVEL_HINTS",
LC_PREBIND_CKSUM => "LC_PREBIND_CKSUM",
LC_LOAD_WEAK_DYLIB => "LC_LOAD_WEAK_DYLIB",
LC_SEGMENT_64 => "LC_SEGMENT_64",
LC_ROUTINES_64 => "LC_ROUTINES_64",
LC_UUID => "LC_UUID",
LC_RPATH => "LC_RPATH",
LC_CODE_SIGNATURE => "LC_CODE_SIGNATURE",
LC_SEGMENT_SPLIT_INFO => "LC_SEGMENT_SPLIT_INFO",
LC_REEXPORT_DYLIB => "LC_REEXPORT_DYLIB",
LC_LAZY_LOAD_DYLIB => "LC_LAZY_LOAD_DYLIB",
LC_ENCRYPTION_INFO => "LC_ENCRYPTION_INFO",
LC_DYLD_INFO => "LC_DYLD_INFO",
LC_DYLD_INFO_ONLY => "LC_DYLD_INFO_ONLY",
LC_LOAD_UPWARD_DYLIB => "LC_LOAD_UPWARD_DYLIB",
LC_VERSION_MIN_MACOSX => "LC_VERSION_MIN_MACOSX",
LC_VERSION_MIN_IPHONEOS => "LC_VERSION_MIN_IPHONEOS",
LC_FUNCTION_STARTS => "LC_FUNCTION_STARTS",
LC_DYLD_ENVIRONMENT => "LC_DYLD_ENVIRONMENT",
LC_MAIN => "LC_MAIN",
LC_DATA_IN_CODE => "LC_DATA_IN_CODE",
LC_SOURCE_VERSION => "LC_SOURCE_VERSION",
LC_DYLIB_CODE_SIGN_DRS => "LC_DYLIB_CODE_SIGN_DRS",
LC_ENCRYPTION_INFO_64 => "LC_ENCRYPTION_INFO_64",
LC_LINKER_OPTION => "LC_LINKER_OPTION",
LC_LINKER_OPTIMIZATION_HINT => "LC_LINKER_OPTIMIZATION_HINT",
_ => "LC_UNKNOWN",
}
}
#[derive(Debug)]
#[allow(clippy::large_enum_variant)]
pub enum CommandVariant {
Segment32 (SegmentCommand32),
Segment64 (SegmentCommand64),
Uuid (UuidCommand),
Symtab (SymtabCommand),
Symseg (SymsegCommand),
Thread (ThreadCommand),
Unixthread (ThreadCommand),
LoadFvmlib (FvmlibCommand),
IdFvmlib (FvmlibCommand),
Ident (IdentCommand),
Fvmfile (FvmfileCommand),
Prepage (LoadCommandHeader),
Dysymtab (DysymtabCommand),
LoadDylib (DylibCommand),
IdDylib (DylibCommand),
LoadDylinker (DylinkerCommand),
IdDylinker (DylinkerCommand),
PreboundDylib (PreboundDylibCommand),
Routines32 (RoutinesCommand32),
Routines64 (RoutinesCommand64),
SubFramework (SubFrameworkCommand),
SubUmbrella (SubUmbrellaCommand),
SubClient (SubClientCommand),
SubLibrary (SubLibraryCommand),
TwolevelHints (TwolevelHintsCommand),
PrebindCksum (PrebindCksumCommand),
LoadWeakDylib (DylibCommand),
Rpath (RpathCommand),
CodeSignature (LinkeditDataCommand),
SegmentSplitInfo (LinkeditDataCommand),
ReexportDylib (DylibCommand),
LazyLoadDylib (DylibCommand),
EncryptionInfo32 (EncryptionInfoCommand32),
EncryptionInfo64 (EncryptionInfoCommand64),
DyldInfo (DyldInfoCommand),
DyldInfoOnly (DyldInfoCommand),
LoadUpwardDylib (DylibCommand),
VersionMinMacosx (VersionMinCommand),
VersionMinIphoneos (VersionMinCommand),
FunctionStarts (LinkeditDataCommand),
DyldEnvironment (DylinkerCommand),
Main (EntryPointCommand),
DataInCode (LinkeditDataCommand),
SourceVersion (SourceVersionCommand),
DylibCodeSignDrs (LinkeditDataCommand),
LinkerOption (LinkeditDataCommand),
LinkerOptimizationHint (LinkeditDataCommand),
Unimplemented (LoadCommandHeader),
}
impl<'a> ctx::TryFromCtx<'a, Endian> for CommandVariant {
type Error = crate::error::Error;
fn try_from_ctx(bytes: &'a [u8], le: Endian) -> error::Result<(Self, usize)> {
use self::CommandVariant::*;
let lc = bytes.pread_with::<LoadCommandHeader>(0, le)?;
let size = lc.cmdsize as usize;
if size > bytes.len() { return Err(error::Error::Malformed(format!("{} has size larger than remainder of binary: {:?}", &lc, bytes.len()))) }
match lc.cmd {
LC_SEGMENT => { let comm = bytes.pread_with::<SegmentCommand32> (0, le)?; Ok((Segment32 (comm), size))},
LC_SEGMENT_64 => { let comm = bytes.pread_with::<SegmentCommand64> (0, le)?; Ok((Segment64 (comm), size))},
LC_DYSYMTAB => { let comm = bytes.pread_with::<DysymtabCommand> (0, le)?; Ok((Dysymtab (comm), size))},
LC_LOAD_DYLINKER => { let comm = bytes.pread_with::<DylinkerCommand> (0, le)?; Ok((LoadDylinker (comm), size))},
LC_ID_DYLINKER => { let comm = bytes.pread_with::<DylinkerCommand> (0, le)?; Ok((IdDylinker (comm), size))},
LC_UUID => { let comm = bytes.pread_with::<UuidCommand> (0, le)?; Ok((Uuid (comm), size))},
LC_SYMTAB => { let comm = bytes.pread_with::<SymtabCommand> (0, le)?; Ok((Symtab (comm), size))},
LC_SYMSEG => { let comm = bytes.pread_with::<SymsegCommand> (0, le)?; Ok((Symseg (comm), size))},
LC_THREAD => { let comm = bytes.pread_with::<ThreadCommand> (0, le)?; Ok((Thread (comm), size))},
LC_UNIXTHREAD => { let comm = bytes.pread_with::<ThreadCommand> (0, le)?; Ok((Unixthread (comm), size))},
LC_LOADFVMLIB => { let comm = bytes.pread_with::<FvmlibCommand> (0, le)?; Ok((LoadFvmlib (comm), size))},
LC_IDFVMLIB => { let comm = bytes.pread_with::<FvmlibCommand> (0, le)?; Ok((IdFvmlib (comm), size))},
LC_IDENT => { let comm = bytes.pread_with::<IdentCommand> (0, le)?; Ok((Ident (comm), size))},
LC_FVMFILE => { let comm = bytes.pread_with::<FvmfileCommand> (0, le)?; Ok((Fvmfile (comm), size))},
LC_PREPAGE => { let comm = bytes.pread_with::<LoadCommandHeader> (0, le)?; Ok((Prepage (comm), size))},
LC_LOAD_DYLIB => { let comm = bytes.pread_with::<DylibCommand> (0, le)?; Ok((LoadDylib (comm), size))},
LC_ID_DYLIB => { let comm = bytes.pread_with::<DylibCommand> (0, le)?; Ok((IdDylib (comm), size))},
LC_PREBOUND_DYLIB => { let comm = bytes.pread_with::<PreboundDylibCommand> (0, le)?; Ok((PreboundDylib (comm), size))},
LC_ROUTINES => { let comm = bytes.pread_with::<RoutinesCommand32> (0, le)?; Ok((Routines32 (comm), size))},
LC_ROUTINES_64 => { let comm = bytes.pread_with::<RoutinesCommand64> (0, le)?; Ok((Routines64 (comm), size))},
LC_SUB_FRAMEWORK => { let comm = bytes.pread_with::<SubFrameworkCommand> (0, le)?; Ok((SubFramework (comm), size))},
LC_SUB_UMBRELLA => { let comm = bytes.pread_with::<SubUmbrellaCommand> (0, le)?; Ok((SubUmbrella (comm), size))},
LC_SUB_CLIENT => { let comm = bytes.pread_with::<SubClientCommand> (0, le)?; Ok((SubClient (comm), size))},
LC_SUB_LIBRARY => { let comm = bytes.pread_with::<SubLibraryCommand> (0, le)?; Ok((SubLibrary (comm), size))},
LC_TWOLEVEL_HINTS => { let comm = bytes.pread_with::<TwolevelHintsCommand> (0, le)?; Ok((TwolevelHints (comm), size))},
LC_PREBIND_CKSUM => { let comm = bytes.pread_with::<PrebindCksumCommand> (0, le)?; Ok((PrebindCksum (comm), size))},
LC_LOAD_WEAK_DYLIB => { let comm = bytes.pread_with::<DylibCommand> (0, le)?; Ok((LoadWeakDylib (comm), size))},
LC_RPATH => { let comm = bytes.pread_with::<RpathCommand> (0, le)?; Ok((Rpath (comm), size))},
LC_CODE_SIGNATURE => { let comm = bytes.pread_with::<LinkeditDataCommand> (0, le)?; Ok((CodeSignature (comm), size))},
LC_SEGMENT_SPLIT_INFO => { let comm = bytes.pread_with::<LinkeditDataCommand> (0, le)?; Ok((SegmentSplitInfo (comm), size))},
LC_REEXPORT_DYLIB => { let comm = bytes.pread_with::<DylibCommand> (0, le)?; Ok((ReexportDylib (comm), size))},
LC_LAZY_LOAD_DYLIB => { let comm = bytes.pread_with::<DylibCommand> (0, le)?; Ok((LazyLoadDylib (comm), size))},
LC_ENCRYPTION_INFO => { let comm = bytes.pread_with::<EncryptionInfoCommand32>(0, le)?; Ok((EncryptionInfo32 (comm), size))},
LC_ENCRYPTION_INFO_64 => { let comm = bytes.pread_with::<EncryptionInfoCommand64>(0, le)?; Ok((EncryptionInfo64 (comm), size))},
LC_DYLD_INFO => { let comm = bytes.pread_with::<DyldInfoCommand> (0, le)?; Ok((DyldInfo (comm), size))},
LC_DYLD_INFO_ONLY => { let comm = bytes.pread_with::<DyldInfoCommand> (0, le)?; Ok((DyldInfoOnly (comm), size))},
LC_LOAD_UPWARD_DYLIB => { let comm = bytes.pread_with::<DylibCommand> (0, le)?; Ok((LoadUpwardDylib (comm), size))},
LC_VERSION_MIN_MACOSX => { let comm = bytes.pread_with::<VersionMinCommand> (0, le)?; Ok((VersionMinMacosx (comm), size))},
LC_VERSION_MIN_IPHONEOS => { let comm = bytes.pread_with::<VersionMinCommand> (0, le)?; Ok((VersionMinIphoneos (comm), size))},
LC_FUNCTION_STARTS => { let comm = bytes.pread_with::<LinkeditDataCommand> (0, le)?; Ok((FunctionStarts (comm), size))},
LC_DYLD_ENVIRONMENT => { let comm = bytes.pread_with::<DylinkerCommand> (0, le)?; Ok((DyldEnvironment (comm), size))},
LC_MAIN => { let comm = bytes.pread_with::<EntryPointCommand> (0, le)?; Ok((Main (comm), size))},
LC_DATA_IN_CODE => { let comm = bytes.pread_with::<LinkeditDataCommand> (0, le)?; Ok((DataInCode (comm), size))},
LC_SOURCE_VERSION => { let comm = bytes.pread_with::<SourceVersionCommand> (0, le)?; Ok((SourceVersion (comm), size))},
LC_DYLIB_CODE_SIGN_DRS => { let comm = bytes.pread_with::<LinkeditDataCommand> (0, le)?; Ok((DylibCodeSignDrs (comm), size))},
LC_LINKER_OPTION => { let comm = bytes.pread_with::<LinkeditDataCommand> (0, le)?; Ok((LinkerOption (comm), size))},
LC_LINKER_OPTIMIZATION_HINT => {let comm = bytes.pread_with::<LinkeditDataCommand> (0, le)?; Ok((LinkerOptimizationHint (comm), size))},
_ => Ok((Unimplemented (lc), size)),
}
}
}
impl CommandVariant {
pub fn cmdsize(&self) -> usize {
use self::CommandVariant::*;
let cmdsize = match *self {
Segment32 (comm) => comm.cmdsize,
Segment64 (comm) => comm.cmdsize,
Uuid (comm) => comm.cmdsize,
Symtab (comm) => comm.cmdsize,
Symseg (comm) => comm.cmdsize,
Thread (comm) => comm.cmdsize,
Unixthread (comm) => comm.cmdsize,
LoadFvmlib (comm) => comm.cmdsize,
IdFvmlib (comm) => comm.cmdsize,
Ident (comm) => comm.cmdsize,
Fvmfile (comm) => comm.cmdsize,
Prepage (comm) => comm.cmdsize,
Dysymtab (comm) => comm.cmdsize,
LoadDylib (comm) => comm.cmdsize,
IdDylib (comm) => comm.cmdsize,
LoadDylinker (comm) => comm.cmdsize,
IdDylinker (comm) => comm.cmdsize,
PreboundDylib (comm) => comm.cmdsize,
Routines32 (comm) => comm.cmdsize,
Routines64 (comm) => comm.cmdsize,
SubFramework (comm) => comm.cmdsize,
SubUmbrella (comm) => comm.cmdsize,
SubClient (comm) => comm.cmdsize,
SubLibrary (comm) => comm.cmdsize,
TwolevelHints (comm) => comm.cmdsize,
PrebindCksum (comm) => comm.cmdsize,
LoadWeakDylib (comm) => comm.cmdsize,
Rpath (comm) => comm.cmdsize,
CodeSignature (comm) => comm.cmdsize,
SegmentSplitInfo (comm) => comm.cmdsize,
ReexportDylib (comm) => comm.cmdsize,
LazyLoadDylib (comm) => comm.cmdsize,
EncryptionInfo32 (comm) => comm.cmdsize,
EncryptionInfo64 (comm) => comm.cmdsize,
DyldInfo (comm) => comm.cmdsize,
DyldInfoOnly (comm) => comm.cmdsize,
LoadUpwardDylib (comm) => comm.cmdsize,
VersionMinMacosx (comm) => comm.cmdsize,
VersionMinIphoneos (comm) => comm.cmdsize,
FunctionStarts (comm) => comm.cmdsize,
DyldEnvironment (comm) => comm.cmdsize,
Main (comm) => comm.cmdsize,
DataInCode (comm) => comm.cmdsize,
SourceVersion (comm) => comm.cmdsize,
DylibCodeSignDrs (comm) => comm.cmdsize,
LinkerOption (comm) => comm.cmdsize,
LinkerOptimizationHint (comm) => comm.cmdsize,
Unimplemented (comm) => comm.cmdsize,
};
cmdsize as usize
}
pub fn cmd(&self) -> u32 {
use self::CommandVariant::*;
match *self {
Segment32 (comm) => comm.cmd,
Segment64 (comm) => comm.cmd,
Uuid (comm) => comm.cmd,
Symtab (comm) => comm.cmd,
Symseg (comm) => comm.cmd,
Thread (comm) => comm.cmd,
Unixthread (comm) => comm.cmd,
LoadFvmlib (comm) => comm.cmd,
IdFvmlib (comm) => comm.cmd,
Ident (comm) => comm.cmd,
Fvmfile (comm) => comm.cmd,
Prepage (comm) => comm.cmd,
Dysymtab (comm) => comm.cmd,
LoadDylib (comm) => comm.cmd,
IdDylib (comm) => comm.cmd,
LoadDylinker (comm) => comm.cmd,
IdDylinker (comm) => comm.cmd,
PreboundDylib (comm) => comm.cmd,
Routines32 (comm) => comm.cmd,
Routines64 (comm) => comm.cmd,
SubFramework (comm) => comm.cmd,
SubUmbrella (comm) => comm.cmd,
SubClient (comm) => comm.cmd,
SubLibrary (comm) => comm.cmd,
TwolevelHints (comm) => comm.cmd,
PrebindCksum (comm) => comm.cmd,
LoadWeakDylib (comm) => comm.cmd,
Rpath (comm) => comm.cmd,
CodeSignature (comm) => comm.cmd,
SegmentSplitInfo (comm) => comm.cmd,
ReexportDylib (comm) => comm.cmd,
LazyLoadDylib (comm) => comm.cmd,
EncryptionInfo32 (comm) => comm.cmd,
EncryptionInfo64 (comm) => comm.cmd,
DyldInfo (comm) => comm.cmd,
DyldInfoOnly (comm) => comm.cmd,
LoadUpwardDylib (comm) => comm.cmd,
VersionMinMacosx (comm) => comm.cmd,
VersionMinIphoneos (comm) => comm.cmd,
FunctionStarts (comm) => comm.cmd,
DyldEnvironment (comm) => comm.cmd,
Main (comm) => comm.cmd,
DataInCode (comm) => comm.cmd,
SourceVersion (comm) => comm.cmd,
DylibCodeSignDrs (comm) => comm.cmd,
LinkerOption (comm) => comm.cmd,
LinkerOptimizationHint (comm) => comm.cmd,
Unimplemented (comm) => comm.cmd,
}
}
}
#[derive(Debug)]
pub struct LoadCommand {
pub offset: usize,
pub command: CommandVariant,
}
impl LoadCommand {
pub fn parse(bytes: &[u8], offset: &mut usize, le: scroll::Endian) -> error::Result<Self> {
let start = *offset;
let command = bytes.pread_with::<CommandVariant>(start, le)?;
let size = command.cmdsize();
*offset = start + size;
Ok(LoadCommand { offset: start, command })
}
}