From 237c93d66fafd021053a25095df8652cacea7505 Mon Sep 17 00:00:00 2001 From: Gabe Stocco <98900+gfs@users.noreply.github.com> Date: Wed, 25 Jan 2023 20:18:13 -0800 Subject: [PATCH] Fixes gathering DLLCharacteristics and Signature information for Read-Only files. (#685) --- Lib/Collectors/FileSystemCollector.cs | 4 -- Lib/Collectors/WindowsFileSystemUtils.cs | 88 +++++++++++++++++++----- 2 files changed, 70 insertions(+), 22 deletions(-) diff --git a/Lib/Collectors/FileSystemCollector.cs b/Lib/Collectors/FileSystemCollector.cs index f4f7d851..5928de2a 100644 --- a/Lib/Collectors/FileSystemCollector.cs +++ b/Lib/Collectors/FileSystemCollector.cs @@ -242,10 +242,6 @@ e is ArgumentNullException obj.SignatureStatus = WindowsFileSystemUtils.GetSignatureStatus(path); obj.Characteristics = WindowsFileSystemUtils.GetDllCharacteristics(path); } - else if (obj.ExecutableType == EXECUTABLE_TYPE.MACOS) - { - obj.MacSignatureStatus = FileSystemUtils.GetMacSignature(path); - } } } } diff --git a/Lib/Collectors/WindowsFileSystemUtils.cs b/Lib/Collectors/WindowsFileSystemUtils.cs index 1a712b1e..05c20408 100644 --- a/Lib/Collectors/WindowsFileSystemUtils.cs +++ b/Lib/Collectors/WindowsFileSystemUtils.cs @@ -59,10 +59,13 @@ e is IndexOutOfRangeException return output; } + /// + /// Gets the of a File on disk. + /// + /// + /// List of DLL Characteristics public static List GetDllCharacteristics(string Path) { - List output = new(); - if (NeedsSignature(Path)) { try @@ -72,41 +75,75 @@ public static List GetDllCharacteristics(string Path) using var mmf = new PeNet.FileParser.MMFile(Path); var peHeader = new PeFile(mmf); var dllCharacteristics = peHeader.ImageNtHeaders?.OptionalHeader.DllCharacteristics; - if (dllCharacteristics is DllCharacteristicsType chars) + if (dllCharacteristics is { } chars) { - ushort characteristics = (ushort)chars; - foreach (DLLCHARACTERISTICS? characteristic in Enum.GetValues(typeof(DLLCHARACTERISTICS))) - { - if (characteristic is DLLCHARACTERISTICS c) - { - if (((ushort)c & characteristics) == (ushort)c) - { - output.Add(c); - } - } - } + return CharacteristicsTypeToListOfCharacteristics(chars); } } } + // This can happen if the file is readable but not writable as MMFile tries to open the file with write privileges. + // When we fail we can retry by reading the file to a Stream first, which cen be less performant but works with just Read access + // See #684 + catch (UnauthorizedAccessException) + { + try + { + using var stream = File.OpenRead(Path); + return GetDllCharacteristics(Path, stream); + } + catch (Exception e) + { + Log.Debug(e, "Failed to get DLL Characteristics for {0} ({1}:{2})", Path, e.GetType(), e.Message); + } + } catch (Exception e) when ( e is IndexOutOfRangeException || e is ArgumentNullException || e is System.IO.IOException || e is ArgumentException - || e is UnauthorizedAccessException || e is NullReferenceException) { - Log.Verbose("Failed to get PE Headers for {0} ({1}:{2})", Path, e.GetType(), e.Message); + Log.Debug("Failed to get DLL Characteristics for {0} ({1}:{2})", Path, e.GetType(), e.Message); } catch (Exception e) { - Log.Debug(e, "Failed to get PE Headers for {0} ({1}:{2})", Path, e.GetType(), e.Message); + Log.Debug(e, "Failed to get DLL Characteristics for {0} ({1}:{2})", Path, e.GetType(), e.Message); } } - return output; + return new(); } + /// + /// Turn a enum flag value into a list of enum values + /// + /// + /// + private static List CharacteristicsTypeToListOfCharacteristics( + DllCharacteristicsType dllcharacteristics) + { + List output = new(); + ushort characteristics = (ushort)dllcharacteristics; + foreach (DLLCHARACTERISTICS? characteristic in Enum.GetValues(typeof(DLLCHARACTERISTICS))) + { + if (characteristic is { } c) + { + if (((ushort)c & characteristics) == (ushort)c) + { + output.Add(c); + } + } + } + + return output; + } + + /// + /// Get the Signature + /// + /// + /// + /// public static Signature? GetSignatureStatus(string Path, Stream stream) { if (stream is null) @@ -151,6 +188,21 @@ e is IndexOutOfRangeException } } } + // This can happen if the file is readable but not writable as MMFile tries to open the file with write privileges. + // When we fail we can retry by reading the file to a Stream first, which cen be less performant but works with just Read access + // See #684 + catch (UnauthorizedAccessException) + { + try + { + using var stream = File.OpenRead(Path); + return GetSignatureStatus(Path, stream); + } + catch (Exception e) + { + Log.Debug(e, "Failed to get signature for {0} ({1}:{2})", Path, e.GetType(), e.Message); + } + } catch (Exception e) { Log.Verbose("Failed to get signature for {0} ({1}:{2})", Path, e.GetType(), e.Message);