schnauzer 0.3.5

Library for parsing Mach-O files
Documentation
use colored::Colorize;

use super::common::options::*;
use super::common::*;
use super::handler::*;
use super::Printer;
use super::Result;
use crate::auto_enum_fields::Field;
use crate::*;
use getopts::*;

static SUBCOMM_NAME: &str = "headers";

pub(super) struct HeadersHandler {
    printer: Printer,
}

impl HeadersHandler {
    pub(super) fn new(printer: Printer) -> Self {
        Self { printer }
    }
}

impl Handler for HeadersHandler {
    fn command_name(&self) -> String {
        SUBCOMM_NAME.to_string()
    }

    fn description(&self) -> String {
        "Prints object headers in file".to_string()
    }

    fn can_handle_with_name(&self, name: &str) -> bool {
        SUBCOMM_NAME == name
    }

    fn handle_object(&self, object: ObjectType, other_args: Vec<String>) -> Result<()> {
        let mut opts = Options::new();
        self.accepted_option_items().add_to_opts(&mut opts);

        let format = &Format::build(&mut opts, &other_args)?;
        let filter = ObjectFilter::build(&mut opts, &other_args)?;

        let objects = &filter.get_objects(object);

        for (idx, obj) in objects.iter().enumerate() {
            self.handle_mach_header(obj.header(), idx, format);
        }

        Ok(())
    }

    fn accepted_option_items(&self) -> Vec<OptionItem> {
        let mut result = default_option_items();
        result.append(&mut Format::option_items());
        result
    }
}

impl HeadersHandler {
    fn handle_mach_header(&self, header: &MachHeader, index: usize, format: &Format) {
        if format.show_indices {
            self.printer.out_list_item_dash(0, index);
        }

        if format.short {
            let mut strings: Vec<String> = vec![header.magic.to_string().green().to_string()];

            let mut cpu_tokens = match header.printable_cpu() {
                Some(cpu) => vec![cpu.to_string().green().to_string()],
                None => vec![
                    header.cputype.to_string().green().to_string(),
                    header.cpusubtype.masked().to_string().green().to_string(),
                ],
            };

            strings.append(&mut cpu_tokens);

            self.printer.print_strings(strings, " ");
            self.printer.print_line("");
        } else {
            let mut fields = vec![Field::new(MAGIC_STR.to_string(), header.magic.to_string())];

            match header.printable_cpu() {
                Some(cpu) => {
                    fields.push(Field::new(ARCH_STR.to_string(), cpu.to_string()));
                }
                None => {
                    fields.append(&mut vec![
                        Field::new(CPU_TYPE_STR.to_string(), header.cputype.to_string()),
                        Field::new(
                            CPU_SUBTYPE_STR.to_string(),
                            header.cpusubtype.masked().to_string(),
                        ),
                    ]);
                }
            };

            fields.append(&mut vec![
                Field::new(
                    CAPS_STR.to_string(),
                    header.cpusubtype.feature_flags().to_string(),
                ),
                Field::new(FILETYPE_STR.to_string(), header.filetype.to_string()),
                Field::new(N_CMDS_STR.to_string(), header.ncmds.to_string()),
                Field::new(SIZE_OF_CMDS_STR.to_string(), header.sizeofcmds.to_string()),
                Field::new(FLAGS_STR.to_string(), header.flags.to_string()),
            ]);

            self.printer.out_default_colored_fields(fields, "\n");

            self.printer
                .print_line(format!("{}", "Flags(detailed):".bright_white()));
            self.printer
                .print_line(printable_flags::strings_for_flags(header.flags.0).join("\n"))
        }
    }
}

mod printable_flags {
    use colored::Colorize;

    use crate::primitives::object_flags_constants::*;

    const ALL_FLAGS: [(u32, &str); 26] = [
        (MH_NOUNDEFS, "MH_NOUNDEFS"),
        (MH_INCRLINK, "MH_INCRLINK"),
        (MH_DYLDLINK, "MH_DYLDLINK"),
        (MH_BINDATLOAD, "MH_BINDATLOAD"),
        (MH_PREBOUND, "MH_PREBOUND"),
        (MH_SPLIT_SEGS, "MH_SPLIT_SEGS"),
        (MH_LAZY_INIT, "MH_LAZY_INIT"),
        (MH_TWOLEVEL, "MH_TWOLEVEL"),
        (MH_FORCE_FLAT, "MH_FORCE_FLAT"),
        (MH_NOMULTIDEFS, "MH_NOMULTIDEFS"),
        (MH_NOFIXPREBINDING, "MH_NOFIXPREBINDING"),
        (MH_PREBINDABLE, "MH_PREBINDABLE"),
        (MH_ALLMODSBOUND, "MH_ALLMODSBOUND"),
        (MH_SUBSECTIONS_VIA_SYMBOLS, "MH_SUBSECTIONS_VIA_SYMBOLS"),
        (MH_CANONICAL, "MH_CANONICAL"),
        (MH_WEAK_DEFINES, "MH_WEAK_DEFINES"),
        (MH_BINDS_TO_WEAK, "MH_BINDS_TO_WEAK"),
        (MH_ALLOW_STACK_EXECUTION, "MH_ALLOW_STACK_EXECUTION"),
        (MH_ROOT_SAFE, "MH_ROOT_SAFE"),
        (MH_SETUID_SAFE, "MH_SETUID_SAFE"),
        (MH_NO_REEXPORTED_DYLIBS, "MH_NO_REEXPORTED_DYLIBS"),
        (MH_PIE, "MH_PIE"),
        (MH_DEAD_STRIPPABLE_DYLIB, "MH_DEAD_STRIPPABLE_DYLIB"),
        (MH_HAS_TLV_DESCRIPTORS, "MH_HAS_TLV_DESCRIPTORS"),
        (MH_NO_HEAP_EXECUTION, "MH_NO_HEAP_EXECUTION"),
        (MH_APP_EXTENSION_SAFE, "MH_APP_EXTENSION_SAFE"),
    ];

    pub(super) fn strings_for_flags(flags: u32) -> Vec<String> {
        let mut result = vec![];
        for tup in ALL_FLAGS {
            if flags & tup.0 > 0 {
                result.push(format!("{}", tup.1.yellow()));
            }
        }
        result
    }
}