From f18f0a116cefab2f4ce9f8fddf00528f876e874c Mon Sep 17 00:00:00 2001 From: dhondta Date: Thu, 16 May 2024 00:41:28 +0200 Subject: [PATCH] Added support for MSDOS Executable (#3) --- src/peid/VERSION.txt | 2 +- src/peid/__init__.py | 10 +++--- src/peid/db/__init__.py | 4 +-- src/peid/exe/__init__.py | 17 +++++++++ src/peid/exe/msdos.py | 75 ++++++++++++++++++++++++++++++++++++++++ src/peid/{ => exe}/pe.py | 5 ++- 6 files changed, 103 insertions(+), 10 deletions(-) create mode 100644 src/peid/exe/__init__.py create mode 100644 src/peid/exe/msdos.py rename src/peid/{ => exe}/pe.py (96%) diff --git a/src/peid/VERSION.txt b/src/peid/VERSION.txt index fd3d3ec..82b225a 100644 --- a/src/peid/VERSION.txt +++ b/src/peid/VERSION.txt @@ -1 +1 @@ -2.1.1 +2.2.0 diff --git a/src/peid/__init__.py b/src/peid/__init__.py index 6ba1d54..1a06416 100644 --- a/src/peid/__init__.py +++ b/src/peid/__init__.py @@ -2,7 +2,7 @@ import os from .db import SignaturesTree, SignaturesDB -from .pe import PE +from .exe import open_exe __all__ = ["find_ep_only_signature", "identify_packer", "SignaturesDB"] @@ -20,13 +20,15 @@ def find_ep_only_signature(*files, minlength=16, maxlength=64, common_bytes_thre data = [] for f in files: try: - with PE(f) as pe: - bytes_from_ep = [f"{b:02X}" for b in list(pe.read(maxlength, pe.entrypoint_offset))[0]] + with open_exe(f) as exe: + bytes_from_ep = [f"{b:02X}" for b in list(exe.read(maxlength, exe.entrypoint_offset))[0]] maxlength = max(min(len(bytes_from_ep), maxlength), minlength) data.append(bytes_from_ep) - except (TypeError, ValueError) as e: + except (OSError, TypeError, ValueError) as e: if logger: logger.debug(f"{f}: {e}") + else: + raise # now determine a signature length = maxlength while length >= minlength: diff --git a/src/peid/db/__init__.py b/src/peid/db/__init__.py index 536fb1f..607a3ba 100644 --- a/src/peid/db/__init__.py +++ b/src/peid/db/__init__.py @@ -2,7 +2,7 @@ import re from os.path import abspath, basename, dirname, exists, expanduser, join -from ..pe import PE +from ..exe import open_exe __all__ = ["DB", "SignaturesDB", "SignaturesTree"] @@ -77,7 +77,7 @@ def _match(subtree, byteseq): subtree = subtree[byte] else: break - with PE(pe, logger=self.logger) as f: + with open_exe(pe, logger=self.logger) as f: if ep_only: for byteseq in f.read(n_bytes, f.entrypoint_offset): _match(self.__tree['ep_only'], byteseq) diff --git a/src/peid/exe/__init__.py b/src/peid/exe/__init__.py new file mode 100644 index 0000000..25f9f33 --- /dev/null +++ b/src/peid/exe/__init__.py @@ -0,0 +1,17 @@ +# -*- coding: UTF-8 -*- +from .msdos import MSDOS +from .pe import PE + + +__all__ = ["open_exe", "MSDOS", "PE"] + + +def open_exe(path, logger=None): + """ Find a matching format and return the instantiated executable object. """ + for fmt in [PE, MSDOS]: + try: + return fmt(path, logger) + except OSError: + pass + raise OSError("Not a valid executable or supported executable format") + diff --git a/src/peid/exe/msdos.py b/src/peid/exe/msdos.py new file mode 100644 index 0000000..4e1f4e4 --- /dev/null +++ b/src/peid/exe/msdos.py @@ -0,0 +1,75 @@ +# -*- coding: UTF-8 -*- +import struct +from os.path import getsize + + +__all__ = ["MSDOS"] + + +class MSDOS: + def __init__(self, path, logger=None): + self.path, self.size, self.logger = path, getsize(path), logger + self.__fd = f = open(path, "rb") + h = f.read(64) + # check MZ signature + if h[:2] != b"MZ": + raise OSError("Invalid MZ signature") + # read some header fields + self.bytes_last_page = struct.unpack("