From 6db476186dcf7c223feed5dde9e010dec60a3f78 Mon Sep 17 00:00:00 2001 From: Jean Gautier Date: Thu, 4 May 2023 17:11:52 +0200 Subject: [PATCH 01/35] OrcLib: Fmt: Result: format underlying type or error --- src/OrcLib/Text/Fmt/Result.h | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/OrcLib/Text/Fmt/Result.h b/src/OrcLib/Text/Fmt/Result.h index 8ae0e682..ef6fa098 100644 --- a/src/OrcLib/Text/Fmt/Result.h +++ b/src/OrcLib/Text/Fmt/Result.h @@ -13,35 +13,31 @@ #include "Utils/Result.h" template -struct fmt::formatter> : public fmt::formatter +struct fmt::formatter> : public fmt::formatter { template auto format(const Orc::Result& result, FormatContext& ctx) -> decltype(ctx.out()) { if (result.has_error()) { - fmt::memory_buffer msg; - fmt::format_to(std::back_inserter(msg), "{}", result.error()); - return fmt::formatter::format(std::begin(msg), ctx); + fmt::format_to(ctx.out(), "{}", result.error()); + return ctx.out(); } - - return formatter::format("Success", ctx); + return formatter::format(result.value(), ctx); } }; template -struct fmt::formatter, wchar_t> : public fmt::formatter +struct fmt::formatter, wchar_t> : public fmt::formatter { template auto format(const Orc::Result& result, FormatContext& ctx) -> decltype(ctx.out()) { if (result.has_error()) { - fmt::wmemory_buffer msg; - fmt::format_to(std::back_inserter(msg), L"{}", result.error()); - return fmt::formatter::format(std::begin(msg), ctx); + fmt::format_to(ctx.out(), L"{}", result.error()); + return ctx.out(); } - - return formatter::format(L"Success", ctx); + return formatter::format(result.value(), ctx); } }; From e1d9c845cefa5ee6166209ca2129712b4b0ef7a5 Mon Sep 17 00:00:00 2001 From: Jean Gautier Date: Thu, 4 May 2023 17:12:27 +0200 Subject: [PATCH 02/35] OrcLib: Log: restore the Get function to get a facility's logger --- src/OrcLib/Log/Log.cpp | 13 +++++++++++++ src/OrcLib/Log/Log.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/src/OrcLib/Log/Log.cpp b/src/OrcLib/Log/Log.cpp index 014eefd8..160860ae 100644 --- a/src/OrcLib/Log/Log.cpp +++ b/src/OrcLib/Log/Log.cpp @@ -25,5 +25,18 @@ void SetDefaultLogger(std::shared_ptr instance) pInstance = std::move(instance); } +const SpdlogLogger::Ptr& Get(Facility id) +{ + static SpdlogLogger::Ptr null_ptr; + + auto& instance = DefaultLogger(); + if (instance) + { + return instance->Get(id); + } + + return null_ptr; +} + } // namespace Log } // namespace Orc diff --git a/src/OrcLib/Log/Log.h b/src/OrcLib/Log/Log.h index 6a40a9eb..1a245f9e 100644 --- a/src/OrcLib/Log/Log.h +++ b/src/OrcLib/Log/Log.h @@ -19,6 +19,8 @@ std::shared_ptr& DefaultLogger(); void SetDefaultLogger(std::shared_ptr instance); +const SpdlogLogger::Ptr& Get(Facility id); + template void Trace(Args&&... args) { From 72c3cf2f9583cf4fac6eb17c1102e65daf1a834c Mon Sep 17 00:00:00 2001 From: Jean Gautier Date: Wed, 30 Aug 2023 13:45:04 +0200 Subject: [PATCH 03/35] Fix formatting compile errors --- .../Log/UtilitiesLoggerConfiguration.cpp | 4 +-- src/OrcLib/Configuration/ConfigFile.cpp | 10 +++---- src/OrcLib/FileFind.cpp | 28 +++++++++++-------- src/OrcLib/OutputSpec.cpp | 7 +++-- src/OrcLib/RegFind.cpp | 27 +++++++++++------- 5 files changed, 44 insertions(+), 32 deletions(-) diff --git a/src/OrcCommand/Log/UtilitiesLoggerConfiguration.cpp b/src/OrcCommand/Log/UtilitiesLoggerConfiguration.cpp index 394b9fca..db4299fd 100644 --- a/src/OrcCommand/Log/UtilitiesLoggerConfiguration.cpp +++ b/src/OrcCommand/Log/UtilitiesLoggerConfiguration.cpp @@ -196,7 +196,7 @@ std::optional ParseLogLevel(const ConfigItem& item) const auto level = Log::ToLevel(item[CONFIGITEM_LOG_COMMON_LEVEL]); if (!level) { - Log::Error(L"Failed to parse log level: {} [{}]", item[CONFIGITEM_LOG_COMMON_LEVEL], level.error()); + Log::Error(L"Failed to parse log level: {} [{}]", item[CONFIGITEM_LOG_COMMON_LEVEL].c_str(), level.error()); return {}; } @@ -214,7 +214,7 @@ std::optional ParseBacktraceLevel(const ConfigItem& item) if (!level) { Log::Error( - L"Failed to parse backtrace trigger level: {} [{}]", item[CONFIGITEM_LOG_COMMON_BACKTRACE], level.error()); + L"Failed to parse backtrace trigger level: {} [{}]", item[CONFIGITEM_LOG_COMMON_BACKTRACE].c_str(), level.error()); return {}; } diff --git a/src/OrcLib/Configuration/ConfigFile.cpp b/src/OrcLib/Configuration/ConfigFile.cpp index af3a503e..745d5a0b 100644 --- a/src/OrcLib/Configuration/ConfigFile.cpp +++ b/src/OrcLib/Configuration/ConfigFile.cpp @@ -376,7 +376,7 @@ HRESULT ConfigFile::PrintConfig(const ConfigItem& config, DWORD dwIndent) (config.Flags & ConfigItem::MANDATORY) ? L"Mandatory" : L"Optional", config ? L"Present" : L"Absent"); if (!config.empty()) - Log::Info(L"{}\tDATA: \"{}\" ", szIndent, config); + Log::Info(L"{}\tDATA: \"{}\" ", szIndent, config.c_str()); std::for_each(begin(config.SubItems), end(config.SubItems), [dwIndent](const ConfigItem& item) { PrintConfig(item, dwIndent + 1); @@ -388,7 +388,7 @@ HRESULT ConfigFile::PrintConfig(const ConfigItem& config, DWORD dwIndent) L"{}ATTRIBUTE: \"{}={}\" {} {}", szIndent, config.strName, - config, + config.c_str(), (config.Flags & ConfigItem::MANDATORY) ? L"Mandatory" : L"Optional", config ? L"Present" : L"Absent"); break; @@ -456,7 +456,7 @@ HRESULT ConfigFile::GetOutputDir(const ConfigItem& item, std::wstring& outputDir { if (FAILED(hr = ::GetOutputDir(item.c_str(), outputDir))) { - Log::Error(L"Error in specified outputdir '{}' in config file [{}]", item, SystemError(hr)); + Log::Error(L"Error in specified outputdir '{}' in config file [{}]", item.c_str(), SystemError(hr)); return hr; } @@ -477,7 +477,7 @@ HRESULT ConfigFile::GetOutputDir(const ConfigItem& item, std::wstring& outputDir { Log::Error( L"Invalid encoding for outputdir in config file: '{}' [{}]", - item.SubItems[CONFIG_CSVENCODING], + item.SubItems[CONFIG_CSVENCODING].c_str(), SystemError(hr)); return hr; } @@ -578,7 +578,7 @@ HRESULT ConfigFile::GetInputFile(const ConfigItem& item, std::wstring& inputFile { if (FAILED(hr = ::ExpandFilePath(item.c_str(), inputFile))) { - Log::Error(L"Error in specified inputfile in config file '{}' [{}]", item, SystemError(hr)); + Log::Error(L"Error in specified inputfile in config file '{}' [{}]", item.c_str(), SystemError(hr)); return hr; } } diff --git a/src/OrcLib/FileFind.cpp b/src/OrcLib/FileFind.cpp index 32d15a84..bf26c0f4 100644 --- a/src/OrcLib/FileFind.cpp +++ b/src/OrcLib/FileFind.cpp @@ -765,7 +765,7 @@ std::shared_ptr FileFind::GetSearchTermFromConfig(const Co fs->dwAttrType = _wtoi(item[CONFIG_FILEFIND_ATTR_TYPE].c_str()); if (fs->dwAttrType == 0) { - Log::Warn(L"Invalid attribute type passed: {}", item[CONFIG_FILEFIND_ATTR_TYPE]); + Log::Warn(L"Invalid attribute type passed: {}", item[CONFIG_FILEFIND_ATTR_TYPE].c_str()); fs->Required = static_cast(fs->Required & ~FileFind::SearchTerm::ATTR_TYPE); } @@ -781,7 +781,7 @@ std::shared_ptr FileFind::GetSearchTermFromConfig(const Co catch (Orc::Exception& e) { auto [hr, msg] = AnsiToWide(e.what()); - Log::Warn(L"Exception while processing '{}': {}", item[CONFIG_FILEFIND_SIZE], msg); + Log::Warn(L"Exception while processing '{}': {}", item[CONFIG_FILEFIND_SIZE].c_str(), msg); } } if (item[CONFIG_FILEFIND_SIZE_GT]) @@ -794,7 +794,7 @@ std::shared_ptr FileFind::GetSearchTermFromConfig(const Co catch (Orc::Exception& e) { auto [hr, msg] = AnsiToWide(e.what()); - Log::Warn(L"Exception while processing '{}': {}", item[CONFIG_FILEFIND_SIZE_GT], msg); + Log::Warn(L"Exception while processing '{}': {}", item[CONFIG_FILEFIND_SIZE_GT].c_str(), msg); } } if (item[CONFIG_FILEFIND_SIZE_GE]) @@ -833,7 +833,7 @@ std::shared_ptr FileFind::GetSearchTermFromConfig(const Co catch (Orc::Exception& e) { auto [hr, msg] = AnsiToWide(e.what()); - Log::Warn(L"Exception while processing '{}': {}", item[CONFIG_FILEFIND_SIZE_LE], msg); + Log::Warn(L"Exception while processing '{}': {}", item[CONFIG_FILEFIND_SIZE_LE].c_str(), msg); } } if (item[CONFIG_FILEFIND_MD5]) @@ -848,7 +848,7 @@ std::shared_ptr FileFind::GetSearchTermFromConfig(const Co fs->Required |= FileFind::SearchTerm::DATA_MD5; else { - Log::Warn(L"Invalid hex string passed as md5: {}", item[CONFIG_FILEFIND_MD5]); + Log::Warn(L"Invalid hex string passed as md5: {}", item[CONFIG_FILEFIND_MD5].c_str()); } } if (item[CONFIG_FILEFIND_SHA1]) @@ -863,7 +863,7 @@ std::shared_ptr FileFind::GetSearchTermFromConfig(const Co fs->Required |= FileFind::SearchTerm::DATA_SHA1; else { - Log::Warn(L"Invalid hex string passed as sha1: {}", item[CONFIG_FILEFIND_SHA1]); + Log::Warn(L"Invalid hex string passed as sha1: {}", item[CONFIG_FILEFIND_SHA1].c_str()); } } if (item[CONFIG_FILEFIND_SHA256]) @@ -878,7 +878,7 @@ std::shared_ptr FileFind::GetSearchTermFromConfig(const Co fs->Required |= FileFind::SearchTerm::DATA_SHA256; else { - Log::Warn(L"Invalid hex string passed as sha256: {}", item[CONFIG_FILEFIND_SHA256]); + Log::Warn(L"Invalid hex string passed as sha256: {}", item[CONFIG_FILEFIND_SHA256].c_str()); } } if (item[CONFIG_FILEFIND_CONTAINS]) @@ -895,7 +895,7 @@ std::shared_ptr FileFind::GetSearchTermFromConfig(const Co { Log::Warn( L"string '{}' passed as binstring could not be converted to ANSI [{}]", - item[CONFIG_FILEFIND_CONTAINS], + item[CONFIG_FILEFIND_CONTAINS].c_str(), SystemError(hr)); } } @@ -912,7 +912,7 @@ std::shared_ptr FileFind::GetSearchTermFromConfig(const Co } else { - Log::Warn(L"Invalid hex string passed as binstring '{}'", item[CONFIG_FILEFIND_CONTAINS_HEX]); + Log::Warn(L"Invalid hex string passed as binstring '{}'", item[CONFIG_FILEFIND_CONTAINS_HEX].c_str()); } } if (item[CONFIG_FILEFIND_HEADER]) @@ -928,7 +928,7 @@ std::shared_ptr FileFind::GetSearchTermFromConfig(const Co { Log::Warn( L"String '{}' passed as header string could not be converted to ANSI [{}]", - item[CONFIG_FILEFIND_HEADER], + item[CONFIG_FILEFIND_HEADER].c_str(), SystemError(hr)); } } @@ -946,7 +946,9 @@ std::shared_ptr FileFind::GetSearchTermFromConfig(const Co else { Log::Warn( - L"Invalid hex string passed as header: {} [{}]", item[CONFIG_FILEFIND_HEADER_HEX], SystemError(hr)); + L"Invalid hex string passed as header: {} [{}]", + item[CONFIG_FILEFIND_HEADER_HEX].c_str(), + SystemError(hr)); } } if (item[CONFIG_FILEFIND_HEADER_REGEX]) @@ -955,7 +957,9 @@ std::shared_ptr FileFind::GetSearchTermFromConfig(const Co if (FAILED(hr = WideToAnsi((std::wstring_view)item[CONFIG_FILEFIND_HEADER_REGEX], ansiRegEx))) { Log::Warn( - L"Invalid hex string passed as header: {} [{}]", item[CONFIG_FILEFIND_HEADER_HEX], SystemError(hr)); + L"Invalid hex string passed as header: {} [{}]", + item[CONFIG_FILEFIND_HEADER_HEX].c_str(), + SystemError(hr)); } else { diff --git a/src/OrcLib/OutputSpec.cpp b/src/OrcLib/OutputSpec.cpp index ec1c265a..a918a139 100644 --- a/src/OrcLib/OutputSpec.cpp +++ b/src/OrcLib/OutputSpec.cpp @@ -308,7 +308,7 @@ OutputSpec::Configure(OutputSpec::Kind supported, const ConfigItem& item, std::o { if (FAILED(hr = Configure(supported, item.c_str()))) { - Log::Error(L"An error occured when evaluating output item {}", item); + Log::Error(L"An error occured when evaluating output item {}", item.c_str()); return hr; } if (::HasValue(item, CONFIG_OUTPUT_FORMAT)) @@ -330,7 +330,8 @@ OutputSpec::Configure(OutputSpec::Kind supported, const ConfigItem& item, std::o } else { - Log::Error(L"Invalid encoding for outputdir in config file: {}", item.SubItems[CONFIG_OUTPUT_ENCODING]); + Log::Error( + L"Invalid encoding for outputdir in config file: {}", item.SubItems[CONFIG_OUTPUT_ENCODING].c_str()); return E_INVALIDARG; } } @@ -415,7 +416,7 @@ HRESULT OutputSpec::Upload::Configure(const ConfigItem& item) Uri uri(configUploadUri, ec); if (ec) { - Log::Error(L"Failed to parse uri '{}' [{}]", item.SubItems[CONFIG_UPLOAD_URI], ec); + Log::Error(L"Failed to parse uri '{}' [{}]", item.SubItems[CONFIG_UPLOAD_URI].c_str(), ec); return E_INVALIDARG; } diff --git a/src/OrcLib/RegFind.cpp b/src/OrcLib/RegFind.cpp index 9d18e77d..4fd41231 100644 --- a/src/OrcLib/RegFind.cpp +++ b/src/OrcLib/RegFind.cpp @@ -375,7 +375,7 @@ std::shared_ptr RegFind::GetSearchTermFromConfig(const Conf if (FAILED(hr = GetBytesFromHexaString(Data.c_str(), static_cast(Data.size()), retval->m_DataContent))) { - Log::Error(L"Invalid bytes for content '{}' [{}]", item[CONFIG_REGFIND_DATA_HEX], SystemError(hr)); + Log::Error(L"Invalid bytes for content '{}' [{}]", item[CONFIG_REGFIND_DATA_HEX].c_str(), SystemError(hr)); return nullptr; } // Also initiate unicode version of pattern (in case pattern tested against SZ values) @@ -390,7 +390,8 @@ std::shared_ptr RegFind::GetSearchTermFromConfig(const Conf LARGE_INTEGER li = {0}; if (FAILED(hr = GetFileSizeFromArg(item[CONFIG_REGFIND_DATA_SIZE].c_str(), li))) { - Log::Error(L"Invalid file size specification: '{}' [{}]", item[CONFIG_REGFIND_DATA_SIZE], SystemError(hr)); + Log::Error( + L"Invalid file size specification: '{}' [{}]", item[CONFIG_REGFIND_DATA_SIZE].c_str(), SystemError(hr)); return nullptr; } if (li.QuadPart < 0) @@ -412,14 +413,16 @@ std::shared_ptr RegFind::GetSearchTermFromConfig(const Conf if (FAILED(hr = GetFileSizeFromArg(item[CONFIG_REGFIND_DATA_SIZE_LT].c_str(), li))) { Log::Error( - L"Invalid file size specification: '{}' [{}]", item[CONFIG_REGFIND_DATA_SIZE_LT], SystemError(hr)); + L"Invalid file size specification: '{}' [{}]", + item[CONFIG_REGFIND_DATA_SIZE_LT].c_str(), + SystemError(hr)); return nullptr; } if (li.QuadPart < 0) { Log::Error( L"Invalid negative file size specification: '{}' [{}]", - item[CONFIG_REGFIND_DATA_SIZE], + item[CONFIG_REGFIND_DATA_SIZE].c_str(), SystemError(hr)); return nullptr; } @@ -439,12 +442,14 @@ std::shared_ptr RegFind::GetSearchTermFromConfig(const Conf if (FAILED(hr = GetFileSizeFromArg(item[CONFIG_REGFIND_DATA_SIZE_GT].c_str(), li))) { Log::Error( - L"Invalid file size specification: '{}' [{}]", item[CONFIG_REGFIND_DATA_SIZE_GT], SystemError(hr)); + L"Invalid file size specification: '{}' [{}]", + item[CONFIG_REGFIND_DATA_SIZE_GT].c_str(), + SystemError(hr)); return nullptr; } if (li.QuadPart < 0) { - Log::Error(L"Invalid negative file size specification: '{}'", item[CONFIG_REGFIND_DATA_SIZE]); + Log::Error(L"Invalid negative file size specification: '{}'", item[CONFIG_REGFIND_DATA_SIZE].c_str()); return nullptr; } @@ -459,12 +464,12 @@ std::shared_ptr RegFind::GetSearchTermFromConfig(const Conf if (FAILED(hr = GetFileSizeFromArg(item[CONFIG_REGFIND_DATA_SIZE_LE].c_str(), li))) { Log::Error( - L"Invalid file size specification: '{}' [{}]", item[CONFIG_REGFIND_DATA_SIZE_LE], SystemError(hr)); + L"Invalid file size specification: '{}' [{}]", item[CONFIG_REGFIND_DATA_SIZE_LE].c_str(), SystemError(hr)); return nullptr; } if (li.QuadPart < 0) { - Log::Error(L"Invalid negative file size specification: '{}'", item[CONFIG_REGFIND_DATA_SIZE]); + Log::Error(L"Invalid negative file size specification: '{}'", item[CONFIG_REGFIND_DATA_SIZE].c_str()); return nullptr; } @@ -479,12 +484,14 @@ std::shared_ptr RegFind::GetSearchTermFromConfig(const Conf if (FAILED(hr = GetFileSizeFromArg(item[CONFIG_REGFIND_DATA_SIZE_GE].c_str(), li))) { Log::Error( - L"Invalid file size specification: '{}' [{}]", item[CONFIG_REGFIND_DATA_SIZE_GE], SystemError(hr)); + L"Invalid file size specification: '{}' [{}]", + item[CONFIG_REGFIND_DATA_SIZE_GE].c_str(), + SystemError(hr)); return nullptr; } if (li.QuadPart < 0) { - Log::Error(L"Invalid negative file size specification: '{}'", item[CONFIG_REGFIND_DATA_SIZE]); + Log::Error(L"Invalid negative file size specification: '{}'", item[CONFIG_REGFIND_DATA_SIZE].c_str()); return nullptr; } From dcf849df94ae709ec1b8261b044442af9a095cbb Mon Sep 17 00:00:00 2001 From: Jean Gautier Date: Thu, 31 Aug 2023 15:03:29 +0200 Subject: [PATCH 04/35] OrcLib: Flags: add FlagsToStringW --- src/OrcLib/Flags.cpp | 23 +++++++++++++++++++++++ src/OrcLib/Flags.h | 1 + 2 files changed, 24 insertions(+) diff --git a/src/OrcLib/Flags.cpp b/src/OrcLib/Flags.cpp index e5050369..bde1ad65 100644 --- a/src/OrcLib/Flags.cpp +++ b/src/OrcLib/Flags.cpp @@ -48,6 +48,29 @@ std::string FlagsToString(DWORD flags, const FlagsDefinition flagValues[], CHAR return out; } +std::wstring FlagsToStringW(DWORD flags, const FlagsDefinition flagValues[], WCHAR separator) +{ + std::wstring out; + + bool bFirst = true; + for (size_t index = 0; flagValues[index].dwFlag != 0xFFFFFFFF; ++index) + { + if (flags & flagValues[index].dwFlag) + { + if (bFirst) + { + bFirst = false; + fmt::format_to(std::back_inserter(out), L"{}", flagValues[index].szShortDescr); + continue; + } + + fmt::format_to(std::back_inserter(out), L"{}{}", separator, flagValues[index].szShortDescr); + } + } + + return out; +} + std::optional ExactFlagToString(DWORD dwFlags, const FlagsDefinition FlagValues[]) { int idx = 0; diff --git a/src/OrcLib/Flags.h b/src/OrcLib/Flags.h index 9d6b0e0c..a18ad6c4 100644 --- a/src/OrcLib/Flags.h +++ b/src/OrcLib/Flags.h @@ -22,6 +22,7 @@ struct FlagsDefinition }; std::string FlagsToString(DWORD flags, const FlagsDefinition flagValues[], CHAR separator = '|'); +std::wstring FlagsToStringW(DWORD flags, const FlagsDefinition flagValues[], WCHAR separator = '|'); // There are FlagsDefinition structure which are used without being flags. Multiple // functions where doing this conversion without using any mask but raw value. From d7cddc0aa01fdcec83e885859ba6f029fcd16fad Mon Sep 17 00:00:00 2001 From: Jean Gautier Date: Thu, 31 Aug 2023 15:03:51 +0200 Subject: [PATCH 05/35] OrcLib: NtDllExtension: add CodeIntegrityOption --- src/OrcLib/NtDllExtension.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/OrcLib/NtDllExtension.h b/src/OrcLib/NtDllExtension.h index 193bff29..8e5e22dc 100644 --- a/src/OrcLib/NtDllExtension.h +++ b/src/OrcLib/NtDllExtension.h @@ -10,6 +10,7 @@ #include "OrcLib.h" #include "ExtensionLibrary.h" +#include "Flags.h" #include #include @@ -167,6 +168,23 @@ class NtDllExtension : public ExtensionLibrary PULONG ReturnLength) = nullptr; }; +static constexpr FlagsDefinition CodeIntegrityOptions[] = { + {CODEINTEGRITY_OPTION_ENABLED, L"CODEINTEGRITY_OPTION_ENABLED", L"Enforcement of kernel mode Code Integrity is enabled"}, + {CODEINTEGRITY_OPTION_TESTSIGN, L"CODEINTEGRITY_OPTION_TESTSIGN", L"Test signing of kernel mode binaries is enabled"}, + {CODEINTEGRITY_OPTION_UMCI_ENABLED, L"CODEINTEGRITY_OPTION_UMCI_ENABLED", L"Enforcement of user mode Code Integrity is enabled"}, + {CODEINTEGRITY_OPTION_UMCI_AUDITMODE_ENABLED, L"CODEINTEGRITY_OPTION_UMCI_AUDITMODE_ENABLED", L"Audit mode of user mode Code Integrity is enabled"}, + {CODEINTEGRITY_OPTION_UMCI_EXCLUSIONPATHS_ENABLED, L"CODEINTEGRITY_OPTION_UMCI_EXCLUSIONPATHS_ENABLED", L"Exclusion paths of user mode Code Integrity are enabled"}, + {CODEINTEGRITY_OPTION_TEST_BUILD, L"CODEINTEGRITY_OPTION_TEST_BUILD", L"Test build of kernel mode binaries is enabled"}, + {CODEINTEGRITY_OPTION_PREPRODUCTION_BUILD, L"CODEINTEGRITY_OPTION_PREPRODUCTION_BUILD", L"Preproduction build of kernel mode binaries is enabled"}, + {CODEINTEGRITY_OPTION_DEBUGMODE_ENABLED, L"CODEINTEGRITY_OPTION_DEBUGMODE_ENABLED", L"Debug mode of kernel mode binaries is enabled"}, + {CODEINTEGRITY_OPTION_FLIGHT_BUILD, L"CODEINTEGRITY_OPTION_FLIGHT_BUILD", L"Flight build of kernel mode binaries is enabled"}, + {CODEINTEGRITY_OPTION_FLIGHTING_ENABLED, L"CODEINTEGRITY_OPTION_FLIGHTING_ENABLED", L"Flighting of kernel mode binaries is enabled"}, + {CODEINTEGRITY_OPTION_HVCI_KMCI_ENABLED, L"CODEINTEGRITY_OPTION_HVCI_KMCI_ENABLED", L"Hypervisor enforced Code Integrity is enabled"}, + {CODEINTEGRITY_OPTION_HVCI_KMCI_AUDITMODE_ENABLED, L"CODEINTEGRITY_OPTION_HVCI_KMCI_AUDITMODE_ENABLED", L"Audit mode of hypervisor enforced Code Integrity is enabled"}, + {CODEINTEGRITY_OPTION_HVCI_KMCI_STRICTMODE_ENABLED, L"CODEINTEGRITY_OPTION_HVCI_KMCI_STRICTMODE_ENABLED", L"Strict mode of hypervisor enforced Code Integrity is enabled"}, + {CODEINTEGRITY_OPTION_HVCI_KMCI_AUDITMODE_ENABLED, L"CODEINTEGRITY_OPTION_HVCI_KMCI_AUDITMODE_ENABLED", L"Audit mode of hypervisor enforced Code Integrity is enabled"} +}; + } // namespace Orc #pragma managed(pop) From f1d93ce827521b3da4680eacc02a9991c5e7443a Mon Sep 17 00:00:00 2001 From: Jean Gautier Date: Mon, 4 Sep 2023 22:52:49 +0200 Subject: [PATCH 06/35] OrcLib: Buffer: add WStrLen Correctly compute the size of a UnicodeString. --- src/OrcLib/Buffer.h | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/OrcLib/Buffer.h b/src/OrcLib/Buffer.h index 41351865..5b3682a5 100644 --- a/src/OrcLib/Buffer.h +++ b/src/OrcLib/Buffer.h @@ -811,7 +811,22 @@ class Buffer return 0; ULONG len = 0; - auto pCur = get(); + auto pCur = get_as(); + while (len < size() && *pCur != 0) + { + pCur++; + len++; + } + return len; + } + + ULONG WStrNLen() const + { + if (empty()) + return 0; + + ULONG len = 0; + auto pCur = get_as(); while (len < size() && *pCur != 0) { pCur++; @@ -902,7 +917,7 @@ class Buffer if (_size == 0) return std::wstring(); - auto stringLength = StrNLen(); + auto stringLength = WStrNLen(); if (stringLength == 0) return std::wstring(); From 4406e2422cb844700a9b32c0e1dd63fea84c5bc8 Mon Sep 17 00:00:00 2001 From: Jean Gautier Date: Thu, 7 Sep 2023 11:41:36 +0200 Subject: [PATCH 07/35] OrcLib: SystemDetails: replace Windows version detection Base system tags deduction build numbers rather than kernel version (5, 6, 7, 10, 10...). --- src/OrcLib/SystemDetails.cpp | 353 ++++++++++++++++++++++++++--------- src/OrcLib/SystemDetails.h | 3 + 2 files changed, 263 insertions(+), 93 deletions(-) diff --git a/src/OrcLib/SystemDetails.cpp b/src/OrcLib/SystemDetails.cpp index 3408684d..e0bc4eaa 100644 --- a/src/OrcLib/SystemDetails.cpp +++ b/src/OrcLib/SystemDetails.cpp @@ -104,6 +104,265 @@ HRESULT SystemDetails::GetSystemType(std::wstring& strProductType) return S_OK; } + +bool SystemDetails::IsKnownWindowsBuild(uint32_t build) +{ + switch (build) + { + case 22621: + case 22000: + case 20348: + case 19045: + case 19044: + case 19043: + case 19042: + case 19041: + case 18363: + case 18362: + case 17763: + case 17134: + case 16299: + case 15063: + case 14393: + case 10586: + case 10240: + case 9600: + case 9200: + case 7601: + case 7600: + case 6003: + case 6002: + case 6001: + case 6000: + case 4500: + case 3790: + case 2600: + return true; + default: + Log::Warn(L"Build number {} is not associated with any known Windows release", build); + return false; + } +} + +void SystemDetails::GetTagsFromBuildId(uint32_t ProductType, uint32_t build, SystemTags& tags) +{ + tags.insert(fmt::format(L"OSBuild#{}", build)); + + if (ProductType != VER_NT_WORKSTATION && ProductType != VER_NT_SERVER && ProductType != VER_NT_DOMAIN_CONTROLLER) + { + Log::Warn( + L"ProductType {} is out of valid values range, we \"reset\" it to VER_NT_WORKSTATION", ProductType); + ProductType = VER_NT_WORKSTATION; + } + + // reference: https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions + + switch (build) + { + case 22621: + tags.insert(L"Windows11"); + tags.insert(L"Release#22H2"); + break; + case 22000: + tags.insert(L"Windows11"); + tags.insert(L"Release#21H2"); + break; + case 20348: + tags.insert(L"WindowsServer2022"); + tags.insert(L"Release#RTM"); + break; + case 19045: + tags.insert(L"Windows10"); + tags.insert(L"Release#22H2"); + break; + case 19044: + tags.insert(L"Windows10"); + tags.insert(L"Release#21H2"); + break; + case 19043: + tags.insert(L"Windows10"); + tags.insert(L"Release#21H1"); + break; + case 19042: + tags.insert(L"Windows10"); + tags.insert(L"Release#20H2"); + break; + case 19041: + tags.insert(L"Windows10"); + tags.insert(L"Release#2004"); + break; + case 18363: + tags.insert(L"Windows10"); + tags.insert(L"Release#1909"); + break; + case 18362: + tags.insert(L"Windows10"); + tags.insert(L"Release#1903"); + break; + case 17763: + switch (ProductType) + { + case VER_NT_WORKSTATION: + tags.insert(L"Windows10"); + break; + case VER_NT_SERVER: + case VER_NT_DOMAIN_CONTROLLER: + tags.insert(L"WindowsServer2019"); + break; + } + tags.insert(L"Release#1809"); + break; + case 17134: + tags.insert(L"Windows10"); + tags.insert(L"Release#1803"); + break; + case 16299: + switch (ProductType) + { + case VER_NT_WORKSTATION: + tags.insert(L"Windows10"); + break; + case VER_NT_SERVER: + case VER_NT_DOMAIN_CONTROLLER: + tags.insert(L"WindowsServer2016"); + break; + } + tags.insert(L"Release#1709"); + break; + case 15063: + tags.insert(L"Windows10"); + tags.insert(L"Release#1703"); + break; + case 14393: + switch (ProductType) + { + case VER_NT_WORKSTATION: + tags.insert(L"Windows10"); + break; + case VER_NT_SERVER: + case VER_NT_DOMAIN_CONTROLLER: + tags.insert(L"WindowsServer2016"); + break; + } + tags.insert(L"Release#1607"); + break; + case 10586: + tags.insert(L"Windows10"); + tags.insert(L"Release#1511"); + break; + case 10240: + tags.insert(L"Windows10"); + tags.insert(L"Release#1507"); + tags.insert(L"Release#RTM"); + break; + case 9600: + switch (ProductType) + { + case VER_NT_WORKSTATION: + tags.insert(L"Windows8.1"); + tags.insert(L"Release#Update1"); + break; + case VER_NT_SERVER: + case VER_NT_DOMAIN_CONTROLLER: + tags.insert(L"WindowsServer2012R2"); + tags.insert(L"Release#RTM"); + break; + } + + break; + case 9200: + switch (ProductType) + { + case VER_NT_WORKSTATION: + tags.insert(L"Windows8"); + tags.insert(L"Release#RTM"); + break; + case VER_NT_SERVER: + case VER_NT_DOMAIN_CONTROLLER: + tags.insert(L"WindowsServer2012"); + tags.insert(L"Release#RTM"); + break; + } + break; + case 7601: + tags.insert(L"Windows7"); + tags.insert(L"Release#SP1"); + break; + case 8400: + tags.insert(L"WindowsHomeServer2011"); + tags.insert(L"Release#RTM"); + break; + case 7600: + switch (ProductType) + { + case VER_NT_WORKSTATION: + tags.insert(L"Windows7"); + tags.insert(L"Release#RTM"); + break; + case VER_NT_SERVER: + case VER_NT_DOMAIN_CONTROLLER: + tags.insert(L"WindowsServer2008R2"); + tags.insert(L"Release#RTM"); + break; + } + break; + case 6003: + tags.insert(L"WindowsServer2008"); + tags.insert(L"Release#RTM"); + break; + case 6002: + switch (ProductType) + { + case VER_NT_WORKSTATION: + tags.insert(L"WindowsVista"); + tags.insert(L"Release#SP2"); + break; + case VER_NT_SERVER: + case VER_NT_DOMAIN_CONTROLLER: + tags.insert(L"WindowsServer2008"); + tags.insert(L"Release#SP2"); + break; + } + break; + tags.insert(L"WindowsVista"); + tags.insert(L"Release#SP2"); + break; + case 6001: + switch (ProductType) + { + case VER_NT_WORKSTATION: + tags.insert(L"WindowsVista"); + tags.insert(L"Release#SP1"); + break; + case VER_NT_SERVER: + case VER_NT_DOMAIN_CONTROLLER: + tags.insert(L"WindowsServer2008"); + tags.insert(L"Release#RTM"); + break; + } + break; + case 6000: + tags.insert(L"WindowsVista"); + tags.insert(L"Release#RTM"); + break; + case 3790: + tags.insert(L"WindowsServer2003"); + tags.insert(L"Release#RTM"); + break; + case 4500: + tags.insert(L"WindowsHomeServer"); + tags.insert(L"Release#RTM"); + break; + case 2600: + tags.insert(L"WindowsXP"); + tags.insert(L"Release#SP2"); + break; + default: + Log::Warn(L"Build number {} is not associated with any known Windows release", build); + break; + } +} + HRESULT Orc::SystemDetails::GetSystemType(BYTE& systemType) { HRESULT hr = E_FAIL; @@ -148,97 +407,7 @@ const SystemTags& Orc::SystemDetails::GetSystemTags() if (auto hr = Orc::SystemDetails::GetSystemType(systemType); FAILED(hr)) throw Exception(Severity::Fatal, hr, L"System type not available"sv); - switch (major) - { - case 5: - switch (minor) - { - case 1: - case 2: - switch (systemType) - { - case VER_NT_WORKSTATION: - tags.insert(L"WindowsXP"s); - break; - case VER_NT_SERVER: - case VER_NT_DOMAIN_CONTROLLER: - tags.insert(L"WindowsServer2003"s); - break; - } - break; - default: - break; - } - break; - case 6: - switch (minor) - { - case 0: - switch (systemType) - { - case VER_NT_WORKSTATION: - tags.insert(L"WindowsVista"s); - break; - case VER_NT_SERVER: - case VER_NT_DOMAIN_CONTROLLER: - tags.insert(L"WindowsServer2008"s); - break; - } - break; - case 1: - switch (systemType) - { - case VER_NT_WORKSTATION: - tags.insert(L"Windows7"s); - break; - case VER_NT_SERVER: - case VER_NT_DOMAIN_CONTROLLER: - tags.insert(L"WindowsServer2008R2"s); - break; - } - break; - case 2: - switch (systemType) - { - case VER_NT_WORKSTATION: - tags.insert(L"Windows8"s); - break; - case VER_NT_SERVER: - case VER_NT_DOMAIN_CONTROLLER: - tags.insert(L"WindowsServer2012"s); - break; - } - break; - case 3: - switch (systemType) - { - case VER_NT_WORKSTATION: - tags.insert(L"Windows8.1"s); - break; - case VER_NT_SERVER: - case VER_NT_DOMAIN_CONTROLLER: - tags.insert(L"WindowsServer2012R2"s); - break; - } - break; - } - break; - case 10: - switch (systemType) - { - case VER_NT_WORKSTATION: - tags.insert(L"Windows10"s); - break; - case VER_NT_SERVER: - case VER_NT_DOMAIN_CONTROLLER: - tags.insert(L"WindowsServer2016"s); - break; - } - break; - break; - default: - break; - } + GetTagsFromBuildId(systemType, g_pDetailsBlock->osvi.dwBuildNumber, tags); switch (g_pDetailsBlock->osvi.wServicePackMajor) { @@ -257,8 +426,6 @@ const SystemTags& Orc::SystemDetails::GetSystemTags() throw Exception(Severity::Fatal, hr, L"System type not available"sv); tags.insert(strProductType); - tags.insert(fmt::format(L"OSBuild#{}", g_pDetailsBlock->osvi.dwBuildNumber)); - HKEY current_version; if (RegOpenKeyW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", ¤t_version) == ERROR_SUCCESS) diff --git a/src/OrcLib/SystemDetails.h b/src/OrcLib/SystemDetails.h index baebd7bd..e2b039f8 100644 --- a/src/OrcLib/SystemDetails.h +++ b/src/OrcLib/SystemDetails.h @@ -45,6 +45,9 @@ class SystemDetails static HRESULT GetSystemType(std::wstring& strSystemType); static HRESULT GetSystemType(BYTE& systemType); + static bool IsKnownWindowsBuild(uint32_t build); + static void GetTagsFromBuildId(uint32_t ProductType, uint32_t build, SystemTags& tags); + static const SystemTags& GetSystemTags(); static HRESULT SetSystemTags(SystemTags tags); From 45b560522fe40a5c3fcc90844d3ba4a63d43223c Mon Sep 17 00:00:00 2001 From: Jean Gautier Date: Wed, 20 Sep 2023 15:59:08 +0200 Subject: [PATCH 08/35] OrcLib: remove unused ORCLIB_API define --- src/OrcLib/OrcLib.h | 14 -------------- src/OrcLib/YaraExtension.h | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/src/OrcLib/OrcLib.h b/src/OrcLib/OrcLib.h index ff7fa06a..50f19d89 100644 --- a/src/OrcLib/OrcLib.h +++ b/src/OrcLib/OrcLib.h @@ -7,20 +7,6 @@ // #pragma once -// The following ifdef block is the standard way of creating macros which make exporting -// from a DLL simpler. All files within this DLL are compiled with the TASKAGENT_EXPORTS -// symbol defined on the command line. this symbol should not be defined on any project -// that uses this DLL. This way any other project whose source files include this file see -// TASKAGENT_API functions as being imported from a DLL, whereas this DLL sees symbols -// defined with this macro as being exported. -#ifdef ORCLIB_EXPORTS -# define __declspec(dllexport) -#elif ORCLIB_IMPORTS -# define __declspec(dllimport) -#else // STATIC linking -# define ORCLIB_API -#endif - #pragma managed(push, off) #include diff --git a/src/OrcLib/YaraExtension.h b/src/OrcLib/YaraExtension.h index 9af7b4a1..bb6faaeb 100644 --- a/src/OrcLib/YaraExtension.h +++ b/src/OrcLib/YaraExtension.h @@ -21,7 +21,7 @@ namespace Orc { -class ORCLIB_API YaraExtension : public ExtensionLibrary +class YaraExtension : public ExtensionLibrary { friend class ExtensionLibrary; From 6c7d24ef412ff0733b7fced6b91ec98e94abfa50 Mon Sep 17 00:00:00 2001 From: Jean Gautier Date: Thu, 5 Oct 2023 18:12:35 +0200 Subject: [PATCH 09/35] OrcLib: UtiltiesMain: add methods ToolName, ToolVersion, ToolDescription Open to version definition outside kOrcFileVerStringW. Add default Tool*() functions. --- src/OrcCommand/UtilitiesMain.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/OrcCommand/UtilitiesMain.h b/src/OrcCommand/UtilitiesMain.h index d71edbbe..e7313c09 100644 --- a/src/OrcCommand/UtilitiesMain.h +++ b/src/OrcCommand/UtilitiesMain.h @@ -797,6 +797,14 @@ class UtilitiesMain virtual HRESULT GetConfigurationFromArgcArgv(int argc, const WCHAR* argv[]) = 0; virtual HRESULT CheckConfiguration() = 0; + // + // Tool Description + // + static LPCWSTR ToolName() { return kOrcMetaNameW; } + static LPCWSTR ToolDescription() { return L"DFIR-ORC Windows artefact collection tool"; } + static LPCWSTR ToolVersion() { return kOrcVersionStringW; } + + // // Output handling // @@ -850,7 +858,7 @@ class UtilitiesMain // TODO: FIXME Cmd.LoadCommonExtensions(); - Cmd.PrintHeader(UtilityT::ToolName(), UtilityT::ToolDescription(), kOrcFileVerStringW); + Cmd.PrintHeader(UtilityT::ToolName(), UtilityT::ToolDescription(), UtilityT::ToolVersion()); try { From be40298e367ad91f8e6e55cd30661dad2c474a02 Mon Sep 17 00:00:00 2001 From: Jean Gautier Date: Fri, 13 Oct 2023 08:34:29 +0200 Subject: [PATCH 10/35] OrcLib: Temporary: replace obsolete string id --- src/OrcLib/Temporary.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrcLib/Temporary.cpp b/src/OrcLib/Temporary.cpp index 08f19697..83514e3f 100644 --- a/src/OrcLib/Temporary.cpp +++ b/src/OrcLib/Temporary.cpp @@ -158,7 +158,7 @@ HRESULT Orc::UtilGetTempFile( while (dwRetries < CREATION_RETRIES) { - if (GetTempFileName(pwszDir, L"NTRACK", 0, wszTempFilePath)) + if (GetTempFileName(pwszDir, L"DFIR-ORC", 0, wszTempFilePath)) { if (pwszExt) { From b43744fd9d67e870f89181bc09666886d196cf1e Mon Sep 17 00:00:00 2001 From: Jean Gautier Date: Fri, 13 Oct 2023 08:35:18 +0200 Subject: [PATCH 11/35] OrcLib: Text: Hex: replace string_view by BufferView --- src/OrcLib/Text/Hex.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OrcLib/Text/Hex.h b/src/OrcLib/Text/Hex.h index 7c784621..5b6b8e9f 100644 --- a/src/OrcLib/Text/Hex.h +++ b/src/OrcLib/Text/Hex.h @@ -157,8 +157,8 @@ OutputIt ToHex(InputIt first, InputIt last, OutputIt out) for (auto it = first; it != last; ++it) { - std::string_view input(reinterpret_cast(&(*it)), sizeof(typename InputIt::value_type)); - for (int i = input.size() - 1; i >= 0; --i) + BufferView input(reinterpret_cast(&(*it)), sizeof(typename InputIt::value_type)); + for (int i = static_cast(input.size()) - 1; i >= 0; --i) { *out++ = hex[(input[i] >> 4) & 0x0F]; *out++ = hex[input[i] & 0x0F]; From 7401ad57820e47f00530a11fae9fa27421f5d2cd Mon Sep 17 00:00:00 2001 From: Jean Gautier Date: Fri, 13 Oct 2023 08:35:42 +0200 Subject: [PATCH 12/35] OrcLib: Text: Guid: replace str::string_view with BufferView --- src/OrcLib/Text/Guid.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/OrcLib/Text/Guid.h b/src/OrcLib/Text/Guid.h index a6df0939..5f000976 100644 --- a/src/OrcLib/Text/Guid.h +++ b/src/OrcLib/Text/Guid.h @@ -17,6 +17,7 @@ #include #include "Text/Hex.h" +#include "Utils/BufferView.h" #include "Utils/Result.h" #include "Utils/TypeTraits.h" @@ -54,13 +55,13 @@ void ToString(const GUID& guid, OutputIt out) } const auto data4leftLength = 2; - std::string_view data4Left(reinterpret_cast(&guid.Data4[0]), data4leftLength); + BufferView data4Left(reinterpret_cast(&guid.Data4[0]), data4leftLength); ToHex(std::cbegin(data4Left), std::cend(data4Left), out); *out++ = '-'; - std::string_view data4right( - reinterpret_cast(&guid.Data4[data4leftLength]), sizeof(guid.Data4) - data4leftLength); + BufferView data4right( + reinterpret_cast(&guid.Data4[data4leftLength]), sizeof(guid.Data4) - data4leftLength); ToHex(std::cbegin(data4right), std::cend(data4right), out); *out++ = '}'; From 4f80cb2f0336ea71a746028e71d2f01580be8bf7 Mon Sep 17 00:00:00 2001 From: Jean Gautier Date: Mon, 16 Oct 2023 18:39:16 +0200 Subject: [PATCH 13/35] OrcLib: ExtensionLibrary: add support for DependencyLibrary Add DependencyLibrary to handle extension libraries depending on other dlls. --- src/OrcLib/ExtensionLibrary.cpp | 62 +++++++++++++++++++++++++++------ src/OrcLib/ExtensionLibrary.h | 36 ++++++++++++++----- 2 files changed, 80 insertions(+), 18 deletions(-) diff --git a/src/OrcLib/ExtensionLibrary.cpp b/src/OrcLib/ExtensionLibrary.cpp index 47664d7f..96e06f7b 100644 --- a/src/OrcLib/ExtensionLibrary.cpp +++ b/src/OrcLib/ExtensionLibrary.cpp @@ -37,13 +37,34 @@ namespace Orc { ExtensionLibrary::ExtensionLibrary( const std::wstring& strKeyword, const std::wstring& strX86LibRef, - const std::wstring& strX64LibRef) + const std::wstring& strX64LibRef, + std::vector> dependencies) : m_strKeyword(strKeyword) , m_strX86LibRef(strX86LibRef) , m_strX64LibRef(strX64LibRef) + , m_Dependencies(std::move(dependencies)) { } +HRESULT Orc::ExtensionLibrary::LoadDependencies(std::optional tempDir) +{ + for (const auto& dependency : m_Dependencies) + { + if (dependency->IsLoaded()) + continue; + if (auto hr = dependency->Load(tempDir); FAILED(hr)) + { + Log::Error(L"Failed to load dependency library '{}'", dependency->Keyword()); + return hr; + } + else + { + Log::Debug(L"Loaded dependency library '{}'", dependency->Keyword()); + } + } + return S_OK; +} + HRESULT ExtensionLibrary::TryLoad(const std::wstring& strFileRef) { using namespace std::filesystem; @@ -300,6 +321,13 @@ HRESULT ExtensionLibrary::Load(std::optional tempDir) if (m_hModule != NULL) return S_OK; + if (auto hr = LoadDependencies(tempDir); FAILED(hr)) + { + Log::Error(L"Failed to load dependencies for extension library '{}'", m_strKeyword); + return hr; + } + + WORD wArch = 0; if (auto hr = SystemDetails::GetArchitecture(wArch); FAILED(hr)) return hr; @@ -383,12 +411,14 @@ HRESULT ExtensionLibrary::Load(std::optional tempDir) HRESULT ExtensionLibrary::UnLoad() { + // Remove the termination handler if (m_UnLoadHandler) { Robustness::RemoveTerminationHandler(m_UnLoadHandler); m_UnLoadHandler = nullptr; } + // Unload the library if (m_hModule != NULL) { ScopedLock lock(m_cs); @@ -396,6 +426,9 @@ HRESULT ExtensionLibrary::UnLoad() m_hModule = NULL; FreeThisLibrary(hmod); } + + // Unload dependencies (at least decrement ref count) + m_Dependencies.clear(); return S_OK; } @@ -435,22 +468,31 @@ HRESULT Orc::ExtensionLibrary::UnloadAndCleanup() m_hModule = NULL; FreeThisLibrary(hmod); + } - if (!m_libFile.empty() && m_bDeleteOnClose) + if (!m_libFile.empty() && m_bDeleteOnClose) + { + DWORD dwRetries = 0L; + while (dwRetries < Orc::DELETION_RETRIES) { - DWORD dwRetries = 0L; - while (dwRetries < Orc::DELETION_RETRIES) + HRESULT hr = E_FAIL; + if (SUCCEEDED(hr = UtilDeleteTemporaryFile(m_libFile.c_str(), 1))) { - HRESULT hr = E_FAIL; - if (SUCCEEDED(hr = UtilDeleteTemporaryFile(m_libFile.c_str(), 1))) - { - return S_OK; - } - dwRetries++; + return S_OK; + } + dwRetries++; + + if (m_hModule != NULL) // retry FreeLibrary + { + ScopedLock lock(m_cs); + HMODULE hmod = m_hModule; + m_hModule = NULL; + FreeThisLibrary(hmod); } } } + return S_OK; } diff --git a/src/OrcLib/ExtensionLibrary.h b/src/OrcLib/ExtensionLibrary.h index 5aa756c0..a335faa7 100644 --- a/src/OrcLib/ExtensionLibrary.h +++ b/src/OrcLib/ExtensionLibrary.h @@ -24,7 +24,6 @@ namespace Orc { template class ExtensionLibraryHandler : public TerminationHandler { - public: ExtensionLibraryHandler(const std::wstring& strDescr) : TerminationHandler(strDescr, ROBUSTNESS_UNLOAD_DLLS) {}; @@ -32,17 +31,19 @@ class ExtensionLibraryHandler : public TerminationHandler HRESULT operator()(); }; +class DependencyLibrary; + class ExtensionLibrary { - template friend class ExtensionLibraryHandler; public: - ExtensionLibrary( - const std::wstring& strKeyword, - const std::wstring& strX86LibRef, - const std::wstring& strX64LibRef); + ExtensionLibrary(const std::wstring& strKeyword, + const std::wstring& strX86LibRef, + const std::wstring& strX64LibRef, + std::vector> dependencies = {} + ); ExtensionLibrary(ExtensionLibrary&&) noexcept = default; @@ -56,8 +57,12 @@ class ExtensionLibrary return L"(invalid library name)"s; } + const auto& Keyword() const { + return m_strKeyword; + } + template - static const std::shared_ptr + static std::shared_ptr GetLibrary(std::optional tempDir = std::nullopt, bool bShared = true) { try @@ -122,9 +127,11 @@ class ExtensionLibrary protected: bool m_bInitialized = false; - CriticalSection m_cs; + HRESULT + LoadDependencies(std::optional tempDir = std::nullopt); + HRESULT TryLoad(const std::wstring& strFileRef); template @@ -212,6 +219,8 @@ class ExtensionLibrary bool m_bDeleteOnClose = false; std::shared_ptr m_UnLoadHandler; + std::vector> m_Dependencies; + HRESULT ToDesiredName(const std::wstring& libName); template @@ -242,6 +251,17 @@ class ExtensionLibrary } }; +class DependencyLibrary : public ExtensionLibrary +{ +public: + using Orc::ExtensionLibrary::ExtensionLibrary; + virtual std::pair LoadThisLibrary(const std::filesystem::path& libFile) + { + // dependency libraries are not loaded + return {S_OK, (HINSTANCE)NULL}; + } +}; + template class ExtensionInScope : private resource_scope> { From 528bb3f3bbe0075ebdbba60126f03e40c340c083 Mon Sep 17 00:00:00 2001 From: Jean Gautier Date: Thu, 19 Oct 2023 20:09:04 +0200 Subject: [PATCH 14/35] OrcLib: FileStream: add an option to delete on close FILE_FLAG_DELETE_ON_CLOSE is more reliable than usin DeleteFile. --- src/OrcLib/FileStream.h | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/OrcLib/FileStream.h b/src/OrcLib/FileStream.h index c6f9f21d..bf281652 100644 --- a/src/OrcLib/FileStream.h +++ b/src/OrcLib/FileStream.h @@ -59,13 +59,29 @@ class FileStream : public ByteStream __in DWORD dwFlagsAndAttributes, __in_opt HANDLE hTemplate); - HRESULT ReadFrom(__in PCWSTR pwzPath) + HRESULT ReadFrom(__in PCWSTR pwzPath, bool bDeleteOnClose = false) { - return OpenFile(pwzPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + return OpenFile( + pwzPath, + GENERIC_READ, + FILE_SHARE_READ | (bDeleteOnClose ? FILE_SHARE_DELETE : 0LU), + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL + | (bDeleteOnClose + ? FILE_FLAG_DELETE_ON_CLOSE : 0LU), + NULL); } - HRESULT WriteTo(__in PCWSTR pwzPath) + HRESULT WriteTo(__in PCWSTR pwzPath, bool bDeleteOnClose = false) { - return OpenFile(pwzPath, GENERIC_WRITE, 0L, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + return OpenFile( + pwzPath, + GENERIC_WRITE, + bDeleteOnClose ? FILE_SHARE_DELETE : 0LU, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL | (bDeleteOnClose ? FILE_FLAG_DELETE_ON_CLOSE : 0LU), + NULL); } HRESULT CopyHandle(HANDLE hFile); From 34257f3bba1528a7db39ff5b6e5782cd0fac0fcd Mon Sep 17 00:00:00 2001 From: Jean Gautier Date: Sun, 12 Nov 2023 16:35:25 +0100 Subject: [PATCH 15/35] OrcLib: Log: allow default construction for Logger class* --- src/OrcLib/Log/Logger.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrcLib/Log/Logger.h b/src/OrcLib/Log/Logger.h index 8ba54473..b4fc1bf4 100644 --- a/src/OrcLib/Log/Logger.h +++ b/src/OrcLib/Log/Logger.h @@ -39,7 +39,7 @@ class Logger kFacilityCount }; - Logger(std::initializer_list> loggers); + Logger(std::initializer_list> loggers = {}); uint64_t warningCount() const; uint64_t errorCount() const; From 0638897a149c2f7fd22c454880ea83bc09de1480 Mon Sep 17 00:00:00 2001 From: fabienfl Date: Thu, 16 Nov 2023 14:12:31 +0100 Subject: [PATCH 16/35] OrcLib: NtDllExtension: fix missing definition for older sdk --- src/OrcLib/NtDllExtension.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/OrcLib/NtDllExtension.h b/src/OrcLib/NtDllExtension.h index 8e5e22dc..d111c194 100644 --- a/src/OrcLib/NtDllExtension.h +++ b/src/OrcLib/NtDllExtension.h @@ -16,6 +16,27 @@ #include #include +// +// C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\winternl.h +// +#ifndef CODEINTEGRITY_OPTION_ENABLED +// bitmask values for CodeIntegrityOptions +# define CODEINTEGRITY_OPTION_ENABLED 0x01 +# define CODEINTEGRITY_OPTION_TESTSIGN 0x02 +# define CODEINTEGRITY_OPTION_UMCI_ENABLED 0x04 +# define CODEINTEGRITY_OPTION_UMCI_AUDITMODE_ENABLED 0x08 +# define CODEINTEGRITY_OPTION_UMCI_EXCLUSIONPATHS_ENABLED 0x10 +# define CODEINTEGRITY_OPTION_TEST_BUILD 0x20 +# define CODEINTEGRITY_OPTION_PREPRODUCTION_BUILD 0x40 +# define CODEINTEGRITY_OPTION_DEBUGMODE_ENABLED 0x80 +# define CODEINTEGRITY_OPTION_FLIGHT_BUILD 0x100 +# define CODEINTEGRITY_OPTION_FLIGHTING_ENABLED 0x200 +# define CODEINTEGRITY_OPTION_HVCI_KMCI_ENABLED 0x400 +# define CODEINTEGRITY_OPTION_HVCI_KMCI_AUDITMODE_ENABLED 0x800 +# define CODEINTEGRITY_OPTION_HVCI_KMCI_STRICTMODE_ENABLED 0x1000 +# define CODEINTEGRITY_OPTION_HVCI_IUM_ENABLED 0x2000 +#endif + #pragma managed(push, off) namespace Orc { From 55d3453ca4da66610fe536d1cedee0123d6a1cfe Mon Sep 17 00:00:00 2001 From: fabienfl Date: Thu, 30 Nov 2023 14:25:11 +0100 Subject: [PATCH 17/35] tools: ci: test: update to nushell 0.87.1 --- tools/ci/README.md | 2 +- tools/ci/test.psm1 | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/tools/ci/README.md b/tools/ci/README.md index a3b8e4ca..e2b75911 100644 --- a/tools/ci/README.md +++ b/tools/ci/README.md @@ -93,7 +93,7 @@ WARNING: WIN-UEP1AAROS8L: Empty file: processes2.log ### ConvertTo-OrcDiffableResults ->**Requirements:** Nushell v0.35 - https://github.com/nushell/nushell/releases/tag/0.35.0 +>**Requirements:** Nushell (tested with v0.87) - https://github.com/nushell/nushell/releases/tag/0.87.0 Convert DFIR-Orc offline results so they can be compared between multiple execution. diff --git a/tools/ci/test.psm1 b/tools/ci/test.psm1 index e8557bc0..5cbf7d4f 100644 --- a/tools/ci/test.psm1 +++ b/tools/ci/test.psm1 @@ -1695,7 +1695,7 @@ function ConvertTo-OrcDiffableResults { $NuExePath = Find-NuShell if (-not $NuExePath) { - Write-Error "'ConvertTo-OrcDiffableResults' requires nu.exe 0.35.0 to be installed, see https://github.com/nushell/nushell" + Write-Error "'ConvertTo-OrcDiffableResults' requires nu.exe >=0.87.1 to be installed, see https://github.com/nushell/nushell" return } @@ -1773,7 +1773,7 @@ function ConvertTo-OrcDiffableResults { # Retrieve all columns and remove those excluded $Columns = NuExe -c ` - "dataframe open $CSV | dataframe first 1 | dataframe show | pivot | get Column0 | to json" | ConvertFrom-Json + "open $CSV | first 1 | transpose | get Column0 | to json" | ConvertFrom-Json $Columns = $Columns | Where-Object { $_ -NotIn $ExcludedColumns } | ForEach-Object { "'$_'" } # Results output files are not described by any metadata. To be able to sort using the correct columns, schema @@ -1813,10 +1813,8 @@ function ConvertTo-OrcDiffableResults { } $Selection = $Columns | Join-String -Separator " " - Write-Verbose "Calling nu with: dataframe open $CSV | dataframe select $Selection | dataframe sort $SortSelection | dataframe to-csv $Out" - NuExe -c ` - "dataframe open $CSV | dataframe select $Selection | dataframe sort $SortSelection | dataframe to-csv $Out" - + Write-Verbose "Calling nu with: open $CSV | select $Selection | sort $SortSelection | to-csv $Out" + NuExe -c "open $CSV | select $Selection | sort-by $SortSelection | to csv | save -f $Out" Write-Output "" } From 588242e3af02f48aa689f638d4f944b66b66b652 Mon Sep 17 00:00:00 2001 From: fabienfl Date: Fri, 17 Nov 2023 11:18:27 +0100 Subject: [PATCH 18/35] cmake: add _SILENCE_ALL_MS_EXT_DEPRECATION_WARNINGS to compile definition --- cmake/Orc.cmake | 1 + tools/rcedit/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/cmake/Orc.cmake b/cmake/Orc.cmake index 23df218a..ded3fb74 100644 --- a/cmake/Orc.cmake +++ b/cmake/Orc.cmake @@ -18,6 +18,7 @@ add_compile_definitions( NOMINMAX BOOST_NO_SWPRINTF _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS + _SILENCE_ALL_MS_EXT_DEPRECATION_WARNINGS _7ZIP_ST ) diff --git a/tools/rcedit/CMakeLists.txt b/tools/rcedit/CMakeLists.txt index 296e4e7f..d6b7eb7f 100644 --- a/tools/rcedit/CMakeLists.txt +++ b/tools/rcedit/CMakeLists.txt @@ -77,6 +77,7 @@ target_compile_definitions(rcedit PRIVATE UNICODE NOMINMAX + _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING ) target_include_directories(rcedit PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) From 411ccd1103c477d8a16c34751556250da9bf1572 Mon Sep 17 00:00:00 2001 From: fabienfl Date: Wed, 6 Dec 2023 10:13:54 +0100 Subject: [PATCH 19/35] OrcLib: UncompressNTFSStream: always clear output buffer When a compressed chunk is filled with zeroes it will be ignored by the ntfs_uncompress_compunit function and the output buffer will not be touched. --- src/OrcLib/UncompressNTFSStream.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/OrcLib/UncompressNTFSStream.cpp b/src/OrcLib/UncompressNTFSStream.cpp index 037c149e..c19d7551 100644 --- a/src/OrcLib/UncompressNTFSStream.cpp +++ b/src/OrcLib/UncompressNTFSStream.cpp @@ -177,6 +177,7 @@ HRESULT UncompressNTFSStream::ReadCompressionUnit( } size_t uncomp_processed = 0; + uncompressedData.ZeroMe(); CBinaryBuffer buffer(true); for (size_t i = 0; i < dwNbCU; ++i) From 2cbb8cec103b326c9e1284e420c5ba0a57046644 Mon Sep 17 00:00:00 2001 From: fabienfl Date: Thu, 7 Dec 2023 15:44:06 +0100 Subject: [PATCH 20/35] OrcLib: EmbeddedResource: fix "unreferenced" warning with run32/run64 With the following configuration: This message would be displayed: [W] Cannot find any reference to embedded resource '7z:#Tools|foo_x64.exe' Because only run32 would be registered as a referenced resource. Only the first 'run' attribute is considered. --- src/OrcLib/EmbeddedResource_Embed.cpp | 31 +++++++++++++-------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/OrcLib/EmbeddedResource_Embed.cpp b/src/OrcLib/EmbeddedResource_Embed.cpp index 61b94779..85b866b1 100644 --- a/src/OrcLib/EmbeddedResource_Embed.cpp +++ b/src/OrcLib/EmbeddedResource_Embed.cpp @@ -261,11 +261,11 @@ class ResourceRegistry std::vector m_items; }; -// Look into the current xml element for an attribute's name which match the provided regex -Result> +// Look into the current xml element for an attributes name which match the provided regex +Result> GetXmlAttributeValueMatch(const CComPtr& reader, std::wstring_view attributeValueRegex) { - std::vector values; + std::vector values; UINT uiAttrCount = 0; HRESULT hr = reader->GetAttributeCount(&uiAttrCount); @@ -277,7 +277,7 @@ GetXmlAttributeValueMatch(const CComPtr& reader, std::wstring_view a if (uiAttrCount == 0L) { - return std::optional {}; + return std::vector(); } hr = reader->MoveToFirstAttribute(); @@ -316,30 +316,28 @@ GetXmlAttributeValueMatch(const CComPtr& reader, std::wstring_view a } std::wregex regex(attributeValueRegex.data(), std::regex_constants::icase); - if (!std::regex_search(pValue, regex)) + if (std::regex_search(pValue, regex)) { - hr = reader->MoveToNextAttribute(); + UINT lineNumber = 0; + hr = reader->GetLineNumber(&lineNumber); if (FAILED(hr)) { XmlLiteExtension::LogError(hr, reader); - return SystemError(hr); + // return; } - continue; + values.emplace_back(XmlString {{}, lineNumber, pValue}); } - UINT lineNumber = 0; - hr = reader->GetLineNumber(&lineNumber); + hr = reader->MoveToNextAttribute(); if (FAILED(hr)) { XmlLiteExtension::LogError(hr, reader); - // return; + return SystemError(hr); } - - return XmlString {{}, lineNumber, pValue}; } - return std::optional {}; + return values; } // Look into the current xml file for all attributes name which match the provided regex @@ -380,9 +378,10 @@ GetXmlAttributesValueMatch(const std::shared_ptr& xmlStream, std::ws continue; } - if ((*result).has_value()) + if (!result->empty()) { - values.emplace_back(std::move(**result)); + std::move(std::begin(*result), std::end(*result), std::back_inserter(values)); + result->clear(); } } From 3b365acfd4a32fd9005e5c0b66eb4256e76bf701 Mon Sep 17 00:00:00 2001 From: fabienfl Date: Fri, 8 Dec 2023 15:24:54 +0100 Subject: [PATCH 21/35] OrcCommand: WolfLauncher: WolfTask: lower log level "hanged for ..." --- src/OrcCommand/Command/WolfLauncher/WolfTask.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrcCommand/Command/WolfLauncher/WolfTask.cpp b/src/OrcCommand/Command/WolfLauncher/WolfTask.cpp index c97ee3bf..47a10a81 100644 --- a/src/OrcCommand/Command/WolfLauncher/WolfTask.cpp +++ b/src/OrcCommand/Command/WolfLauncher/WolfTask.cpp @@ -156,7 +156,7 @@ HRESULT WolfTask::ApplyNotification( { if (dwHangTime - m_dwLastReportedHang >= 30) { - Log::Error( + Log::Debug( L"{} (pid: {}): Hanged for {} secs", m_command, m_dwPID == 0 ? notification->GetProcessID() : m_dwPID, From efb2900bf071692ea87f26601336bd3e835c9d94 Mon Sep 17 00:00:00 2001 From: fabienfl Date: Thu, 18 Jan 2024 14:34:25 +0100 Subject: [PATCH 22/35] OrcLib: Archive: 7z: InStreamAdapter: continue archive on file read error The archive was aborted on any parsing issue. This could be an unwanted behavior specially when failing to read deleted files. --- src/OrcLib/Archive/7z/Archive7z.cpp | 2 +- src/OrcLib/Archive/7z/ArchiveUpdateCallback.cpp | 2 +- src/OrcLib/Archive/7z/InStreamAdapter.cpp | 15 ++++++++++++++- src/OrcLib/Archive/7z/InStreamAdapter.h | 4 +++- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/OrcLib/Archive/7z/Archive7z.cpp b/src/OrcLib/Archive/7z/Archive7z.cpp index 11f25426..ef4709e1 100644 --- a/src/OrcLib/Archive/7z/Archive7z.cpp +++ b/src/OrcLib/Archive/7z/Archive7z.cpp @@ -207,7 +207,7 @@ void Archive7z::Compress( } CComQIPtr archiverIn(archiver); - CComPtr inStream = new InStreamAdapter(inputArchive); + CComPtr inStream = new InStreamAdapter(inputArchive, true); CComPtr archiveOpenCallback(new ArchiveOpenCallback()); hr = archiverIn->Open(inStream, nullptr, archiveOpenCallback); if (FAILED(hr)) diff --git a/src/OrcLib/Archive/7z/ArchiveUpdateCallback.cpp b/src/OrcLib/Archive/7z/ArchiveUpdateCallback.cpp index 347a86b6..0880601f 100644 --- a/src/OrcLib/Archive/7z/ArchiveUpdateCallback.cpp +++ b/src/OrcLib/Archive/7z/ArchiveUpdateCallback.cpp @@ -227,7 +227,7 @@ STDMETHODIMP ArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream* return S_OK; } - CComQIPtr stream(new InStreamAdapter(item)); + CComQIPtr stream(new InStreamAdapter(item, true)); *pInStream = stream.Detach(); return S_OK; diff --git a/src/OrcLib/Archive/7z/InStreamAdapter.cpp b/src/OrcLib/Archive/7z/InStreamAdapter.cpp index e1b0d5fc..1148d3f4 100644 --- a/src/OrcLib/Archive/7z/InStreamAdapter.cpp +++ b/src/OrcLib/Archive/7z/InStreamAdapter.cpp @@ -30,7 +30,20 @@ STDMETHODIMP InStreamAdapter::Read(void* data, UInt32 size, UInt32* processedSiz } // Transform S_FALSE to S_OK - return SUCCEEDED(hr) ? S_OK : hr; + if (SUCCEEDED(hr)) + { + return S_OK; + } + + // Shadow copy volume Read can silently fail with some blocks and it will produce an error with ntfs compressed + // files. That error should be ignored so the archive is not aborted. + if (m_readErrorIsNotFailure) + { + Log::Error("Failed to read a stream to compress (archived item size: {}) [{}]", read, SystemError(hr)); + return S_OK; + } + + return hr; } STDMETHODIMP InStreamAdapter::Seek(Int64 offset, UInt32 seekOrigin, UInt64* newPosition) diff --git a/src/OrcLib/Archive/7z/InStreamAdapter.h b/src/OrcLib/Archive/7z/InStreamAdapter.h index e08e424d..9a9d16c7 100644 --- a/src/OrcLib/Archive/7z/InStreamAdapter.h +++ b/src/OrcLib/Archive/7z/InStreamAdapter.h @@ -25,8 +25,9 @@ class InStreamAdapter , public CMyUnknownImp { public: - InStreamAdapter(std::shared_ptr outByteStream) + InStreamAdapter(std::shared_ptr outByteStream, bool readErrorIsNotFailure) : m_stream(std::move(outByteStream)) + , m_readErrorIsNotFailure(readErrorIsNotFailure) { } @@ -43,6 +44,7 @@ class InStreamAdapter private: std::shared_ptr m_stream; + bool m_readErrorIsNotFailure; }; } // namespace Archive From c5050348a720588dd6d00f3075b565dfb4770db8 Mon Sep 17 00:00:00 2001 From: fabienfl Date: Mon, 22 Jan 2024 10:09:52 +0100 Subject: [PATCH 23/35] OrcLib: Text: StdoutContainerAdapter: fix stdout pipe break on unicode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some unicode characters truncated the stdout redirection. Ex: libssl-devamd64.txt --- src/OrcLib/Text/StdoutContainerAdapter.h | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/OrcLib/Text/StdoutContainerAdapter.h b/src/OrcLib/Text/StdoutContainerAdapter.h index 4bedefc2..3b8c6294 100644 --- a/src/OrcLib/Text/StdoutContainerAdapter.h +++ b/src/OrcLib/Text/StdoutContainerAdapter.h @@ -9,6 +9,8 @@ #include +#include "Text/Iconv.h" + namespace Orc { // Adapter for a container interface to be usable with Text::Tree and fmt. @@ -19,11 +21,21 @@ struct StdoutContainerAdapter public: using value_type = T; + StdoutContainerAdapter() + : m_hStdout(GetStdHandle(STD_OUTPUT_HANDLE)) + { + } + void flush() { - Traits::get_std_out() << m_buffer; - m_buffer.clear(); - Traits::get_std_out().flush(); + if (m_buffer.size()) + { + DWORD written = 0; + auto buffer = ToUtf8(m_buffer); + WriteFile(m_hStdout, (void*)buffer.data(), buffer.size(), &written, NULL); + } + + FlushFileBuffers(m_hStdout); } void push_back(T c) @@ -33,7 +45,10 @@ struct StdoutContainerAdapter Log::Info(Log::Facility::kLogFile, m_buffer); m_buffer.push_back(c); - Traits::get_std_out() << m_buffer; + + DWORD written = 0; + auto buffer = ToUtf8(m_buffer); + WriteFile(m_hStdout, (void*)buffer.data(), buffer.size(), &written, NULL); m_buffer.clear(); } else if (c) @@ -43,6 +58,7 @@ struct StdoutContainerAdapter } private: + HANDLE m_hStdout; std::basic_string m_buffer; }; From 577f0198c1627cb2d085d28ae2d4d38cb3f452e2 Mon Sep 17 00:00:00 2001 From: fabienfl Date: Tue, 30 Jan 2024 17:53:53 +0100 Subject: [PATCH 24/35] vcpkg: yara: replace wincrypt with LibreSSL --- cmake/FindYara.cmake | 3 +++ external/vcpkg | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/cmake/FindYara.cmake b/cmake/FindYara.cmake index d4a2be9f..b0f7f3e9 100644 --- a/cmake/FindYara.cmake +++ b/cmake/FindYara.cmake @@ -32,8 +32,11 @@ find_library(YARA_LIB_RELEASE add_library(yara::yara INTERFACE IMPORTED) +find_package(OpenSSL REQUIRED) + # Add 'OpenSSL::Crypto' if yara is built with openssl or libressl target_link_libraries(yara::yara INTERFACE debug ${YARA_LIB_DEBUG} optimized ${YARA_LIB_RELEASE} + OpenSSL::Crypto ) diff --git a/external/vcpkg b/external/vcpkg index a4a0659e..24bc1d29 160000 --- a/external/vcpkg +++ b/external/vcpkg @@ -1 +1 @@ -Subproject commit a4a0659ed84fa94c214edb735436a7e95032b37e +Subproject commit 24bc1d29e3856834fbfa27fbd4dc2130ac0f0884 From 2ff3b3f5056d56466f7f054ef4344033b33f470d Mon Sep 17 00:00:00 2001 From: fabienfl Date: Mon, 5 Feb 2024 14:33:40 +0100 Subject: [PATCH 25/35] vcpkg: yara: update to Yara 4.4.0 --- external/vcpkg | 2 +- src/OrcLib/YaraScanner.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/external/vcpkg b/external/vcpkg index 24bc1d29..c3759e40 160000 --- a/external/vcpkg +++ b/external/vcpkg @@ -1 +1 @@ -Subproject commit 24bc1d29e3856834fbfa27fbd4dc2130ac0f0884 +Subproject commit c3759e4082f213e4d21f2d041826121cc9203285 diff --git a/src/OrcLib/YaraScanner.cpp b/src/OrcLib/YaraScanner.cpp index 8f4e0e5c..069ef096 100644 --- a/src/OrcLib/YaraScanner.cpp +++ b/src/OrcLib/YaraScanner.cpp @@ -849,7 +849,8 @@ HRESULT Orc::YaraScanner::PrintConfiguration() YR_RULE* yr_rule = nullptr; yr_rules_foreach(yr_rules, yr_rule) { - Log::Info("Rule: {} ({})", yr_rule->identifier, RULE_IS_DISABLED(yr_rule) ? "disabled" : "enabled"); + const auto rule = RULE_IS_DISABLED(yr_rule) ? "disabled" : "enabled"; + Log::Info("Rule: {} ({})", yr_rule->identifier, rule); } return S_OK; } From 692c968c02b6afe55b4cdd37d99c8612ba896ee1 Mon Sep 17 00:00:00 2001 From: fabienfl Date: Thu, 1 Feb 2024 18:12:40 +0100 Subject: [PATCH 26/35] OrcLib: YaraScanner: add workaround on Yara limitation for block api Unfortunately the block API does not seem to work at least for some modules like 'pe'. It silently fails to parse security directory and rule does not match. The yara.exe binary does map the file completely aswell. https://github.com/VirusTotal/yara/issues/1994 --- src/OrcLib/YaraScanner.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/OrcLib/YaraScanner.cpp b/src/OrcLib/YaraScanner.cpp index 069ef096..5b5568d7 100644 --- a/src/OrcLib/YaraScanner.cpp +++ b/src/OrcLib/YaraScanner.cpp @@ -542,10 +542,18 @@ HRESULT YaraScanner::ScanBlocks(const std::shared_ptr& stream, Match return nullptr; } + // + // COMMENT: Unfortunately the block API does not seem to work at least for some modules like 'pe'. It silently + // fails to parse security directory and rule does not match. The yara.exe binary does map the file completely + // aswell. + // // On first fetch only read 1MB as it will be often enough for header matching - context->block.size = std::min( - static_cast(context->buffer.size()), - std::min(static_cast(1048576), context->streamSize)); + // context->block.size = std::min( + // static_cast(context->buffer.size()), + // std::min(static_cast(1048576), context->streamSize)); + context->buffer.resize(context->streamSize); + context->block.size = context->buffer.size(); + context->block.base = 0; return &context->block; }; From 2b4c12e103f9d900544fc7111e683037d2c0c558 Mon Sep 17 00:00:00 2001 From: fabienfl Date: Fri, 2 Feb 2024 14:55:17 +0100 Subject: [PATCH 27/35] OrcLib: Utils: Guard: add RegistryHandle --- src/OrcLib/Utils/Guard.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/OrcLib/Utils/Guard.h b/src/OrcLib/Utils/Guard.h index 338a218f..b325f2e2 100644 --- a/src/OrcLib/Utils/Guard.h +++ b/src/OrcLib/Utils/Guard.h @@ -266,6 +266,33 @@ class Handle final : public DescriptorGuard } }; +class RegistryHandle final : public DescriptorGuard +{ +public: + RegistryHandle(HKEY handle = static_cast(INVALID_HANDLE_VALUE)) + : DescriptorGuard(handle, static_cast(INVALID_HANDLE_VALUE)) + { + } + + RegistryHandle(RegistryHandle&& handle) noexcept = default; + RegistryHandle& operator=(RegistryHandle&& o) = default; + + ~RegistryHandle() + { + if (m_data == m_invalidValue) + { + return; + } + + LSTATUS status = RegCloseKey(m_data); + if (status != ERROR_SUCCESS) + { + Log::Debug("Failed RegCloseKey [{}]", Win32Error(status)); + return; + } + } +}; + class Module final : public DescriptorGuard { public: From 2221e548949909e3b239855567b59a93a4a1c7af Mon Sep 17 00:00:00 2001 From: fabienfl Date: Fri, 2 Feb 2024 14:56:49 +0100 Subject: [PATCH 28/35] OrcLib: SystemDetails: add GetShutdownTimeFromRegistry --- src/OrcLib/SystemDetails.cpp | 29 +++++++++++++++++++++++++++++ src/OrcLib/SystemDetails.h | 1 + 2 files changed, 30 insertions(+) diff --git a/src/OrcLib/SystemDetails.cpp b/src/OrcLib/SystemDetails.cpp index e0bc4eaa..0663c482 100644 --- a/src/OrcLib/SystemDetails.cpp +++ b/src/OrcLib/SystemDetails.cpp @@ -26,6 +26,7 @@ #include "BinaryBuffer.h" #include "Utils/Time.h" #include "Utils/TypeTraits.h" +#include "Utils/Guard.h" namespace fs = std::filesystem; using namespace std::string_view_literals; @@ -1007,6 +1008,34 @@ HRESULT Orc::SystemDetails::GetUserLanguage(std::wstring& strLanguage) return S_OK; } +Result Orc::SystemDetails::GetShutdownTimeFromRegistry() +{ + const wchar_t key[] = L"SYSTEM\\CurrentControlSet\\Control\\Windows"; + + Guard::RegistryHandle hKey; + auto status = RegOpenKeyW(HKEY_LOCAL_MACHINE, key, &hKey.value()); + if (status != ERROR_SUCCESS) + { + auto ec = Win32Error(status); + Log::Debug(L"Failed RegOpenKeyW (key: {}) [{}]", key, ec); + return ec; + } + + FILETIME shutdownTime; + const wchar_t value[] = L"ShutdownTime"; + DWORD valueType = 0L; + DWORD cbData = sizeof(shutdownTime); + status = RegQueryValueExW(hKey.value(), value, NULL, &valueType, (LPBYTE)&shutdownTime, &cbData); + if (status != ERROR_SUCCESS) + { + auto ec = Win32Error(status); + Log::Debug(L"Failed RegQueryValueExW (key: {}, value: {}) [{}]", key, value, ec); + return ec; + } + + return FromFileTime(shutdownTime); +} + SystemDetails::DriveType SystemDetails::GetPathLocation(const std::wstring& strAnyPath) { WCHAR szVolume[ORC_MAX_PATH]; diff --git a/src/OrcLib/SystemDetails.h b/src/OrcLib/SystemDetails.h index e2b039f8..1f3e7fc4 100644 --- a/src/OrcLib/SystemDetails.h +++ b/src/OrcLib/SystemDetails.h @@ -114,6 +114,7 @@ class SystemDetails static HRESULT GetSystemLanguage(std::wstring& strLocale); static HRESULT GetUserLanguage(std::wstring& strLocale); + static Result GetShutdownTimeFromRegistry(); static HRESULT GetCurrentWorkingDirectory(std::filesystem::path& cwd); static HRESULT GetProcessBinary(std::wstring& strFullPath); From 329743d81a616dd4d5589c13cf6ec7c561e83230 Mon Sep 17 00:00:00 2001 From: fabienfl Date: Fri, 2 Feb 2024 14:57:33 +0100 Subject: [PATCH 29/35] OrcLib: SystemDetails: add GetInstallTimeFromRegistry --- src/OrcLib/SystemDetails.cpp | 28 ++++++++++++++++++++++++++++ src/OrcLib/SystemDetails.h | 1 + 2 files changed, 29 insertions(+) diff --git a/src/OrcLib/SystemDetails.cpp b/src/OrcLib/SystemDetails.cpp index 0663c482..12d34515 100644 --- a/src/OrcLib/SystemDetails.cpp +++ b/src/OrcLib/SystemDetails.cpp @@ -1036,6 +1036,34 @@ Result Orc::SystemDetails::GetShutdownTim return FromFileTime(shutdownTime); } +Result Orc::SystemDetails::GetInstallTimeFromRegistry() +{ + const wchar_t key[] = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"; + + Guard::RegistryHandle hKey; + auto status = RegOpenKeyW(HKEY_LOCAL_MACHINE, key, &hKey.value()); + if (status != ERROR_SUCCESS) + { + auto ec = Win32Error(status); + Log::Debug(L"Failed RegOpenKeyW (key: {}) [{}]", key, ec); + return ec; + } + + FILETIME installTime; + const wchar_t value[] = L"InstallTime"; + DWORD valueType = 0L; + DWORD cbData = sizeof(installTime); + status = RegQueryValueExW(hKey.value(), value, NULL, &valueType, (LPBYTE)&installTime, &cbData); + if (status != ERROR_SUCCESS) + { + auto ec = Win32Error(status); + Log::Debug(L"Failed RegQueryValueExW (key: {}, value: {}) [{}]", key, value, ec); + return ec; + } + + return FromFileTime(installTime); +} + SystemDetails::DriveType SystemDetails::GetPathLocation(const std::wstring& strAnyPath) { WCHAR szVolume[ORC_MAX_PATH]; diff --git a/src/OrcLib/SystemDetails.h b/src/OrcLib/SystemDetails.h index 1f3e7fc4..5b2e291c 100644 --- a/src/OrcLib/SystemDetails.h +++ b/src/OrcLib/SystemDetails.h @@ -115,6 +115,7 @@ class SystemDetails static HRESULT GetUserLanguage(std::wstring& strLocale); static Result GetShutdownTimeFromRegistry(); + static Result GetInstallTimeFromRegistry(); static HRESULT GetCurrentWorkingDirectory(std::filesystem::path& cwd); static HRESULT GetProcessBinary(std::wstring& strFullPath); From 0f0c225897eb409b689b3aa27b157e2b3ab72b57 Mon Sep 17 00:00:00 2001 From: fabienfl Date: Fri, 2 Feb 2024 14:57:59 +0100 Subject: [PATCH 30/35] OrcLib: SystemDetails: add GetInstallDateFromRegistry --- src/OrcLib/SystemDetails.cpp | 28 ++++++++++++++++++++++++++++ src/OrcLib/SystemDetails.h | 2 ++ 2 files changed, 30 insertions(+) diff --git a/src/OrcLib/SystemDetails.cpp b/src/OrcLib/SystemDetails.cpp index 12d34515..57b755ff 100644 --- a/src/OrcLib/SystemDetails.cpp +++ b/src/OrcLib/SystemDetails.cpp @@ -1064,6 +1064,34 @@ Result Orc::SystemDetails::GetInstallTime return FromFileTime(installTime); } +Result Orc::SystemDetails::GetInstallDateFromRegistry() +{ + const wchar_t key[] = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"; + + Guard::RegistryHandle hKey; + auto status = RegOpenKeyW(HKEY_LOCAL_MACHINE, key, &hKey.value()); + if (status != ERROR_SUCCESS) + { + auto ec = Win32Error(status); + Log::Debug(L"Failed RegOpenKeyW (key: {}) [{}]", key, ec); + return ec; + } + + __time32_t installDate; + const wchar_t value[] = L"InstallDate"; + DWORD valueType = 0L; + DWORD cbData = sizeof(installDate); + status = RegQueryValueExW(hKey.value(), value, NULL, &valueType, (LPBYTE)&installDate, &cbData); + if (status != ERROR_SUCCESS) + { + auto ec = Win32Error(status); + Log::Debug(L"Failed RegQueryValueExW (key: {}, value: {}) [{}]", key, value, ec); + return ec; + } + + return std::chrono::system_clock::from_time_t(installDate); +} + SystemDetails::DriveType SystemDetails::GetPathLocation(const std::wstring& strAnyPath) { WCHAR szVolume[ORC_MAX_PATH]; diff --git a/src/OrcLib/SystemDetails.h b/src/OrcLib/SystemDetails.h index 5b2e291c..16f56500 100644 --- a/src/OrcLib/SystemDetails.h +++ b/src/OrcLib/SystemDetails.h @@ -116,6 +116,8 @@ class SystemDetails static Result GetShutdownTimeFromRegistry(); static Result GetInstallTimeFromRegistry(); + static Result GetInstallDateFromRegistry(); + static HRESULT GetCurrentWorkingDirectory(std::filesystem::path& cwd); static HRESULT GetProcessBinary(std::wstring& strFullPath); From 8ee768d1f49e5b37801f1618e920c27316156ac3 Mon Sep 17 00:00:00 2001 From: fabienfl Date: Fri, 2 Feb 2024 14:58:46 +0100 Subject: [PATCH 31/35] OrcLib: SystemIdentity: add install_date, install_time, shutdown_time This will add those to Outline. --- src/OrcLib/SystemIdentity.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/OrcLib/SystemIdentity.cpp b/src/OrcLib/SystemIdentity.cpp index a11c6154..be31a427 100644 --- a/src/OrcLib/SystemIdentity.cpp +++ b/src/OrcLib/SystemIdentity.cpp @@ -16,6 +16,7 @@ #include "SystemDetails.h" #include "CpuInfo.h" +#include "Utils/Time.h" HRESULT Orc::SystemIdentity::Write(const std::shared_ptr& writer, IdentityArea areas) { @@ -236,6 +237,28 @@ HRESULT Orc::SystemIdentity::OperatingSystem(const std::shared_ptrWriteNamed(L"language", language.c_str()); } + { + auto installDate = SystemDetails::GetInstallDateFromRegistry(); + if (installDate) + { + writer->WriteNamed(L"install_date", ToStringIso8601(*installDate)); + } + } + { + auto installTime = SystemDetails::GetInstallTimeFromRegistry(); + if (installTime) + { + writer->WriteNamed(L"install_time", ToStringIso8601(*installTime)); + } + } + { + auto shutdownTime = SystemDetails::GetShutdownTimeFromRegistry(); + if (shutdownTime) + { + ToStringIso8601(*shutdownTime); + writer->WriteNamed(L"shutdown_time", ToStringIso8601(*shutdownTime)); + } + } { auto tags = SystemDetails::GetSystemTags(); writer->BeginCollection(L"tag"); From 29bd66da787f5e3eec2993980cb45ee515af503d Mon Sep 17 00:00:00 2001 From: fabienfl Date: Tue, 6 Feb 2024 16:05:05 +0100 Subject: [PATCH 32/35] OrcLib: Text: Fmt: Result: forward to underlying type formatter Add also 'void' specialization --- src/OrcLib/Text/Fmt/Result.h | 38 ++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/OrcLib/Text/Fmt/Result.h b/src/OrcLib/Text/Fmt/Result.h index ef6fa098..f713301b 100644 --- a/src/OrcLib/Text/Fmt/Result.h +++ b/src/OrcLib/Text/Fmt/Result.h @@ -20,13 +20,30 @@ struct fmt::formatter> : public fmt::formatter { if (result.has_error()) { - fmt::format_to(ctx.out(), "{}", result.error()); - return ctx.out(); + formatter error; + return error.format(result.error(), ctx); } + return formatter::format(result.value(), ctx); } }; +template <> +struct fmt::formatter> : public fmt::formatter +{ + template + auto format(const Orc::Result& result, FormatContext& ctx) -> decltype(ctx.out()) + { + if (result.has_error()) + { + formatter error; + return error.format(result.error(), ctx); + } + + return formatter::format("Success", ctx); + } +}; + template struct fmt::formatter, wchar_t> : public fmt::formatter { @@ -38,6 +55,23 @@ struct fmt::formatter, wchar_t> : public fmt::formatter::format(result.value(), ctx); } }; + +template <> +struct fmt::formatter, wchar_t> : public fmt::formatter +{ + template + auto format(const Orc::Result& result, FormatContext& ctx) -> decltype(ctx.out()) + { + if (result.has_error()) + { + formatter error; + return error.format(result.error(), ctx); + } + + return formatter::format(L"Success", ctx); + } +}; From e694f25853a1eed22a17d19679d15d4fa30951e7 Mon Sep 17 00:00:00 2001 From: fabienfl Date: Tue, 6 Feb 2024 16:58:07 +0100 Subject: [PATCH 33/35] OrcLib: Text: Fmt: std_optional: forward to underlying type formatter Add compatibility with format string syntax. --- .../Command/GetThis/GetThis_Output.cpp | 2 ++ src/OrcCommand/Command/GetThis/GetThis_Run.cpp | 1 + src/OrcLib/Text/Fmt/std_optional.h | 18 ++++++++++-------- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/OrcCommand/Command/GetThis/GetThis_Output.cpp b/src/OrcCommand/Command/GetThis/GetThis_Output.cpp index 919852d5..2f8adfe3 100644 --- a/src/OrcCommand/Command/GetThis/GetThis_Output.cpp +++ b/src/OrcCommand/Command/GetThis/GetThis_Output.cpp @@ -17,6 +17,8 @@ #include "ToolVersion.h" #include "Text/Fmt/Boolean.h" +#include "Text/Fmt/ByteQuantity.h" +#include "Text/Fmt/Limit.h" #include "Text/Print.h" #include "Text/Print/LocationSet.h" #include "Text/Print/OutputSpec.h" diff --git a/src/OrcCommand/Command/GetThis/GetThis_Run.cpp b/src/OrcCommand/Command/GetThis/GetThis_Run.cpp index aa452dc4..c58bdf34 100644 --- a/src/OrcCommand/Command/GetThis/GetThis_Run.cpp +++ b/src/OrcCommand/Command/GetThis/GetThis_Run.cpp @@ -44,6 +44,7 @@ #include "Archive/Appender.h" #include "Archive/7z/Archive7z.h" #include "Text/Fmt/Result.h" +#include "Text/Fmt/Limit.h" namespace fs = std::filesystem; diff --git a/src/OrcLib/Text/Fmt/std_optional.h b/src/OrcLib/Text/Fmt/std_optional.h index 28d6eee8..15b73f7a 100644 --- a/src/OrcLib/Text/Fmt/std_optional.h +++ b/src/OrcLib/Text/Fmt/std_optional.h @@ -13,31 +13,33 @@ #include template -struct fmt::formatter> : public fmt::formatter +struct fmt::formatter> : public fmt::formatter { template - auto format(const std::optional& optional, FormatContext& ctx) + auto format(const std::optional& optional, FormatContext& ctx) -> decltype(ctx.out()) { if (!optional.has_value()) { - return fmt::formatter::format("N/A", ctx); + formatter na; + return na.format("N/A", ctx); } - return fmt::format_to(ctx.out(), "{}", *optional); + return formatter::format(optional.value(), ctx); } }; template -struct fmt::formatter, wchar_t> : public fmt::formatter +struct fmt::formatter, wchar_t> : public fmt::formatter { template - auto format(const std::optional& optional, FormatContext& ctx) + auto format(const std::optional& optional, FormatContext& ctx) -> decltype(ctx.out()) { if (!optional.has_value()) { - return fmt::formatter::format(L"N/A", ctx); + formatter na; + return na.format(L"N/A", ctx); } - return fmt::format_to(ctx.out(), L"{}", *optional); + return formatter::format(optional.value(), ctx); } }; From 211cd5c846afcc23e0b3732be8fc340fcc944608 Mon Sep 17 00:00:00 2001 From: fabienfl Date: Wed, 7 Feb 2024 15:04:45 +0100 Subject: [PATCH 34/35] OrcCommand: WolfLauncher: Outline: add 'computer_name' Match Outcome's computer_name --- src/OrcCommand/Command/WolfLauncher/WolfLauncher_Run.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/OrcCommand/Command/WolfLauncher/WolfLauncher_Run.cpp b/src/OrcCommand/Command/WolfLauncher/WolfLauncher_Run.cpp index d85022d5..33429ffa 100644 --- a/src/OrcCommand/Command/WolfLauncher/WolfLauncher_Run.cpp +++ b/src/OrcCommand/Command/WolfLauncher/WolfLauncher_Run.cpp @@ -593,6 +593,12 @@ HRESULT Orc::Command::Wolf::Main::CreateAndUploadOutline() SystemDetails::GetTimeStamp(strTimeStamp); writer->WriteNamed(L"timestamp", strTimeStamp); + { + std::wstring computerName; + SystemDetails::GetFullComputerName(computerName); + writer->WriteNamed(L"computer_name", computerName); + } + auto mothership_id = SystemDetails::GetParentProcessId(); if (mothership_id) { From 6869b5f251faa93ae18da5c2883e02b86d980590 Mon Sep 17 00:00:00 2001 From: fabienfl Date: Fri, 2 Feb 2024 15:19:49 +0100 Subject: [PATCH 35/35] changelog: update to 10.2.4 --- CHANGELOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6379ad91..5846e963 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # ChangeLog +## [10.2.4] - 2024-02-02 +### Added +- Outline: add install_date, install_time and shutdown_time filled from registry +- Outline: add computer_name to match outcome's + +### Changed +- Ntfs: improve behavior for compressed buffers when shadow copy block is lost +- GetThis: go to next file in case of errors like unrecoverable deleted file +- Yara: update to v4.4.0 +- Yara: replace Windows library with LibreSSL to benefit some features + +### Fixed +- ToolEmbed: remove unwanted warning message for run32 and run64 attributes +- Fix breaking stdout redirection on unicode character +- Yara: use yara.exe's workaround for block api (files are now entirely mapped) + + ## [10.2.3] - 2023-11-15 ### Added - Ntfs: Windows overlay file compression support with resident files