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 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/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/external/vcpkg b/external/vcpkg index a4a0659e..c3759e40 160000 --- a/external/vcpkg +++ b/external/vcpkg @@ -1 +1 @@ -Subproject commit a4a0659ed84fa94c214edb735436a7e95032b37e +Subproject commit c3759e4082f213e4d21f2d041826121cc9203285 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/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) { 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, 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/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 { 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 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(); 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/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(); } } 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> { 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/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); 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. 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) { 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; diff --git a/src/OrcLib/NtDllExtension.h b/src/OrcLib/NtDllExtension.h index 193bff29..d111c194 100644 --- a/src/OrcLib/NtDllExtension.h +++ b/src/OrcLib/NtDllExtension.h @@ -10,11 +10,33 @@ #include "OrcLib.h" #include "ExtensionLibrary.h" +#include "Flags.h" #include #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 { @@ -167,6 +189,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) 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/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; } diff --git a/src/OrcLib/SystemDetails.cpp b/src/OrcLib/SystemDetails.cpp index 3408684d..57b755ff 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; @@ -104,6 +105,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 +408,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 +427,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) @@ -840,6 +1008,90 @@ 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); +} + +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); +} + +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 baebd7bd..16f56500 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); @@ -111,6 +114,10 @@ class SystemDetails static HRESULT GetSystemLanguage(std::wstring& strLocale); static HRESULT GetUserLanguage(std::wstring& strLocale); + static Result GetShutdownTimeFromRegistry(); + static Result GetInstallTimeFromRegistry(); + static Result GetInstallDateFromRegistry(); + static HRESULT GetCurrentWorkingDirectory(std::filesystem::path& cwd); static HRESULT GetProcessBinary(std::wstring& strFullPath); 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"); 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) { diff --git a/src/OrcLib/Text/Fmt/Result.h b/src/OrcLib/Text/Fmt/Result.h index 8ae0e682..f713301b 100644 --- a/src/OrcLib/Text/Fmt/Result.h +++ b/src/OrcLib/Text/Fmt/Result.h @@ -13,16 +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); + 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); @@ -30,16 +45,31 @@ struct fmt::formatter> : public fmt::formatter }; 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(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); 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); } }; 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++ = '}'; 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]; 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; }; 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) 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: 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; diff --git a/src/OrcLib/YaraScanner.cpp b/src/OrcLib/YaraScanner.cpp index 8f4e0e5c..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; }; @@ -849,7 +857,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; } 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 "" } 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)