Skip to content

Commit

Permalink
HiveSwarming - version 1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
salsifis committed Feb 10, 2020
0 parents commit d937f5a
Show file tree
Hide file tree
Showing 17 changed files with 1,905 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.vs
*.vcxproj.user
Binary file added Binx64/HiveSwarming.exe
Binary file not shown.
Binary file added Binx64/HiveSwarming.pdb
Binary file not shown.
60 changes: 60 additions & 0 deletions CommonFunctions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// (C) Stormshield 2020
// 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;
}
22 changes: 22 additions & 0 deletions CommonFunctions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// (C) Stormshield 2020
// 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{}
);
87 changes: 87 additions & 0 deletions Constants.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// (C) Stormshield 2020
// 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" };
};

/// .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;

/// Sequence used when continuing a hexadecimal rendition on a new line
static const std::wstring HexByteNewLine { L"\\\r\n\u0020\u0020" };
};
};

82 changes: 82 additions & 0 deletions Conversions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// (C) Stormshield 2020
// 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
);
101 changes: 101 additions & 0 deletions HiveSwarming.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// (C) Stormshield 2020
// 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;
}
31 changes: 31 additions & 0 deletions HiveSwarming.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29609.76
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HiveSwarming", "HiveSwarming.vcxproj", "{00DC3B6B-A592-4736-9CA9-130E4DF06CD4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{00DC3B6B-A592-4736-9CA9-130E4DF06CD4}.Debug|x64.ActiveCfg = Debug|x64
{00DC3B6B-A592-4736-9CA9-130E4DF06CD4}.Debug|x64.Build.0 = Debug|x64
{00DC3B6B-A592-4736-9CA9-130E4DF06CD4}.Debug|x86.ActiveCfg = Debug|Win32
{00DC3B6B-A592-4736-9CA9-130E4DF06CD4}.Debug|x86.Build.0 = Debug|Win32
{00DC3B6B-A592-4736-9CA9-130E4DF06CD4}.Release|x64.ActiveCfg = Release|x64
{00DC3B6B-A592-4736-9CA9-130E4DF06CD4}.Release|x64.Build.0 = Release|x64
{00DC3B6B-A592-4736-9CA9-130E4DF06CD4}.Release|x86.ActiveCfg = Release|Win32
{00DC3B6B-A592-4736-9CA9-130E4DF06CD4}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FD1888F9-D331-4CD9-A58D-0C0F01F6735B}
EndGlobalSection
EndGlobal
Loading

0 comments on commit d937f5a

Please sign in to comment.