Oliver Rhodes

22 papers A* 1A 1B 1C 2Journal 15Unranked 2
YearRankTypeTitle / Venue / Authors
2026 J jnl
CoRR
Tom Potter, Oliver Rhodes
2026 J jnl
CoRR
Mike Middleton, Teymoor Ali, Hakan Kayan, Basabdatta Sen Bhattacharya, Charith Perera, Oliver Rhodes, Elena Gheorghiu, Mark Vousden, Martin A. Trefzer
2025 C conf
DSD
Marko S. Andjelkovic, Rizwan Tariq Syed, Alessandro Veronesi, Fabian Vargas, Markus Ulbricht, Leticia Bolzani Poehls, Milos Krstic, Davide Bertozzi, Edward G. Jones, Oliver Rhodes, Riccardo Zese, Michele Favalli, Alice Bizzarri, Evelina Lamma, Marco Gavanelli, Elena Bellodi, Zoran Peric, Jelena Nikolic, Milan R. Dincic, Aleksandra Jovanovic, Dejan Ciric, Nikola Vucic, Sofija Peric, Jelena Jovanovic, Milica Stojanovic, Tatjana R. Nikolic, Goran Nikolic, Jelena Nedeljkovic, Danijel Dankovic, Emilija Zivanovic, Milos Marjanovic, Sandra Veljkovic, Nikola Mitrovic, Bratislav Predic, Tamara Milovanovic
2025 J jnl
CoRR
Johanna Senk, Anno Christopher Kurth, Steve B. Furber, Tobias Gemmeke, Bruno Golosio, Arne Heittmann, James C. Knight, Eric Müller, Tobias Noll, Thomas Nowotny, Gorka Peraza Coppola, Luca Peres, Oliver Rhodes, Andrew Rowley, Johannes Schemmel, Tim Stadtmann, Tom Tetzlaff, Gianmarco Tiddia, Sacha J. van Albada, Jose Villamar, Markus Diesmann
2025 J jnl
CoRR
Cedrick Kinavuidi, Luca Peres, Oliver Rhodes
2025 J jnl
WIREs Data. Mining. Knowl. Discov.
Pavan Kumar Enuganti, Basabdatta Sen Bhattacharya, Teresa Serrano-Gotarredona, Oliver Rhodes
2025 J jnl
CoRR
Paul Hueber, Luca Peres, Florian Pitters, Alejandro Hernán Gloriani, Oliver Rhodes
2025 J jnl
CoRR
Brian Ezinwoke, Oliver Rhodes
2025 J jnl
CoRR
Prithvish Nembhani, Oliver Rhodes, Guangzhi Tang, Alexandra F. Dobrita, Yingfu Xu, Kanishkan Vadivel, Kevin Shidqi, Paul Detterer, Mario Konijnenburg, Gert-Jan van Schaik, Manolis Sifalakis, Zaid Al-Ars, Amirreza Yousefzadeh
2025 B conf
IJCNN
Prithvish Nembhani, Oliver Rhodes, Guangzhi Tang, Alexandra F. Dobrita, Yingfu Xu, Kanishkan Vadivel, Kevin Shidqi, Paul Detterer, Mario Konijnenburg, Gert-Jan van Schaik, Manolis Sifalakis, Zaid Al-Ars, Amirreza Yousefzadeh
2025 C conf
ISCAS
Luca Peres, Edward G. Jones, Oliver Rhodes
2024 A* conf
DAC
Xabier Iturbe, Bernabé Linares-Barranco, Sio-Hoi Ieng, Arne Erdmann, Luca Peres, Oliver Rhodes, Rafael Tornero, Manolis Sifalakis, Marcel D. van de Burgwal, Amirreza Yousefzadeh, Maha Kooli, Riccardo Alidori, Pavel Zaykov
2024 J jnl
CoRR
Matei Ioan Stan, Oliver Rhodes
2024 J jnl
J. Comput. Sci. Technol.
Oliver Rhodes
2023 A conf
DATE
Xabier Iturbe, Nassim Abderrahmane, Jaume Abella, Sergi Alcaide, Eric Beyne, Henri-Pierre Charles, Christelle Charpin-Nicolle, Lars Chittka, Angélica Dávila, Arne Erdmann, Carles Estrada, Ander Fernández, Anna Fontanelli, José Flich, Gianluca Furano, Alejandro Hernán Gloriani, Erik Isusquiza, Radu Grosu, Carles Hernández, Daniele Ielmini, David Jackson, Maha Kooli, Nicola Lepri, Bernabé Linares-Barranco, Jean-Loup Lachese, Eric Laurent, Menno Lindwer, Frank Linsenmaier, Mikel Luján, Karel Masarík, Nele Mentens, Orlando Moreira, Chinmay Nawghane, Luca Peres, Jean-Philippe Noel, Arash Pourtaherian, Christoph Posch, Peter Priller, Zdenek Prikryl, Felix Resch, Oliver Rhodes, Todor P. Stefanov, Moritz Storring, Michele Taliercio, Rafael Tornero, Marcel D. van de Burgwal, Geert Van der Plas, Elisa Vianello, Pavel Zaykov
2022 conf
IPDPS Workshops
Oliver Rhodes
2022 J jnl
Frontiers Artif. Intell.
Adam Perrett, Steve B. Furber, Oliver Rhodes
2022 conf
NICE
Adam Perrett, Sara Summerton, Andrew Gait, Oliver Rhodes
2020 J jnl
CoRR
Simon Davidson, Stephen B. Furber, Oliver Rhodes
2019 J jnl
CoRR
Oliver Rhodes, Luca Peres, Andrew G. D. Rowley, Andrew Gait, Luis A. Plana, Christian Y. A. Brenninkmeijer, Steve B. Furber
2018 J jnl
IEEE Trans. Cogn. Dev. Syst.
Basabdatta Sen Bhattacharya, Sebastian S. James, Oliver Rhodes, Indar Sugiarto, Andrew Rowley, Alan B. Stokes, Kevin N. Gurney, Steve B. Furber
2018 J jnl
CoRR
Andrew G. D. Rowley, Christian Y. A. Brenninkmeijer, Simon Davidson, Donal Fellows, Andrew Gait, David R. Lester, Luis A. Plana, Oliver Rhodes, Alan B. Stokes, Steve B. Furber
redb/extractors/macho_extractor.py
← Index redb/extractors/macho_extractor.py python
import logging
from abc import ABCMeta, abstractmethod
import inspect
import sys
import os

