Narrow desired rights when loading hive

Fixes #3
This commit is contained in:
bmortgat
2023-06-15 14:59:56 +02:00
parent 20c981eb84
commit 50e1e747c3
14 changed files with 1781 additions and 1776 deletions
+2
View File
@@ -1,3 +1,5 @@
src/.vs
src/*.vcxproj.user
src/*.aps
src/intermediate
src/output
+16 -13
View File
@@ -1,13 +1,16 @@
Version 1.0 - 2020-02-10
* Initial release
Version 1.1 - 2020-02-11
* Support newline (\n) characters in key names
* Support newline (\n) characters in value names
* Support newline (\n) characters in string value contents
Version 1.2 - 2022-02-28
* Support registry symbolic links
* Accept continuation lines with any amount of leading spaces
for values stored as hexadecimal
* Accept multiple newlines after preamble
Version 1.3 - 2023-06-15
* Narrow desired rights when loading hive
Version 1.2 - 2022-02-28
* Support registry symbolic links
* Accept continuation lines with any amount of leading spaces
for values stored as hexadecimal
* Accept multiple newlines after preamble
Version 1.1 - 2020-02-11
* Support newline (\n) characters in key names
* Support newline (\n) characters in value names
* Support newline (\n) characters in string value contents
Version 1.0 - 2020-02-10
* Initial release
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright 2022 Stormshield
Copyright 2023 Stormshield
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
+1 -1
View File
@@ -1,4 +1,4 @@
(C) 2022 Stormshield
(C) 2023 Stormshield
HiveSwarming - Conversions between registry hive and registry export formats
without a need for special privileges.
+74 -74
View File
@@ -1,74 +1,74 @@
// (C) Stormshield 2022
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details
#include <windows.h>
#include "Constants.h"
#include "CommonFunctions.h"
#include <vector>
#include <iostream>
#include <iomanip>
void DeleteHiveLogFiles
(
_In_ const std::wstring &HiveFilePath
)
{
for (auto& Ext : Constants::Hives::LogFileExtensions)
{
std::wstring LogFilePath = HiveFilePath + Ext;
DWORD Attributes = GetFileAttributesW(LogFilePath.c_str());
if (Attributes != INVALID_FILE_ATTRIBUTES)
{
Attributes &= ~FILE_ATTRIBUTE_HIDDEN;
Attributes &= ~FILE_ATTRIBUTE_SYSTEM;
SetFileAttributesW(LogFilePath.c_str(), Attributes);
DeleteFileW(LogFilePath.c_str());
}
}
}
void ReportError
(
_In_ const HRESULT ErrorCode,
_In_ const std::wstring& Context
)
{
LPWSTR MessageBuffer = NULL;
DWORD FmtResult = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&MessageBuffer, 0, NULL);
if (!Context.empty())
{
std::wcerr << Context << L":" << std::endl;
}
if (FmtResult == 0)
{
std::wcerr << L"ERROR " << std::hex << std::setw(8) << ErrorCode << L" (could not format message)";
}
else
{
std::wcerr << L"ERROR " << std::hex << std::setw(8) << ErrorCode << L" (" << MessageBuffer << L")";
LocalFree((PVOID)MessageBuffer);
MessageBuffer = NULL;
}
std::wcerr << std::endl << std::endl;
}
VOID GlobalStringSubstitute(
_Inout_ std::wstring& String,
_In_ const std::wstring& Pattern,
_In_ const std::wstring& Replacement
)
{
size_t Position = String.find(Pattern);
while (Position != String.npos)
{
String.replace(Position, Pattern.length(), Replacement);
Position = String.find(Pattern, Position + Replacement.length());
}
}
// (C) Stormshield 2023
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details
#include <windows.h>
#include "Constants.h"
#include "CommonFunctions.h"
#include <vector>
#include <iostream>
#include <iomanip>
void DeleteHiveLogFiles
(
_In_ const std::wstring &HiveFilePath
)
{
for (auto& Ext : Constants::Hives::LogFileExtensions)
{
std::wstring LogFilePath = HiveFilePath + Ext;
DWORD Attributes = GetFileAttributesW(LogFilePath.c_str());
if (Attributes != INVALID_FILE_ATTRIBUTES)
{
Attributes &= ~FILE_ATTRIBUTE_HIDDEN;
Attributes &= ~FILE_ATTRIBUTE_SYSTEM;
SetFileAttributesW(LogFilePath.c_str(), Attributes);
DeleteFileW(LogFilePath.c_str());
}
}
}
void ReportError
(
_In_ const HRESULT ErrorCode,
_In_ const std::wstring& Context
)
{
LPWSTR MessageBuffer = NULL;
DWORD FmtResult = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&MessageBuffer, 0, NULL);
if (!Context.empty())
{
std::wcerr << Context << L":" << std::endl;
}
if (FmtResult == 0)
{
std::wcerr << L"ERROR " << std::hex << std::setw(8) << ErrorCode << L" (could not format message)";
}
else
{
std::wcerr << L"ERROR " << std::hex << std::setw(8) << ErrorCode << L" (" << MessageBuffer << L")";
LocalFree((PVOID)MessageBuffer);
MessageBuffer = NULL;
}
std::wcerr << std::endl << std::endl;
}
VOID GlobalStringSubstitute(
_Inout_ std::wstring& String,
_In_ const std::wstring& Pattern,
_In_ const std::wstring& Replacement
)
{
size_t Position = String.find(Pattern);
while (Position != String.npos)
{
String.replace(Position, Pattern.length(), Replacement);
Position = String.find(Pattern, Position + Replacement.length());
}
}
+32 -32
View File
@@ -1,32 +1,32 @@
// (C) Stormshield 2022
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details
#pragma once
#include <string>
/// @brief Delete .LOG1 and .LOG2 system files that were created when loading an application hive
/// @param[in] HiveFilePath Path to the hive file
void DeleteHiveLogFiles
(
_In_ const std::wstring &HiveFilePath
);
/// @brief Report an error
/// @param[in] ErrorCode HRESULT value
/// @param[in] Context Optional context
void ReportError
(
_In_ const HRESULT ErrorCode,
_In_ const std::wstring& Context = std::wstring{}
);
/// @brief Perform global replacement of substring in a std::wstring
/// @param[in,out] String String on which to perform substitutions
/// @param[in] Pattern Substring that will be replaced by #Replacement in #String
/// @param[in] Replacement What is inserted in place of #Substring in #String
VOID GlobalStringSubstitute(
_Inout_ std::wstring& String,
_In_ const std::wstring& Pattern,
_In_ const std::wstring& Replacement
);
// (C) Stormshield 2023
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details
#pragma once
#include <string>
/// @brief Delete .LOG1 and .LOG2 system files that were created when loading an application hive
/// @param[in] HiveFilePath Path to the hive file
void DeleteHiveLogFiles
(
_In_ const std::wstring &HiveFilePath
);
/// @brief Report an error
/// @param[in] ErrorCode HRESULT value
/// @param[in] Context Optional context
void ReportError
(
_In_ const HRESULT ErrorCode,
_In_ const std::wstring& Context = std::wstring{}
);
/// @brief Perform global replacement of substring in a std::wstring
/// @param[in,out] String String on which to perform substitutions
/// @param[in] Pattern Substring that will be replaced by #Replacement in #String
/// @param[in] Replacement What is inserted in place of #Substring in #String
VOID GlobalStringSubstitute(
_Inout_ std::wstring& String,
_In_ const std::wstring& Pattern,
_In_ const std::wstring& Replacement
);
+93 -93
View File
@@ -1,93 +1,93 @@
// (C) Stormshield 2022
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details
#pragma once
#include <windows.h>
#include <vector>
#include <string>
/// Program constants
namespace Constants {
/// Command-line constants
namespace Program {
/// Switch for converting a hive to a .reg file
static const std::wstring HiveToRegFileSwitch { L"--hive-to-reg-file" };
/// Switch for converting a .reg file to a hive
static const std::wstring RegFileToHiveSwitch { L"--reg-file-to-hive" };
};
/// Program defaults
namespace Defaults {
/// Default Root registry path in generated .reg files
static const std::wstring ExportKeyPath { L"(HiveRoot)" };
};
/// Hive-specific constants
namespace Hives {
/// Extensions of extra files that are generated when manipulating registry hives
static const std::vector<std::wstring> LogFileExtensions{ L".LOG1", L".LOG2" };
/// Special value storing the destination of a symbolic link
static const std::wstring SymbolicLinkValue { L"SymbolicLinkValue" };
};
/// .reg file-specific constants
namespace RegFiles {
/// New lines used in .reg files
static const std::wstring NewLines { L"\r\n" };
/// Preamble found in .reg files
static const std::wstring Preamble { L"\ufeff" // Byte Order Mark
L"Windows Registry Editor Version 5.00\r\n"
L"\r\n" };
/// Character used at start of line beginning a registry key path
static const WCHAR KeyOpening { L'[' };
/// Character delimiting parent key from its child in a registry path
static const WCHAR PathSeparator { L'\\' };
/// Character used at end of line closing a registry key path
static const WCHAR KeyClosing { L']' };
/// Character used for default registry values
static const WCHAR DefaultValue { L'@' };
/// Character used for separating value declaration from its content
static const WCHAR ValueNameSeparator { L'=' };
/// Sequence used for describing a DWORD rendition
static const std::wstring DwordPrefix { L"dword:" };
/// Sequence used for describing a hexadecimal rendition
static const std::wstring HexPrefix { L"hex" };
/// Character used when beginning the value type for a hexadecimal rendition
static const WCHAR HexTypeSpecOpening { L'(' };
/// Character used when ending the value type for a hexadecimal rendition
static const WCHAR HexTypeSpecClosing { L')' };
/// Character at the beginning of the hexadecimal rendition
static const WCHAR HexSuffix { L':' };
/// Byte separator in hexadecimal renditions
static const WCHAR HexByteSeparator { L',' };
/// Desired maximal line length when dumping hexadecimal rendition of registry values
static const SIZE_T HexWrappingLimit = 80u;
/// Count of leading spaces when wrapping a hexadecimal rendition
static const SIZE_T HexNewLineLeadingSpaces = 2u;
/// Space character at the beginning of a continuation line when wrapping hex values
static const WCHAR LeadingSpace { L' '};
/// Sequence used when continuing a hexadecimal rendition on a new line
static const std::wstring HexByteNewLine { L"\\\r\n" };
};
};
// (C) Stormshield 2023
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details
#pragma once
#include <windows.h>
#include <vector>
#include <string>
/// Program constants
namespace Constants {
/// Command-line constants
namespace Program {
/// Switch for converting a hive to a .reg file
static const std::wstring HiveToRegFileSwitch { L"--hive-to-reg-file" };
/// Switch for converting a .reg file to a hive
static const std::wstring RegFileToHiveSwitch { L"--reg-file-to-hive" };
};
/// Program defaults
namespace Defaults {
/// Default Root registry path in generated .reg files
static const std::wstring ExportKeyPath { L"(HiveRoot)" };
};
/// Hive-specific constants
namespace Hives {
/// Extensions of extra files that are generated when manipulating registry hives
static const std::vector<std::wstring> LogFileExtensions{ L".LOG1", L".LOG2" };
/// Special value storing the destination of a symbolic link
static const std::wstring SymbolicLinkValue { L"SymbolicLinkValue" };
};
/// .reg file-specific constants
namespace RegFiles {
/// New lines used in .reg files
static const std::wstring NewLines { L"\r\n" };
/// Preamble found in .reg files
static const std::wstring Preamble { L"\ufeff" // Byte Order Mark
L"Windows Registry Editor Version 5.00\r\n"
L"\r\n" };
/// Character used at start of line beginning a registry key path
static const WCHAR KeyOpening { L'[' };
/// Character delimiting parent key from its child in a registry path
static const WCHAR PathSeparator { L'\\' };
/// Character used at end of line closing a registry key path
static const WCHAR KeyClosing { L']' };
/// Character used for default registry values
static const WCHAR DefaultValue { L'@' };
/// Character used for separating value declaration from its content
static const WCHAR ValueNameSeparator { L'=' };
/// Sequence used for describing a DWORD rendition
static const std::wstring DwordPrefix { L"dword:" };
/// Sequence used for describing a hexadecimal rendition
static const std::wstring HexPrefix { L"hex" };
/// Character used when beginning the value type for a hexadecimal rendition
static const WCHAR HexTypeSpecOpening { L'(' };
/// Character used when ending the value type for a hexadecimal rendition
static const WCHAR HexTypeSpecClosing { L')' };
/// Character at the beginning of the hexadecimal rendition
static const WCHAR HexSuffix { L':' };
/// Byte separator in hexadecimal renditions
static const WCHAR HexByteSeparator { L',' };
/// Desired maximal line length when dumping hexadecimal rendition of registry values
static const SIZE_T HexWrappingLimit = 80u;
/// Count of leading spaces when wrapping a hexadecimal rendition
static const SIZE_T HexNewLineLeadingSpaces = 2u;
/// Space character at the beginning of a continuation line when wrapping hex values
static const WCHAR LeadingSpace { L' '};
/// Sequence used when continuing a hexadecimal rendition on a new line
static const std::wstring HexByteNewLine { L"\\\r\n" };
};
};
+81 -81
View File
@@ -1,82 +1,82 @@
// (C) Stormshield 2022
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details
#pragma once
#include <Windows.h>
#include <string>
#include <vector>
/// Internal representation of a registry value.
struct RegistryValue {
/// Name of the registry value. May not contain null character
std::wstring Name;
/// Type of the registry value. Usually a small number.
DWORD Type;
/// Binary representation of the underlying data as a byte buffer.
std::vector<BYTE> BinaryValue;
};
/// Internal representation of a registry key.
struct RegistryKey {
/// Name of the registry key. May contain any character except backslash
std::wstring Name;
/// Container of subkeys
std::vector<RegistryKey> Subkeys;
/// Container of values
std::vector<RegistryValue> Values;
};
/// @brief Create an internal representation of a registry key from a registry hive (binary) file
/// @param[in] HiveFilePath Path to the registry hive
/// @param[in] RootName Path to the root key for export
/// @param[out] RegKey Internal structure
/// @return HRESULT semantics
/// @note For the moment, system files that are created (.LOG1, .LOG2) are not cleaned up.
_Must_inspect_result_
HRESULT HiveToInternal
(
_In_ const std::wstring &HiveFilePath,
_In_ const std::wstring &RootName,
_Out_ RegistryKey& RegKey
);
/// @brief Create a .reg file from the internal representation of a registry key
/// @param[in] RegKey Representation of the registry key
/// @param[in] OutputFilePath Path of the desired output file
/// @return HRESULT semantics
/// @note #OutputFilePath is overwritten if it already exists
_Must_inspect_result_
HRESULT InternalToRegfile
(
_In_ const RegistryKey& RegKey,
_In_ const std::wstring &OutputFilePath
);
/// @brief Create a hive file from the internal representation of a registry key
/// @param[in] RegKey Representation of the registry key
/// @param[in] OutputFilePath Path of the desired output file
/// @return HRESULT semantics
/// @note #OutputFilePath is overwritten if it already exists
_Must_inspect_result_
HRESULT InternalToHive
(
_In_ const RegistryKey& RegKey,
_In_ const std::wstring &OutputFilePath
);
/// @brief Create an internal representation of a registry key from a registry .reg (text) file
/// @param[in] RegFilePath Path to the registry .reg file
/// @param[out] RegKey Internal structure
/// @return HRESULT semantics
_Must_inspect_result_
HRESULT RegfileToInternal
(
_In_ const std::wstring& RegFilePath,
_Out_ RegistryKey& RegKey
// (C) Stormshield 2023
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details
#pragma once
#include <Windows.h>
#include <string>
#include <vector>
/// Internal representation of a registry value.
struct RegistryValue {
/// Name of the registry value. May not contain null character
std::wstring Name;
/// Type of the registry value. Usually a small number.
DWORD Type;
/// Binary representation of the underlying data as a byte buffer.
std::vector<BYTE> BinaryValue;
};
/// Internal representation of a registry key.
struct RegistryKey {
/// Name of the registry key. May contain any character except backslash
std::wstring Name;
/// Container of subkeys
std::vector<RegistryKey> Subkeys;
/// Container of values
std::vector<RegistryValue> Values;
};
/// @brief Create an internal representation of a registry key from a registry hive (binary) file
/// @param[in] HiveFilePath Path to the registry hive
/// @param[in] RootName Path to the root key for export
/// @param[out] RegKey Internal structure
/// @return HRESULT semantics
/// @note For the moment, system files that are created (.LOG1, .LOG2) are not cleaned up.
_Must_inspect_result_
HRESULT HiveToInternal
(
_In_ const std::wstring &HiveFilePath,
_In_ const std::wstring &RootName,
_Out_ RegistryKey& RegKey
);
/// @brief Create a .reg file from the internal representation of a registry key
/// @param[in] RegKey Representation of the registry key
/// @param[in] OutputFilePath Path of the desired output file
/// @return HRESULT semantics
/// @note #OutputFilePath is overwritten if it already exists
_Must_inspect_result_
HRESULT InternalToRegfile
(
_In_ const RegistryKey& RegKey,
_In_ const std::wstring &OutputFilePath
);
/// @brief Create a hive file from the internal representation of a registry key
/// @param[in] RegKey Representation of the registry key
/// @param[in] OutputFilePath Path of the desired output file
/// @return HRESULT semantics
/// @note #OutputFilePath is overwritten if it already exists
_Must_inspect_result_
HRESULT InternalToHive
(
_In_ const RegistryKey& RegKey,
_In_ const std::wstring &OutputFilePath
);
/// @brief Create an internal representation of a registry key from a registry .reg (text) file
/// @param[in] RegFilePath Path to the registry .reg file
/// @param[out] RegKey Internal structure
/// @return HRESULT semantics
_Must_inspect_result_
HRESULT RegfileToInternal
(
_In_ const std::wstring& RegFilePath,
_Out_ RegistryKey& RegKey
);
+100 -100
View File
@@ -1,101 +1,101 @@
// (C) Stormshield 2022
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details
#include <windows.h>
#include <iostream>
#include "Conversions.h"
#include "CommonFunctions.h"
#include "Constants.h"
/// @brief Program entry point
/// @param[in] Argc Command line token count, including program name
/// @param[in] Argv Tokens of the command line (#Argc valid entries)
/// @retval EXIT_SUCCESS Program execution successful
/// @retval EXIT_FAILURE Program execution failed
int wmain(
INT CONST Argc,
LPCWSTR CONST* CONST Argv
)
{
HRESULT Result = E_FAIL;
RegistryKey InternalStruct;
auto Usage = [&]()
{
std::wcerr << L"Usage: " << std::endl <<
L"\t" << Argv[0] << L" " << Constants::Program::HiveToRegFileSwitch << L" <HiveFile> <RegFile>" << std::endl <<
L"\t" << Argv[0] << L" " << Constants::Program::RegFileToHiveSwitch << L" <RegFile> <HiveFile>" << std::endl <<
std::endl;
};
if (Argc <= 1)
{
Usage();
Result = S_OK;
goto Cleanup;
}
if (Constants::Program::HiveToRegFileSwitch == Argv[1])
{
if (Argc != 4)
{
Usage();
Result = E_INVALIDARG;
goto Cleanup;
}
const std::wstring HivePath { Argv[2] };
const std::wstring RegPath { Argv[3] };
Result = HiveToInternal(HivePath, Constants::Defaults::ExportKeyPath, InternalStruct);
if (FAILED(Result))
{
goto Cleanup;
}
Result = InternalToRegfile(InternalStruct, RegPath);
if (FAILED(Result))
{
goto Cleanup;
}
}
else if (Constants::Program::RegFileToHiveSwitch == Argv[1])
{
if (Argc != 4)
{
Usage();
Result = E_INVALIDARG;
goto Cleanup;
}
const std::wstring RegPath { Argv[2] };
const std::wstring HivePath { Argv[3] };
Result = RegfileToInternal(RegPath, InternalStruct);
if (FAILED(Result))
{
ReportError(Result, L"Serializing registry file" + RegPath);
goto Cleanup;
}
Result = InternalToHive(InternalStruct, HivePath);
if (FAILED(Result))
{
ReportError(Result, L"Writing hive file " + HivePath);
goto Cleanup;
}
}
else
{
Usage();
Result = E_INVALIDARG;
goto Cleanup;
}
Result = S_OK;
Cleanup:
return FAILED(Result) ? EXIT_FAILURE : EXIT_SUCCESS;
// (C) Stormshield 2023
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details
#include <windows.h>
#include <iostream>
#include "Conversions.h"
#include "CommonFunctions.h"
#include "Constants.h"
/// @brief Program entry point
/// @param[in] Argc Command line token count, including program name
/// @param[in] Argv Tokens of the command line (#Argc valid entries)
/// @retval EXIT_SUCCESS Program execution successful
/// @retval EXIT_FAILURE Program execution failed
int wmain(
INT CONST Argc,
LPCWSTR CONST* CONST Argv
)
{
HRESULT Result = E_FAIL;
RegistryKey InternalStruct;
auto Usage = [&]()
{
std::wcerr << L"Usage: " << std::endl <<
L"\t" << Argv[0] << L" " << Constants::Program::HiveToRegFileSwitch << L" <HiveFile> <RegFile>" << std::endl <<
L"\t" << Argv[0] << L" " << Constants::Program::RegFileToHiveSwitch << L" <RegFile> <HiveFile>" << std::endl <<
std::endl;
};
if (Argc <= 1)
{
Usage();
Result = S_OK;
goto Cleanup;
}
if (Constants::Program::HiveToRegFileSwitch == Argv[1])
{
if (Argc != 4)
{
Usage();
Result = E_INVALIDARG;
goto Cleanup;
}
const std::wstring HivePath { Argv[2] };
const std::wstring RegPath { Argv[3] };
Result = HiveToInternal(HivePath, Constants::Defaults::ExportKeyPath, InternalStruct);
if (FAILED(Result))
{
goto Cleanup;
}
Result = InternalToRegfile(InternalStruct, RegPath);
if (FAILED(Result))
{
goto Cleanup;
}
}
else if (Constants::Program::RegFileToHiveSwitch == Argv[1])
{
if (Argc != 4)
{
Usage();
Result = E_INVALIDARG;
goto Cleanup;
}
const std::wstring RegPath { Argv[2] };
const std::wstring HivePath { Argv[3] };
Result = RegfileToInternal(RegPath, InternalStruct);
if (FAILED(Result))
{
ReportError(Result, L"Serializing registry file" + RegPath);
goto Cleanup;
}
Result = InternalToHive(InternalStruct, HivePath);
if (FAILED(Result))
{
ReportError(Result, L"Writing hive file " + HivePath);
goto Cleanup;
}
}
else
{
Usage();
Result = E_INVALIDARG;
goto Cleanup;
}
Result = S_OK;
Cleanup:
return FAILED(Result) ? EXIT_FAILURE : EXIT_SUCCESS;
}
+110 -110
View File
@@ -1,110 +1,110 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,2,0,0
PRODUCTVERSION 1,2,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Stormshield SAS"
VALUE "FileDescription", "Conversions between Registry export format and Registry hive"
VALUE "FileVersion", "1.2.0.0"
VALUE "InternalName", "HiveSwarming.exe"
VALUE "LegalCopyright", "Copyright (C) 2022 Stormshield SAS"
VALUE "OriginalFilename", "HiveSwarming.exe"
VALUE "ProductName", "HiveSwarming"
VALUE "ProductVersion", "1.2.0.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// French (France) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA)
LANGUAGE LANG_FRENCH, SUBLANG_FRENCH
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // French (France) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,3,0,0
PRODUCTVERSION 1,3,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Stormshield SAS"
VALUE "FileDescription", "Conversions between Registry export format and Registry hive"
VALUE "FileVersion", "1.3.0.0"
VALUE "InternalName", "HiveSwarming.exe"
VALUE "LegalCopyright", "Copyright (C) 2022 Stormshield SAS"
VALUE "OriginalFilename", "HiveSwarming.exe"
VALUE "ProductName", "HiveSwarming"
VALUE "ProductVersion", "1.3.0.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// French (France) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA)
LANGUAGE LANG_FRENCH, SUBLANG_FRENCH
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // French (France) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
+188 -188
View File
@@ -1,189 +1,189 @@
// (C) Stormshield 2022
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details
#include "Conversions.h"
#include "CommonFunctions.h"
#include <sstream>
/// @brief Create an internal representation of a registry key from the handle to a registry key
/// @param[in] Hkey the registry key
/// @param[in] KeyName Name of the key #Hkey is a handle to
/// @param[out] RegKey Representation of the key
/// @return HRESULT semantics
_Must_inspect_result_
static HRESULT HkeyToInternal
(
_In_ const HKEY Hkey,
_In_ const std::wstring& KeyName,
_Out_ RegistryKey& RegKey
)
{
HRESULT Result = E_FAIL;
DWORD SubkeyCount = 0;
DWORD MaximalSubKeyLength = 0;
DWORD ValueCount = 0;
DWORD MaximalValueNameLength = 0;
DWORD MaximalValueLength = 0;
LPWSTR SubKeyNameBuffer = NULL;
LPWSTR ValueNameBuffer = NULL;
PBYTE ValueBuffer = NULL;
if (Hkey == NULL)
{
ReportError(E_HANDLE, L"Null HKEY");
return E_HANDLE;
}
Result = HRESULT_FROM_WIN32(RegQueryInfoKeyW(Hkey, NULL, 0, NULL, &SubkeyCount, &MaximalSubKeyLength,
NULL, &ValueCount, &MaximalValueNameLength, &MaximalValueLength, NULL, NULL));
if (FAILED(Result))
{
ReportError(Result, L"Getting information on HKEY - Current key name: " + KeyName);
goto Cleanup;
}
SubKeyNameBuffer = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (1 + MaximalSubKeyLength) * sizeof(WCHAR));
if (SubKeyNameBuffer == NULL)
{
Result = HRESULT_FROM_WIN32(GetLastError());
ReportError(Result, L"Allocating space for subkey names - Current key name: " + KeyName);
goto Cleanup;
}
ValueNameBuffer = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (1 + MaximalValueNameLength) * sizeof(WCHAR));
if (ValueNameBuffer == NULL)
{
Result = HRESULT_FROM_WIN32(GetLastError());
ReportError(Result, L"Allocating space for value names - Current key name: " + KeyName);
goto Cleanup;
}
ValueBuffer = (PBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MaximalValueLength);
if (ValueBuffer == NULL)
{
Result = HRESULT_FROM_WIN32(GetLastError());
ReportError(Result, L"Allocating space for values - Current key name: " + KeyName);
goto Cleanup;
}
RegKey.Name = KeyName;
for (DWORD ValueIndex = 0; ValueIndex < ValueCount; ++ValueIndex)
{
DWORD ValueNameLength = MaximalValueNameLength + 1;
DWORD ValueType = 0;
DWORD DataLength = MaximalValueLength + 1;
Result = HRESULT_FROM_WIN32(RegEnumValueW(Hkey, ValueIndex, ValueNameBuffer, &ValueNameLength,
NULL, &ValueType, ValueBuffer, &DataLength));
if (FAILED(Result))
{
std::wostringstream ErrorMessageStream;
ErrorMessageStream << L"Getting value at index " << ValueIndex << L" - Current key name: " << KeyName;
ReportError(Result, ErrorMessageStream.str());
goto Cleanup;
}
RegistryValue NewValue;
NewValue.Name.assign(ValueNameBuffer, ValueNameLength);
NewValue.Type = ValueType;
NewValue.BinaryValue.assign(ValueBuffer, ValueBuffer + DataLength);
RegKey.Values.emplace_back(std::move(NewValue));
}
for (DWORD SubkeyIndex = 0; SubkeyIndex < SubkeyCount; ++SubkeyIndex)
{
HKEY HSubkey = NULL;
DWORD SubkeyNameLength = MaximalSubKeyLength + 1;
Result = HRESULT_FROM_WIN32(RegEnumKeyExW(Hkey, SubkeyIndex, SubKeyNameBuffer, &SubkeyNameLength, NULL, NULL, NULL, NULL));
if (FAILED(Result))
{
std::wostringstream ErrorMessageStream;
ErrorMessageStream << L"Getting subkey name at index " << SubkeyIndex << L" - Current key name: " << KeyName;
ReportError(Result, ErrorMessageStream.str());
goto Cleanup;
}
Result = HRESULT_FROM_WIN32(RegOpenKeyExW(Hkey, SubKeyNameBuffer, REG_OPTION_OPEN_LINK, KEY_READ, &HSubkey));
if (FAILED(Result)) {
Result = HRESULT_FROM_WIN32(RegOpenKeyExW(Hkey, SubKeyNameBuffer, 0, KEY_READ, &HSubkey));
}
if (FAILED(Result))
{
std::wostringstream ErrorMessageStream;
ErrorMessageStream << L"Opening subkey named " << SubKeyNameBuffer << L" at index " << SubkeyIndex << L" - Current key name: " << KeyName;
ReportError(Result, ErrorMessageStream.str());
goto Cleanup;
}
std::wstring SubkeyName;
SubkeyName.assign(SubKeyNameBuffer, SubkeyNameLength);
RegistryKey NewKey;
Result = HkeyToInternal(HSubkey, SubkeyName, NewKey);
if (FAILED(Result))
{
std::wostringstream ErrorMessageStream;
ErrorMessageStream << L"Getting contents of subkey named " << SubkeyName << L" - Current key name: " << KeyName;
ReportError(Result, ErrorMessageStream.str());
goto Cleanup;
}
RegKey.Subkeys.emplace_back(std::move(NewKey));
RegCloseKey(HSubkey);
}
Cleanup:
if (SubKeyNameBuffer)
{
HeapFree(GetProcessHeap(), 0, (LPVOID)SubKeyNameBuffer);
SubKeyNameBuffer = NULL;
}
if (ValueNameBuffer)
{
HeapFree(GetProcessHeap(), 0, (LPVOID)ValueNameBuffer);
ValueNameBuffer = NULL;
}
if (ValueBuffer)
{
HeapFree(GetProcessHeap(), 0, (LPVOID)ValueBuffer);
ValueBuffer = NULL;
}
return Result;
}
// non-static function: documented in header.
_Must_inspect_result_
HRESULT HiveToInternal
(
_In_ const std::wstring& HiveFilePath,
_In_ const std::wstring& RootName,
_Out_ RegistryKey& RegKey
)
{
HRESULT Result = E_FAIL;
HKEY HiveKey = NULL;
Result = HRESULT_FROM_WIN32(RegLoadAppKeyW(HiveFilePath.c_str(), &HiveKey, KEY_ALL_ACCESS, REG_PROCESS_APPKEY, 0));
if (FAILED(Result))
{
ReportError(Result, L"Loading hive file " + HiveFilePath);
goto Cleanup;
}
Result = HkeyToInternal(HiveKey, RootName, RegKey);
Cleanup:
if (HiveKey != NULL)
{
RegCloseKey(HiveKey);
HiveKey = NULL;
DeleteHiveLogFiles(HiveFilePath);
}
return Result;
// (C) Stormshield 2023
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details
#include "Conversions.h"
#include "CommonFunctions.h"
#include <sstream>
/// @brief Create an internal representation of a registry key from the handle to a registry key
/// @param[in] Hkey the registry key
/// @param[in] KeyName Name of the key #Hkey is a handle to
/// @param[out] RegKey Representation of the key
/// @return HRESULT semantics
_Must_inspect_result_
static HRESULT HkeyToInternal
(
_In_ const HKEY Hkey,
_In_ const std::wstring& KeyName,
_Out_ RegistryKey& RegKey
)
{
HRESULT Result = E_FAIL;
DWORD SubkeyCount = 0;
DWORD MaximalSubKeyLength = 0;
DWORD ValueCount = 0;
DWORD MaximalValueNameLength = 0;
DWORD MaximalValueLength = 0;
LPWSTR SubKeyNameBuffer = NULL;
LPWSTR ValueNameBuffer = NULL;
PBYTE ValueBuffer = NULL;
if (Hkey == NULL)
{
ReportError(E_HANDLE, L"Null HKEY");
return E_HANDLE;
}
Result = HRESULT_FROM_WIN32(RegQueryInfoKeyW(Hkey, NULL, 0, NULL, &SubkeyCount, &MaximalSubKeyLength,
NULL, &ValueCount, &MaximalValueNameLength, &MaximalValueLength, NULL, NULL));
if (FAILED(Result))
{
ReportError(Result, L"Getting information on HKEY - Current key name: " + KeyName);
goto Cleanup;
}
SubKeyNameBuffer = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (1 + MaximalSubKeyLength) * sizeof(WCHAR));
if (SubKeyNameBuffer == NULL)
{
Result = HRESULT_FROM_WIN32(GetLastError());
ReportError(Result, L"Allocating space for subkey names - Current key name: " + KeyName);
goto Cleanup;
}
ValueNameBuffer = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (1 + MaximalValueNameLength) * sizeof(WCHAR));
if (ValueNameBuffer == NULL)
{
Result = HRESULT_FROM_WIN32(GetLastError());
ReportError(Result, L"Allocating space for value names - Current key name: " + KeyName);
goto Cleanup;
}
ValueBuffer = (PBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MaximalValueLength);
if (ValueBuffer == NULL)
{
Result = HRESULT_FROM_WIN32(GetLastError());
ReportError(Result, L"Allocating space for values - Current key name: " + KeyName);
goto Cleanup;
}
RegKey.Name = KeyName;
for (DWORD ValueIndex = 0; ValueIndex < ValueCount; ++ValueIndex)
{
DWORD ValueNameLength = MaximalValueNameLength + 1;
DWORD ValueType = 0;
DWORD DataLength = MaximalValueLength + 1;
Result = HRESULT_FROM_WIN32(RegEnumValueW(Hkey, ValueIndex, ValueNameBuffer, &ValueNameLength,
NULL, &ValueType, ValueBuffer, &DataLength));
if (FAILED(Result))
{
std::wostringstream ErrorMessageStream;
ErrorMessageStream << L"Getting value at index " << ValueIndex << L" - Current key name: " << KeyName;
ReportError(Result, ErrorMessageStream.str());
goto Cleanup;
}
RegistryValue NewValue;
NewValue.Name.assign(ValueNameBuffer, ValueNameLength);
NewValue.Type = ValueType;
NewValue.BinaryValue.assign(ValueBuffer, ValueBuffer + DataLength);
RegKey.Values.emplace_back(std::move(NewValue));
}
for (DWORD SubkeyIndex = 0; SubkeyIndex < SubkeyCount; ++SubkeyIndex)
{
HKEY HSubkey = NULL;
DWORD SubkeyNameLength = MaximalSubKeyLength + 1;
Result = HRESULT_FROM_WIN32(RegEnumKeyExW(Hkey, SubkeyIndex, SubKeyNameBuffer, &SubkeyNameLength, NULL, NULL, NULL, NULL));
if (FAILED(Result))
{
std::wostringstream ErrorMessageStream;
ErrorMessageStream << L"Getting subkey name at index " << SubkeyIndex << L" - Current key name: " << KeyName;
ReportError(Result, ErrorMessageStream.str());
goto Cleanup;
}
Result = HRESULT_FROM_WIN32(RegOpenKeyExW(Hkey, SubKeyNameBuffer, REG_OPTION_OPEN_LINK, KEY_READ, &HSubkey));
if (FAILED(Result)) {
Result = HRESULT_FROM_WIN32(RegOpenKeyExW(Hkey, SubKeyNameBuffer, 0, KEY_READ, &HSubkey));
}
if (FAILED(Result))
{
std::wostringstream ErrorMessageStream;
ErrorMessageStream << L"Opening subkey named " << SubKeyNameBuffer << L" at index " << SubkeyIndex << L" - Current key name: " << KeyName;
ReportError(Result, ErrorMessageStream.str());
goto Cleanup;
}
std::wstring SubkeyName;
SubkeyName.assign(SubKeyNameBuffer, SubkeyNameLength);
RegistryKey NewKey;
Result = HkeyToInternal(HSubkey, SubkeyName, NewKey);
if (FAILED(Result))
{
std::wostringstream ErrorMessageStream;
ErrorMessageStream << L"Getting contents of subkey named " << SubkeyName << L" - Current key name: " << KeyName;
ReportError(Result, ErrorMessageStream.str());
goto Cleanup;
}
RegKey.Subkeys.emplace_back(std::move(NewKey));
RegCloseKey(HSubkey);
}
Cleanup:
if (SubKeyNameBuffer)
{
HeapFree(GetProcessHeap(), 0, (LPVOID)SubKeyNameBuffer);
SubKeyNameBuffer = NULL;
}
if (ValueNameBuffer)
{
HeapFree(GetProcessHeap(), 0, (LPVOID)ValueNameBuffer);
ValueNameBuffer = NULL;
}
if (ValueBuffer)
{
HeapFree(GetProcessHeap(), 0, (LPVOID)ValueBuffer);
ValueBuffer = NULL;
}
return Result;
}
// non-static function: documented in header.
_Must_inspect_result_
HRESULT HiveToInternal
(
_In_ const std::wstring& HiveFilePath,
_In_ const std::wstring& RootName,
_Out_ RegistryKey& RegKey
)
{
HRESULT Result = E_FAIL;
HKEY HiveKey = NULL;
Result = HRESULT_FROM_WIN32(RegLoadAppKeyW(HiveFilePath.c_str(), &HiveKey, KEY_READ, REG_PROCESS_APPKEY, 0));
if (FAILED(Result))
{
ReportError(Result, L"Loading hive file " + HiveFilePath);
goto Cleanup;
}
Result = HkeyToInternal(HiveKey, RootName, RegKey);
Cleanup:
if (HiveKey != NULL)
{
RegCloseKey(HiveKey);
HiveKey = NULL;
DeleteHiveLogFiles(HiveFilePath);
}
return Result;
}
+138 -138
View File
@@ -1,139 +1,139 @@
// (C) Stormshield 2022
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details
#include "Conversions.h"
#include "CommonFunctions.h"
#include <sstream>
#include <iomanip>
#include "Constants.h"
/// @brief Fill an empty HKEY with internal structures representing a registry key and dependencies
/// @param[in] RegKey Registry key to dump into the HKEY
/// @param[in] KeyHandle Handle to the key
/// @return HRESULT semantics
_Must_inspect_result_
static HRESULT InternalToHkey(
_In_ const RegistryKey& RegKey,
_In_ const HKEY KeyHandle
)
{
HRESULT Result = E_FAIL;
HKEY SubkeyHandle = NULL;
if (KeyHandle == NULL)
{
ReportError(E_HANDLE, L"Invalid Parameter");
return E_HANDLE;
}
for (auto &Value : RegKey.Values)
{
if (Value.BinaryValue.size() > MAXDWORD)
{
ReportError(E_UNEXPECTED, L"Binary value is too long (name: " + Value.Name + L")");
Result = E_UNEXPECTED;
goto Cleanup;
}
Result = HRESULT_FROM_WIN32(RegSetValueExW(KeyHandle, Value.Name.c_str(), 0, Value.Type,
Value.BinaryValue.data(), static_cast<DWORD>(Value.BinaryValue.size())));
if (FAILED(Result))
{
ReportError(Result, L"Could not set value " + Value.Name + L" of key " + RegKey.Name);
goto Cleanup;
}
}
for (auto &Key : RegKey.Subkeys)
{
if (SubkeyHandle != NULL)
{
RegCloseKey(SubkeyHandle);
SubkeyHandle = NULL;
}
if (Key.Values.size() == 1 && Key.Subkeys.size() == 0 && Key.Values[0].Type == REG_LINK && Key.Values[0].Name == Constants::Hives::SymbolicLinkValue)
{
Result = HRESULT_FROM_WIN32(RegCreateKeyExW(KeyHandle, Key.Name.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE | REG_OPTION_CREATE_LINK,
KEY_ALL_ACCESS, NULL, &SubkeyHandle, NULL));
}
else
{
Result = HRESULT_FROM_WIN32(RegCreateKeyExW(KeyHandle, Key.Name.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL, &SubkeyHandle, NULL));
}
if (FAILED(Result))
{
ReportError(Result, L"Could not create subkey " + Key.Name + L" of key " + RegKey.Name);
goto Cleanup;
}
Result = InternalToHkey(Key, SubkeyHandle);
if (FAILED(Result))
{
ReportError(Result, L"Could not render subkey " + Key.Name + L" of key " + RegKey.Name);
goto Cleanup;
}
}
Result = S_OK;
Cleanup:
if (SubkeyHandle != NULL)
{
RegCloseKey(SubkeyHandle);
SubkeyHandle = NULL;
}
return Result;
}
// non-static function: documented in header.
_Must_inspect_result_
HRESULT InternalToHive
(
_In_ const RegistryKey& RegKey,
_In_ const std::wstring& OutputFilePath
)
{
HRESULT Result = E_FAIL;
HKEY HiveKey = NULL;
if (!DeleteFileW(OutputFilePath.c_str()))
{
if (GetLastError() != ERROR_FILE_NOT_FOUND)
{
Result = HRESULT_FROM_WIN32(GetLastError());
ReportError(Result, L"Could not delete hive file " + OutputFilePath);
goto Cleanup;
}
}
Result = HRESULT_FROM_WIN32(RegLoadAppKeyW(OutputFilePath.c_str(), &HiveKey, KEY_ALL_ACCESS, REG_PROCESS_APPKEY, 0));
if (FAILED(Result))
{
ReportError(Result, L"Could not create empty hive file " + OutputFilePath);
goto Cleanup;
}
Result = InternalToHkey(RegKey, HiveKey);
if (FAILED(Result))
{
ReportError(Result, L"Could not render internal structure to hive");
}
Result = S_OK;
Cleanup:
if (HiveKey != NULL)
{
RegCloseKey(HiveKey);
HiveKey = NULL;
DeleteHiveLogFiles(OutputFilePath);
}
return Result;
// (C) Stormshield 2023
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details
#include "Conversions.h"
#include "CommonFunctions.h"
#include <sstream>
#include <iomanip>
#include "Constants.h"
/// @brief Fill an empty HKEY with internal structures representing a registry key and dependencies
/// @param[in] RegKey Registry key to dump into the HKEY
/// @param[in] KeyHandle Handle to the key
/// @return HRESULT semantics
_Must_inspect_result_
static HRESULT InternalToHkey(
_In_ const RegistryKey& RegKey,
_In_ const HKEY KeyHandle
)
{
HRESULT Result = E_FAIL;
HKEY SubkeyHandle = NULL;
if (KeyHandle == NULL)
{
ReportError(E_HANDLE, L"Invalid Parameter");
return E_HANDLE;
}
for (auto &Value : RegKey.Values)
{
if (Value.BinaryValue.size() > MAXDWORD)
{
ReportError(E_UNEXPECTED, L"Binary value is too long (name: " + Value.Name + L")");
Result = E_UNEXPECTED;
goto Cleanup;
}
Result = HRESULT_FROM_WIN32(RegSetValueExW(KeyHandle, Value.Name.c_str(), 0, Value.Type,
Value.BinaryValue.data(), static_cast<DWORD>(Value.BinaryValue.size())));
if (FAILED(Result))
{
ReportError(Result, L"Could not set value " + Value.Name + L" of key " + RegKey.Name);
goto Cleanup;
}
}
for (auto &Key : RegKey.Subkeys)
{
if (SubkeyHandle != NULL)
{
RegCloseKey(SubkeyHandle);
SubkeyHandle = NULL;
}
if (Key.Values.size() == 1 && Key.Subkeys.size() == 0 && Key.Values[0].Type == REG_LINK && Key.Values[0].Name == Constants::Hives::SymbolicLinkValue)
{
Result = HRESULT_FROM_WIN32(RegCreateKeyExW(KeyHandle, Key.Name.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE | REG_OPTION_CREATE_LINK,
KEY_ALL_ACCESS, NULL, &SubkeyHandle, NULL));
}
else
{
Result = HRESULT_FROM_WIN32(RegCreateKeyExW(KeyHandle, Key.Name.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL, &SubkeyHandle, NULL));
}
if (FAILED(Result))
{
ReportError(Result, L"Could not create subkey " + Key.Name + L" of key " + RegKey.Name);
goto Cleanup;
}
Result = InternalToHkey(Key, SubkeyHandle);
if (FAILED(Result))
{
ReportError(Result, L"Could not render subkey " + Key.Name + L" of key " + RegKey.Name);
goto Cleanup;
}
}
Result = S_OK;
Cleanup:
if (SubkeyHandle != NULL)
{
RegCloseKey(SubkeyHandle);
SubkeyHandle = NULL;
}
return Result;
}
// non-static function: documented in header.
_Must_inspect_result_
HRESULT InternalToHive
(
_In_ const RegistryKey& RegKey,
_In_ const std::wstring& OutputFilePath
)
{
HRESULT Result = E_FAIL;
HKEY HiveKey = NULL;
if (!DeleteFileW(OutputFilePath.c_str()))
{
if (GetLastError() != ERROR_FILE_NOT_FOUND)
{
Result = HRESULT_FROM_WIN32(GetLastError());
ReportError(Result, L"Could not delete hive file " + OutputFilePath);
goto Cleanup;
}
}
Result = HRESULT_FROM_WIN32(RegLoadAppKeyW(OutputFilePath.c_str(), &HiveKey, KEY_ALL_ACCESS, REG_PROCESS_APPKEY, 0));
if (FAILED(Result))
{
ReportError(Result, L"Could not create empty hive file " + OutputFilePath);
goto Cleanup;
}
Result = InternalToHkey(RegKey, HiveKey);
if (FAILED(Result))
{
ReportError(Result, L"Could not render internal structure to hive");
}
Result = S_OK;
Cleanup:
if (HiveKey != NULL)
{
RegCloseKey(HiveKey);
HiveKey = NULL;
DeleteHiveLogFiles(OutputFilePath);
}
return Result;
}
+396 -396
View File
@@ -1,397 +1,397 @@
// (C) Stormshield 2022
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details
#include "Constants.h"
#include "Conversions.h"
#include "CommonFunctions.h"
#include <sstream>
#include <iomanip>
/// @brief Append binary contents of a std::wstring to an opened file
/// @param[in] OutFileHandle Handle to the file
/// @param[in] String Input string
/// @note The string buffer is dumped to the file “as is”.
/// Null characters may be appended to the file if the string buffer includes some of them.
_Must_inspect_result_
static HRESULT WriteStringBufferToFile
(
_In_ const HANDLE OutFileHandle,
_In_ const std::wstring String
)
{
HRESULT Result = E_FAIL;
if (String.length() >= MAXDWORD / sizeof(decltype(String)::traits_type::char_type))
{
Result = HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
ReportError(Result, L"Writing data that is too large");
return Result;
}
if (OutFileHandle == NULL || OutFileHandle == INVALID_HANDLE_VALUE)
{
ReportError(E_HANDLE, L"Invalid parameter");
return E_HANDLE;
}
{
const DWORD BytesToWrite = static_cast<DWORD>(String.length() * sizeof(decltype(String)::traits_type::char_type));
DWORD BytesWritten = 0;
if (!WriteFile(OutFileHandle, (LPCVOID)String.c_str(), BytesToWrite, &BytesWritten, NULL))
{
Result = HRESULT_FROM_WIN32(GetLastError());
ReportError(Result, L"Could not write to output file");
return Result;
}
if (BytesWritten != BytesToWrite)
{
Result = E_UNEXPECTED;
ReportError(Result, L"Bytes not fully written to file");
return Result;
}
}
return S_OK;
}
/// @brief Render the contents of a registry value in a .reg file
/// @param[in] OutFileHandle Handle to the file
/// @param[in] FirstLineSizeSoFar How many characters have already been written on the line when dumping
/// the name of the value and the equal sign.
/// This is used for mimicking .reg format line breaks before lines over 80 characters
/// @param[in] RegValue Representation of the registry value
/// @return HRESULT semantics
_Must_inspect_result_
static HRESULT RenderBinaryValue
(
_In_ const HANDLE OutFileHandle,
_In_ const SIZE_T FirstLineSizeSoFar,
_In_ const RegistryValue& RegValue
)
{
HRESULT Result = E_FAIL;
SIZE_T CurLineSizeSoFar = FirstLineSizeSoFar;
if (OutFileHandle == NULL || OutFileHandle == INVALID_HANDLE_VALUE)
{
return E_HANDLE;
}
std::wostringstream BinaryRenditionStream;
BinaryRenditionStream << Constants::RegFiles::HexPrefix;
if (RegValue.Type != REG_BINARY)
{
BinaryRenditionStream << Constants::RegFiles::HexTypeSpecOpening << std::hex << RegValue.Type << Constants::RegFiles::HexTypeSpecClosing;
}
BinaryRenditionStream << Constants::RegFiles::HexSuffix;
CurLineSizeSoFar += BinaryRenditionStream.str().length();
for (std::vector<BYTE>::const_iterator CurByteIt = RegValue.BinaryValue.cbegin(); CurByteIt != RegValue.BinaryValue.cend(); ++CurByteIt)
{
BinaryRenditionStream << std::hex << std::setfill(L'0') << std::setw(2) << *CurByteIt;
CurLineSizeSoFar += 2;
if (CurByteIt + 1 != RegValue.BinaryValue.cend())
{
BinaryRenditionStream << Constants::RegFiles::HexByteSeparator;
CurLineSizeSoFar += 1;
if (CurLineSizeSoFar > Constants::RegFiles::HexWrappingLimit - 4)
{
// adding "xx,\" would go over 80 characters, reg export typically breaks line here.
BinaryRenditionStream << Constants::RegFiles::HexByteNewLine;
for (SIZE_T SpaceCount = 0; SpaceCount < Constants::RegFiles::HexNewLineLeadingSpaces; ++SpaceCount)
{
BinaryRenditionStream << Constants::RegFiles::LeadingSpace;
}
CurLineSizeSoFar = Constants::RegFiles::HexNewLineLeadingSpaces;
}
}
}
BinaryRenditionStream << Constants::RegFiles::NewLines;
Result = WriteStringBufferToFile(OutFileHandle, BinaryRenditionStream.str());
if (FAILED(Result))
{
ReportError(Result, L"Could not write to output file");
return Result;
}
return S_OK;
}
/// @brief Render the contents of a REG_DWORD registry value in a .reg file
/// @param[in] OutFileHandle Handle to the file
/// @param[in] FirstLineSizeSoFar Use for fallback to #RenderBinaryValue
/// @param[in] RegValue Representation of the registry value
/// @return HRESULT semantics
_Must_inspect_result_
static HRESULT RenderDwordValue
(
_In_ const HANDLE OutFileHandle,
_In_ const SIZE_T FirstLineSizeSoFar,
_In_ const RegistryValue& RegValue
)
{
if (OutFileHandle == NULL || OutFileHandle == INVALID_HANDLE_VALUE)
{
ReportError(E_HANDLE, L"Invalid parameter");
return E_HANDLE;
}
if (RegValue.Type != REG_DWORD)
{
ReportError(E_HANDLE, L"Invalid parameter");
return E_INVALIDARG;
}
if (RegValue.BinaryValue.size() != sizeof(DWORD))
{
return RenderBinaryValue(OutFileHandle, FirstLineSizeSoFar, RegValue);
}
std::wostringstream DwordRenditionStream;
DwordRenditionStream << L"dword:";
DwordRenditionStream << std::hex << std::setw(8) << std::setfill(L'0') << *(DWORD*)(RegValue.BinaryValue.data());
DwordRenditionStream << Constants::RegFiles::NewLines;
return WriteStringBufferToFile(OutFileHandle, DwordRenditionStream.str());
}
/// @brief Render the contents of a REG_SZ registry value in a .reg file
/// @param[in] OutFileHandle Handle to the file
/// @param[in] FirstLineSizeSoFar Use for fallback to #RenderBinaryValue
/// @param[in] RegValue Representation of the registry value
/// @return HRESULT semantics
/// @note This falls back to binary rendition if the REG_SZ does not meet requirements such as:
/// - REG_SZ values should be terminated by a null character
/// - REG_SZ values may not contain other null characters
/// - REG_SZ value sizes should be a multiple of 2 as they store WCHAR-based values.
_Must_inspect_result_
static HRESULT RenderStringValue
(
_In_ const HANDLE OutFileHandle,
_In_ const SIZE_T FirstLineSizeSoFar,
_In_ const RegistryValue& RegValue
)
{
std::wstring WstringValue;
if (OutFileHandle == NULL || OutFileHandle == INVALID_HANDLE_VALUE)
{
ReportError(E_HANDLE, L"Invalid parameter");
return E_HANDLE;
}
if (RegValue.Type != REG_SZ)
{
ReportError(E_HANDLE, L"Invalid parameter");
return E_INVALIDARG;
}
if (RegValue.BinaryValue.size() % sizeof(WCHAR) != 0)
{
return RenderBinaryValue(OutFileHandle, FirstLineSizeSoFar, RegValue);
}
WstringValue.assign((PWCHAR) RegValue.BinaryValue.data(), RegValue.BinaryValue.size() / sizeof(WCHAR));
if (WstringValue.empty())
{
return RenderBinaryValue(OutFileHandle, FirstLineSizeSoFar, RegValue);
}
if ( WstringValue.empty()
|| WstringValue.back() != L'\0'
|| std::count(WstringValue.cbegin(), WstringValue.cend() - 1, L'\0') != 0
)
{
return RenderBinaryValue(OutFileHandle, FirstLineSizeSoFar, RegValue);
}
// Now we can render the value as REG_SZ: Remove null character
WstringValue.pop_back();
GlobalStringSubstitute(WstringValue, L"\\", L"\\\\");
GlobalStringSubstitute(WstringValue, L"\"", L"\\\"");
GlobalStringSubstitute(WstringValue, L"\n", L"\r\n");
std::wostringstream StringRenditionStream;
StringRenditionStream << L"\"" << WstringValue << L"\"" << Constants::RegFiles::NewLines;
return WriteStringBufferToFile(OutFileHandle, StringRenditionStream.str());
}
/// @brief Render a registry value and its contents in a .reg file
/// @param[in] OutFileHandle Handle to the file
/// @param[in] RegValue Representation of the registry value
/// @return HRESULT semantics
_Must_inspect_result_
HRESULT RenderRegistryValue
(
_In_ const HANDLE OutFileHandle,
_In_ const RegistryValue& RegValue
)
{
HRESULT Result = E_FAIL;
SIZE_T FirstLineSizeSoFar = 0;
if (OutFileHandle == NULL || OutFileHandle == INVALID_HANDLE_VALUE)
{
ReportError(E_HANDLE, L"Invalid parameter");
return E_HANDLE;
}
std::wstring EscapedName = RegValue.Name;
GlobalStringSubstitute(EscapedName, L"\\", L"\\\\");
GlobalStringSubstitute(EscapedName, L"\"", L"\\\"");
GlobalStringSubstitute(EscapedName, L"\n", L"\r\n");
std::wostringstream Str;
if (EscapedName.empty())
{
Str << Constants::RegFiles::DefaultValue << Constants::RegFiles::ValueNameSeparator;
}
else
{
Str << L"\"" << EscapedName << L"\"=";
}
Result = WriteStringBufferToFile(OutFileHandle, Str.str());
if (FAILED(Result))
{
ReportError(Result, L"Could not write data to file");
return Result;
}
FirstLineSizeSoFar += Str.str().length();
if (RegValue.Type == REG_DWORD)
{
return RenderDwordValue(OutFileHandle, FirstLineSizeSoFar, RegValue);
}
if (RegValue.Type == REG_SZ)
{
return RenderStringValue(OutFileHandle, FirstLineSizeSoFar, RegValue);
}
return RenderBinaryValue(OutFileHandle, FirstLineSizeSoFar, RegValue);
}
/// @brief Render a registry key and its values and subkeys in a .reg file
/// @param[in] OutFileHandle Handle to the file
/// @param[in] RegKey Representation of the registry key
/// @param[in] PathSoFar Path to this key
/// @return HRESULT semantics
_Must_inspect_result_
HRESULT RenderRegistryKey
(
_In_ const HANDLE OutFileHandle,
_In_ const RegistryKey& RegKey,
_In_ const std::wstring &PathSoFar
)
{
HRESULT Result = E_FAIL;
if (OutFileHandle == NULL || OutFileHandle == INVALID_HANDLE_VALUE)
{
ReportError(E_HANDLE, L"Invalid parameter");
return E_HANDLE;
}
std::wstring NewPath;
if (PathSoFar.empty())
{
NewPath = RegKey.Name;
}
else
{
NewPath = PathSoFar + Constants::RegFiles::PathSeparator + RegKey.Name;
}
std::wstring EscapedPath { NewPath };
GlobalStringSubstitute(EscapedPath, L"\n", L"\r\n");
{
std::wostringstream KeySpecStream;
KeySpecStream << Constants::RegFiles::KeyOpening << EscapedPath << Constants::RegFiles::KeyClosing << Constants::RegFiles::NewLines;
Result = WriteStringBufferToFile(OutFileHandle, KeySpecStream.str());
if (FAILED(Result))
{
ReportError(E_HANDLE, L"Could not write to output file");
return Result;
}
}
for (const RegistryValue &Value : RegKey.Values)
{
Result = RenderRegistryValue(OutFileHandle, Value);
if (FAILED(Result))
{
ReportError(E_HANDLE, L"Could not render registry value" + Value.Name);
return Result;
}
}
{
Result = WriteStringBufferToFile(OutFileHandle, Constants::RegFiles::NewLines );
if (FAILED(Result))
{
ReportError(E_HANDLE, L"Could not write to output file");
return Result;
}
}
for (const RegistryKey &Key : RegKey.Subkeys)
{
Result = RenderRegistryKey(OutFileHandle, Key, NewPath);
if (FAILED(Result))
{
ReportError(E_HANDLE, L"Could not render registry key" + Key.Name);
return Result;
}
}
return S_OK;
}
// non-static function: documented in header.
_Must_inspect_result_
HRESULT InternalToRegfile
(
_In_ const RegistryKey& RegKey,
_In_ const std::wstring& OutputFilePath
)
{
HRESULT Result = E_FAIL;
HANDLE OutFileHandle = INVALID_HANDLE_VALUE;
OutFileHandle = CreateFileW(OutputFilePath.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (OutFileHandle == INVALID_HANDLE_VALUE)
{
Result = HRESULT_FROM_WIN32(GetLastError());
ReportError(Result, L"Could not open file " + OutputFilePath + L" for writing");
goto Cleanup;
}
{
Result = WriteStringBufferToFile(OutFileHandle, Constants::RegFiles::Preamble);
if (FAILED(Result))
{
ReportError(Result, L"Could not write to output file");
goto Cleanup;
}
}
Result = RenderRegistryKey(OutFileHandle, RegKey, std::wstring{});
if (FAILED(Result))
{
ReportError(Result, L"Could not render registry key");
goto Cleanup;
}
Result = S_OK;
Cleanup:
if (OutFileHandle != INVALID_HANDLE_VALUE)
{
CloseHandle(OutFileHandle);
OutFileHandle = INVALID_HANDLE_VALUE;
}
return Result;
// (C) Stormshield 2023
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details
#include "Constants.h"
#include "Conversions.h"
#include "CommonFunctions.h"
#include <sstream>
#include <iomanip>
/// @brief Append binary contents of a std::wstring to an opened file
/// @param[in] OutFileHandle Handle to the file
/// @param[in] String Input string
/// @note The string buffer is dumped to the file “as is”.
/// Null characters may be appended to the file if the string buffer includes some of them.
_Must_inspect_result_
static HRESULT WriteStringBufferToFile
(
_In_ const HANDLE OutFileHandle,
_In_ const std::wstring String
)
{
HRESULT Result = E_FAIL;
if (String.length() >= MAXDWORD / sizeof(decltype(String)::traits_type::char_type))
{
Result = HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
ReportError(Result, L"Writing data that is too large");
return Result;
}
if (OutFileHandle == NULL || OutFileHandle == INVALID_HANDLE_VALUE)
{
ReportError(E_HANDLE, L"Invalid parameter");
return E_HANDLE;
}
{
const DWORD BytesToWrite = static_cast<DWORD>(String.length() * sizeof(decltype(String)::traits_type::char_type));
DWORD BytesWritten = 0;
if (!WriteFile(OutFileHandle, (LPCVOID)String.c_str(), BytesToWrite, &BytesWritten, NULL))
{
Result = HRESULT_FROM_WIN32(GetLastError());
ReportError(Result, L"Could not write to output file");
return Result;
}
if (BytesWritten != BytesToWrite)
{
Result = E_UNEXPECTED;
ReportError(Result, L"Bytes not fully written to file");
return Result;
}
}
return S_OK;
}
/// @brief Render the contents of a registry value in a .reg file
/// @param[in] OutFileHandle Handle to the file
/// @param[in] FirstLineSizeSoFar How many characters have already been written on the line when dumping
/// the name of the value and the equal sign.
/// This is used for mimicking .reg format line breaks before lines over 80 characters
/// @param[in] RegValue Representation of the registry value
/// @return HRESULT semantics
_Must_inspect_result_
static HRESULT RenderBinaryValue
(
_In_ const HANDLE OutFileHandle,
_In_ const SIZE_T FirstLineSizeSoFar,
_In_ const RegistryValue& RegValue
)
{
HRESULT Result = E_FAIL;
SIZE_T CurLineSizeSoFar = FirstLineSizeSoFar;
if (OutFileHandle == NULL || OutFileHandle == INVALID_HANDLE_VALUE)
{
return E_HANDLE;
}
std::wostringstream BinaryRenditionStream;
BinaryRenditionStream << Constants::RegFiles::HexPrefix;
if (RegValue.Type != REG_BINARY)
{
BinaryRenditionStream << Constants::RegFiles::HexTypeSpecOpening << std::hex << RegValue.Type << Constants::RegFiles::HexTypeSpecClosing;
}
BinaryRenditionStream << Constants::RegFiles::HexSuffix;
CurLineSizeSoFar += BinaryRenditionStream.str().length();
for (std::vector<BYTE>::const_iterator CurByteIt = RegValue.BinaryValue.cbegin(); CurByteIt != RegValue.BinaryValue.cend(); ++CurByteIt)
{
BinaryRenditionStream << std::hex << std::setfill(L'0') << std::setw(2) << *CurByteIt;
CurLineSizeSoFar += 2;
if (CurByteIt + 1 != RegValue.BinaryValue.cend())
{
BinaryRenditionStream << Constants::RegFiles::HexByteSeparator;
CurLineSizeSoFar += 1;
if (CurLineSizeSoFar > Constants::RegFiles::HexWrappingLimit - 4)
{
// adding "xx,\" would go over 80 characters, reg export typically breaks line here.
BinaryRenditionStream << Constants::RegFiles::HexByteNewLine;
for (SIZE_T SpaceCount = 0; SpaceCount < Constants::RegFiles::HexNewLineLeadingSpaces; ++SpaceCount)
{
BinaryRenditionStream << Constants::RegFiles::LeadingSpace;
}
CurLineSizeSoFar = Constants::RegFiles::HexNewLineLeadingSpaces;
}
}
}
BinaryRenditionStream << Constants::RegFiles::NewLines;
Result = WriteStringBufferToFile(OutFileHandle, BinaryRenditionStream.str());
if (FAILED(Result))
{
ReportError(Result, L"Could not write to output file");
return Result;
}
return S_OK;
}
/// @brief Render the contents of a REG_DWORD registry value in a .reg file
/// @param[in] OutFileHandle Handle to the file
/// @param[in] FirstLineSizeSoFar Use for fallback to #RenderBinaryValue
/// @param[in] RegValue Representation of the registry value
/// @return HRESULT semantics
_Must_inspect_result_
static HRESULT RenderDwordValue
(
_In_ const HANDLE OutFileHandle,
_In_ const SIZE_T FirstLineSizeSoFar,
_In_ const RegistryValue& RegValue
)
{
if (OutFileHandle == NULL || OutFileHandle == INVALID_HANDLE_VALUE)
{
ReportError(E_HANDLE, L"Invalid parameter");
return E_HANDLE;
}
if (RegValue.Type != REG_DWORD)
{
ReportError(E_HANDLE, L"Invalid parameter");
return E_INVALIDARG;
}
if (RegValue.BinaryValue.size() != sizeof(DWORD))
{
return RenderBinaryValue(OutFileHandle, FirstLineSizeSoFar, RegValue);
}
std::wostringstream DwordRenditionStream;
DwordRenditionStream << L"dword:";
DwordRenditionStream << std::hex << std::setw(8) << std::setfill(L'0') << *(DWORD*)(RegValue.BinaryValue.data());
DwordRenditionStream << Constants::RegFiles::NewLines;
return WriteStringBufferToFile(OutFileHandle, DwordRenditionStream.str());
}
/// @brief Render the contents of a REG_SZ registry value in a .reg file
/// @param[in] OutFileHandle Handle to the file
/// @param[in] FirstLineSizeSoFar Use for fallback to #RenderBinaryValue
/// @param[in] RegValue Representation of the registry value
/// @return HRESULT semantics
/// @note This falls back to binary rendition if the REG_SZ does not meet requirements such as:
/// - REG_SZ values should be terminated by a null character
/// - REG_SZ values may not contain other null characters
/// - REG_SZ value sizes should be a multiple of 2 as they store WCHAR-based values.
_Must_inspect_result_
static HRESULT RenderStringValue
(
_In_ const HANDLE OutFileHandle,
_In_ const SIZE_T FirstLineSizeSoFar,
_In_ const RegistryValue& RegValue
)
{
std::wstring WstringValue;
if (OutFileHandle == NULL || OutFileHandle == INVALID_HANDLE_VALUE)
{
ReportError(E_HANDLE, L"Invalid parameter");
return E_HANDLE;
}
if (RegValue.Type != REG_SZ)
{
ReportError(E_HANDLE, L"Invalid parameter");
return E_INVALIDARG;
}
if (RegValue.BinaryValue.size() % sizeof(WCHAR) != 0)
{
return RenderBinaryValue(OutFileHandle, FirstLineSizeSoFar, RegValue);
}
WstringValue.assign((PWCHAR) RegValue.BinaryValue.data(), RegValue.BinaryValue.size() / sizeof(WCHAR));
if (WstringValue.empty())
{
return RenderBinaryValue(OutFileHandle, FirstLineSizeSoFar, RegValue);
}
if ( WstringValue.empty()
|| WstringValue.back() != L'\0'
|| std::count(WstringValue.cbegin(), WstringValue.cend() - 1, L'\0') != 0
)
{
return RenderBinaryValue(OutFileHandle, FirstLineSizeSoFar, RegValue);
}
// Now we can render the value as REG_SZ: Remove null character
WstringValue.pop_back();
GlobalStringSubstitute(WstringValue, L"\\", L"\\\\");
GlobalStringSubstitute(WstringValue, L"\"", L"\\\"");
GlobalStringSubstitute(WstringValue, L"\n", L"\r\n");
std::wostringstream StringRenditionStream;
StringRenditionStream << L"\"" << WstringValue << L"\"" << Constants::RegFiles::NewLines;
return WriteStringBufferToFile(OutFileHandle, StringRenditionStream.str());
}
/// @brief Render a registry value and its contents in a .reg file
/// @param[in] OutFileHandle Handle to the file
/// @param[in] RegValue Representation of the registry value
/// @return HRESULT semantics
_Must_inspect_result_
HRESULT RenderRegistryValue
(
_In_ const HANDLE OutFileHandle,
_In_ const RegistryValue& RegValue
)
{
HRESULT Result = E_FAIL;
SIZE_T FirstLineSizeSoFar = 0;
if (OutFileHandle == NULL || OutFileHandle == INVALID_HANDLE_VALUE)
{
ReportError(E_HANDLE, L"Invalid parameter");
return E_HANDLE;
}
std::wstring EscapedName = RegValue.Name;
GlobalStringSubstitute(EscapedName, L"\\", L"\\\\");
GlobalStringSubstitute(EscapedName, L"\"", L"\\\"");
GlobalStringSubstitute(EscapedName, L"\n", L"\r\n");
std::wostringstream Str;
if (EscapedName.empty())
{
Str << Constants::RegFiles::DefaultValue << Constants::RegFiles::ValueNameSeparator;
}
else
{
Str << L"\"" << EscapedName << L"\"=";
}
Result = WriteStringBufferToFile(OutFileHandle, Str.str());
if (FAILED(Result))
{
ReportError(Result, L"Could not write data to file");
return Result;
}
FirstLineSizeSoFar += Str.str().length();
if (RegValue.Type == REG_DWORD)
{
return RenderDwordValue(OutFileHandle, FirstLineSizeSoFar, RegValue);
}
if (RegValue.Type == REG_SZ)
{
return RenderStringValue(OutFileHandle, FirstLineSizeSoFar, RegValue);
}
return RenderBinaryValue(OutFileHandle, FirstLineSizeSoFar, RegValue);
}
/// @brief Render a registry key and its values and subkeys in a .reg file
/// @param[in] OutFileHandle Handle to the file
/// @param[in] RegKey Representation of the registry key
/// @param[in] PathSoFar Path to this key
/// @return HRESULT semantics
_Must_inspect_result_
HRESULT RenderRegistryKey
(
_In_ const HANDLE OutFileHandle,
_In_ const RegistryKey& RegKey,
_In_ const std::wstring &PathSoFar
)
{
HRESULT Result = E_FAIL;
if (OutFileHandle == NULL || OutFileHandle == INVALID_HANDLE_VALUE)
{
ReportError(E_HANDLE, L"Invalid parameter");
return E_HANDLE;
}
std::wstring NewPath;
if (PathSoFar.empty())
{
NewPath = RegKey.Name;
}
else
{
NewPath = PathSoFar + Constants::RegFiles::PathSeparator + RegKey.Name;
}
std::wstring EscapedPath { NewPath };
GlobalStringSubstitute(EscapedPath, L"\n", L"\r\n");
{
std::wostringstream KeySpecStream;
KeySpecStream << Constants::RegFiles::KeyOpening << EscapedPath << Constants::RegFiles::KeyClosing << Constants::RegFiles::NewLines;
Result = WriteStringBufferToFile(OutFileHandle, KeySpecStream.str());
if (FAILED(Result))
{
ReportError(E_HANDLE, L"Could not write to output file");
return Result;
}
}
for (const RegistryValue &Value : RegKey.Values)
{
Result = RenderRegistryValue(OutFileHandle, Value);
if (FAILED(Result))
{
ReportError(E_HANDLE, L"Could not render registry value" + Value.Name);
return Result;
}
}
{
Result = WriteStringBufferToFile(OutFileHandle, Constants::RegFiles::NewLines );
if (FAILED(Result))
{
ReportError(E_HANDLE, L"Could not write to output file");
return Result;
}
}
for (const RegistryKey &Key : RegKey.Subkeys)
{
Result = RenderRegistryKey(OutFileHandle, Key, NewPath);
if (FAILED(Result))
{
ReportError(E_HANDLE, L"Could not render registry key" + Key.Name);
return Result;
}
}
return S_OK;
}
// non-static function: documented in header.
_Must_inspect_result_
HRESULT InternalToRegfile
(
_In_ const RegistryKey& RegKey,
_In_ const std::wstring& OutputFilePath
)
{
HRESULT Result = E_FAIL;
HANDLE OutFileHandle = INVALID_HANDLE_VALUE;
OutFileHandle = CreateFileW(OutputFilePath.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (OutFileHandle == INVALID_HANDLE_VALUE)
{
Result = HRESULT_FROM_WIN32(GetLastError());
ReportError(Result, L"Could not open file " + OutputFilePath + L" for writing");
goto Cleanup;
}
{
Result = WriteStringBufferToFile(OutFileHandle, Constants::RegFiles::Preamble);
if (FAILED(Result))
{
ReportError(Result, L"Could not write to output file");
goto Cleanup;
}
}
Result = RenderRegistryKey(OutFileHandle, RegKey, std::wstring{});
if (FAILED(Result))
{
ReportError(Result, L"Could not render registry key");
goto Cleanup;
}
Result = S_OK;
Cleanup:
if (OutFileHandle != INVALID_HANDLE_VALUE)
{
CloseHandle(OutFileHandle);
OutFileHandle = INVALID_HANDLE_VALUE;
}
return Result;
}
+549 -549
View File
File diff suppressed because it is too large Load Diff