PyMISP/pymisp/tools/machoobject.py

97 lines
4.1 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from ..exceptions import InvalidMISPObject
from .abstractgenerator import AbstractMISPObjectGenerator
from io import BytesIO
from hashlib import md5, sha1, sha256, sha512
import logging
from typing import Optional, Union
from pathlib import Path
from . import FileObject
import lief
try:
import pydeep # type: ignore
HAS_PYDEEP = True
except ImportError:
HAS_PYDEEP = False
logger = logging.getLogger('pymisp')
def make_macho_objects(lief_parsed: lief.MachO.Binary, misp_file: FileObject, standalone: bool = True, default_attributes_parameters: dict = {}):
macho_object = MachOObject(parsed=lief_parsed, standalone=standalone, default_attributes_parameters=default_attributes_parameters)
misp_file.add_reference(macho_object.uuid, 'includes', 'MachO indicators')
macho_sections = []
for s in macho_object.sections:
macho_sections.append(s)
return misp_file, macho_object, macho_sections
class MachOObject(AbstractMISPObjectGenerator):
def __init__(self, parsed: Optional[lief.MachO.Binary] = None, filepath: Optional[Union[Path, str]] = None, pseudofile: Optional[BytesIO] = None, **kwargs):
"""Creates an MachO object, with lief"""
super().__init__('macho', **kwargs)
if not HAS_PYDEEP:
logger.warning("pydeep is missing, please install pymisp this way: pip install pymisp[fileobjects]")
if pseudofile:
if isinstance(pseudofile, BytesIO):
self.__macho = lief.MachO.parse(io=pseudofile)
elif isinstance(pseudofile, bytes):
self.__macho = lief.MachO.parse(raw=pseudofile)
else:
raise InvalidMISPObject('Pseudo file can be BytesIO or bytes got {}'.format(type(pseudofile)))
elif filepath:
self.__macho = lief.MachO.parse(filepath)
elif parsed:
# Got an already parsed blob
if isinstance(parsed, lief.MachO.Binary):
self.__macho = parsed
else:
raise InvalidMISPObject('Not a lief.MachO.Binary: {}'.format(type(parsed)))
self.generate_attributes()
def generate_attributes(self):
self.add_attribute('type', value=str(self.__macho.header.file_type).split('.')[1])
self.add_attribute('name', value=self.__macho.name)
# General information
if self.__macho.has_entrypoint:
self.add_attribute('entrypoint-address', value=self.__macho.entrypoint)
# Sections
self.sections = []
if self.__macho.sections:
pos = 0
for section in self.__macho.sections:
s = MachOSectionObject(section, standalone=self._standalone, default_attributes_parameters=self._default_attributes_parameters)
self.add_reference(s.uuid, 'includes', 'Section {} of MachO'.format(pos))
pos += 1
self.sections.append(s)
self.add_attribute('number-sections', value=len(self.sections))
class MachOSectionObject(AbstractMISPObjectGenerator):
def __init__(self, section: lief.MachO.Section, **kwargs):
"""Creates an MachO Section object. Object generated by MachOObject."""
# Python3 way
# super().__init__('pe-section')
super(MachOSectionObject, self).__init__('macho-section', **kwargs)
self.__section = section
self.__data = bytes(self.__section.content)
self.generate_attributes()
def generate_attributes(self):
self.add_attribute('name', value=self.__section.name)
size = self.add_attribute('size-in-bytes', value=self.__section.size)
if int(size.value) > 0:
self.add_attribute('entropy', value=self.__section.entropy)
self.add_attribute('md5', value=md5(self.__data).hexdigest())
self.add_attribute('sha1', value=sha1(self.__data).hexdigest())
self.add_attribute('sha256', value=sha256(self.__data).hexdigest())
self.add_attribute('sha512', value=sha512(self.__data).hexdigest())
if HAS_PYDEEP:
self.add_attribute('ssdeep', value=pydeep.hash_buf(self.__data).decode())