import machofile

from redb.extractors.extractor import Extractor

logger = logging.getLogger(__name__)


@abstractmethod
class MachOExtractor(Extractor, metaclass=ABCMeta):

    def __init__(
        self,
        filepath,
        log,
        exporters=None,
        index_prefix=None,
        elastic_index=None,
        known_benign=False,
        known_malicious=False,
        macho=None,
    ):
        # Read binary and parse machofile BEFORE calling super().__init__
        # This avoids reading the file twice
        with open(filepath, "rb") as f:
            binary_data = f.read()

        # Parse machofile with binary data
        self.macho = macho if macho else self._generate_machofile_object(binary_data)

        # Extract hashes from machofile to pass to parent
        precomputed_hashes = None
        if self.macho:
            try:
                general_info = self.macho.get_general_info()
                if general_info:
                    # For FAT binaries, get_general_info() returns dict with 'fat' key
                    # For single-arch, it returns the info directly
                    if 'fat' in general_info:
                        fat_info = general_info['fat']
                        precomputed_hashes = {
                            'MD5': fat_info.get('MD5'),
                            'SHA1': fat_info.get('SHA1'),
                            'SHA256': fat_info.get('SHA256'),
                        }
                    else:
                        precomputed_hashes = {
                            'MD5': general_info.get('MD5'),
                            'SHA1': general_info.get('SHA1'),
                            'SHA256': general_info.get('SHA256'),
                        }
            except Exception as e:
                logger.debug(f"Could not get hashes from machofile: {e}")

        super().__init__(
            filepath,
            log,
            exporters,
            index_prefix,
            elastic_index,
            known_benign,
            known_malicious,
            precomputed_hashes=precomputed_hashes,
        )

        # Store binary data so base class doesn't re-read
        self._binary_data = binary_data

    @property
    def binary(self):
        """Override to use already-read binary data."""
        return self._binary_data

    def _generate_machofile_object(self, binary_data):
        """Generate and parse a machofile object from binary data."""
        macho = None
        try:
            macho = machofile.UniversalMachO(data=binary_data)
            if not macho:
                raise Exception("Empty file?")

            # Parse the MachO object once during initialization
            macho.parse()

        except Exception as e:
            logger.error(f"Format error parsing MachO: {e}")
        return macho

    # def _is_macho_file(self):
    #     """Check if the file is a valid Mach-O binary."""
    #     try:
    #         if not self.macho:
    #             return False
            
    #         # For Universal/FAT binaries, check if any architecture is valid
    #         if hasattr(self.macho, 'is_fat') and self.macho.is_fat:
    #             return len(self.macho.architectures) > 0
    #         else:
    #             # Single architecture binary
    #             return hasattr(self.macho, 'macho') and self.macho.macho is not None
    #     except Exception as e:
    #         self.log.error(f"Error checking Mach-O file: {e}")
    #         return False

    def _is_signed(self):
        """Check if the Mach-O binary is code signed using new API."""
        try:
            if not self.macho:
                return False

            # Get architectures using new API
            architectures = self.macho.get_architectures()

            # For each architecture, check if signed
            for arch in architectures:
                try:
                    signature_info = self.macho.get_code_signature_info(arch=arch)
                    if signature_info and signature_info.get('signed', False):
                        return True
                except Exception:
                    continue

            return False
        except Exception as e:
            self.log.error(f"Error checking Mach-O signature: {e}")
            return False

    def _get_architectures(self):
        """Get list of architectures in the Mach-O binary using new API."""
        try:
            if not self.macho:
                return []

            # Use new API method
            architectures = self.macho.get_architectures()
            return architectures if architectures else []
        except Exception as e:
            self.log.error(f"Error getting architectures: {e}")
            return []

    # def _get_macho_for_arch(self, arch_name=None):
    #     """Get MachO instance for specific architecture or default."""
    #     try:
    #         if not self.macho:
    #             return None
            
    #         if hasattr(self.macho, 'is_fat') and self.macho.is_fat:
    #             if arch_name:
    #                 return self.macho.architectures.get(arch_name)
    #             else:
    #                 # Return first available architecture
    #                 return next(iter(self.macho.architectures.values())) if self.macho.architectures else None
    #         else:
    #             # Single architecture binary
    #             return self.macho.macho if hasattr(self.macho, 'macho') else None
    #     except Exception as e:
    #         self.log.error(f"Error getting MachO for architecture: {e}")
    #         return None

    # def _get_formatted_header_values(self, header):
    #     """Get both raw and human-readable header values."""
    #     try:
    #         macho_instance = self._get_macho_for_arch()
    #         if not macho_instance:
    #             return None
            
    #         # Parse the MachO if not already parsed
    #         if not hasattr(macho_instance, 'header') or not macho_instance.header:
    #             macho_instance.parse()
            
    #         # Get human-readable values using machofile's formatting methods
    #         magic_str = macho_instance.format_magic_value(header.get('magic', 0))
            
    #         # Simple CPU type mapping since CPU_TYPE_MAP is not exposed
    #         cputype = header.get('cputype', 0)
    #         if cputype == 0x7:
    #             cputype_str = "x86"
    #         elif cputype == 0x1000007:
    #             cputype_str = "x86_64"
    #         elif cputype == 0xC:
    #             cputype_str = "ARM"
    #         elif cputype == 0x100000C:
    #             cputype_str = "ARM 64-bit"
    #         else:
    #             cputype_str = str(cputype)
            
    #         cpusubtype_str = macho_instance.decode_cpusubtype(header.get('cputype', 0), header.get('cpusubtype', 0))
    #         filetype_str = macho_instance.format_file_type(header.get('filetype', 0))
    #         flags_str = macho_instance.decode_flags(header.get('flags', 0))
            
    #         return {
    #             'raw': {
    #                 'magic': header.get('magic', 0),
    #                 'cputype': header.get('cputype', 0),
    #                 'cpusubtype': header.get('cpusubtype', 0),
    #                 'filetype': header.get('filetype', 0),
    #                 'flags': header.get('flags', 0),
    #             },
    #             'formatted': {
    #                 'magic_str': magic_str,
    #                 'cputype_str': cputype_str,
    #                 'cpusubtype_str': cpusubtype_str,
    #                 'filetype_str': filetype_str,
    #                 'flags_str': flags_str,
    #             }
    #         }
    #     except Exception as e:
    #         self.log.error(f"Error formatting header values: {e}")
    #         return None