Skip to content

Commit

Permalink
Support symbolic links
Browse files Browse the repository at this point in the history
  • Loading branch information
salsifis committed Feb 28, 2022
1 parent 038c610 commit aa880f9
Show file tree
Hide file tree
Showing 19 changed files with 214 additions and 22 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.vs
*.vcxproj.user
*.aps
Binary file modified Binx64/HiveSwarming.exe
Binary file not shown.
Binary file removed Binx64/HiveSwarming.pdb
Binary file not shown.
13 changes: 13 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
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
2 changes: 1 addition & 1 deletion CommonFunctions.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// (C) Stormshield 2020
// (C) Stormshield 2022
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details

Expand Down
2 changes: 1 addition & 1 deletion CommonFunctions.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// (C) Stormshield 2020
// (C) Stormshield 2022
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details

Expand Down
10 changes: 8 additions & 2 deletions Constants.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// (C) Stormshield 2020
// (C) Stormshield 2022
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details

Expand Down Expand Up @@ -29,6 +29,9 @@ namespace 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
Expand Down Expand Up @@ -80,8 +83,11 @@ namespace Constants {
/// 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\u0020\u0020" };
static const std::wstring HexByteNewLine { L"\\\r\n" };
};
};

2 changes: 1 addition & 1 deletion Conversions.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// (C) Stormshield 2020
// (C) Stormshield 2022
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details

Expand Down
2 changes: 1 addition & 1 deletion HiveSwarming.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// (C) Stormshield 2020
// (C) Stormshield 2022
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details

Expand Down
110 changes: 110 additions & 0 deletions HiveSwarming.rc
Original file line number Diff line number Diff line change
@@ -0,0 +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

4 changes: 4 additions & 0 deletions HiveSwarming.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
<ClInclude Include="Constants.h" />
<ClInclude Include="Conversions.h" />
<ClInclude Include="CommonFunctions.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="HiveSwarming.rc" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
Expand Down
8 changes: 8 additions & 0 deletions HiveSwarming.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,13 @@
<ClInclude Include="CommonFunctions.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="HiveSwarming.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>
7 changes: 5 additions & 2 deletions HiveToInternal.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// (C) Stormshield 2020
// (C) Stormshield 2022
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details

Expand Down Expand Up @@ -106,7 +106,10 @@ static HRESULT HkeyToInternal
goto Cleanup;
}

Result = HRESULT_FROM_WIN32(RegOpenKeyExW(Hkey, SubKeyNameBuffer, 0, KEY_ALL_ACCESS, &HSubkey));
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;
Expand Down
13 changes: 11 additions & 2 deletions InternalToHive.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// (C) Stormshield 2020
// (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
Expand Down Expand Up @@ -51,8 +52,16 @@ static HRESULT InternalToHkey(
SubkeyHandle = NULL;
}

Result = HRESULT_FROM_WIN32(RegCreateKeyExW(KeyHandle, Key.Name.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE,
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))
{
Expand Down
6 changes: 5 additions & 1 deletion InternalToRegfile.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// (C) Stormshield 2020
// (C) Stormshield 2022
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details

Expand Down Expand Up @@ -99,6 +99,10 @@ static HRESULT RenderBinaryValue
{
// 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;
}
}
Expand Down
2 changes: 1 addition & 1 deletion LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright 2020 Stormshield
Copyright 2022 Stormshield

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
21 changes: 13 additions & 8 deletions README.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(C) 2020 Stormshield
(C) 2022 Stormshield

HiveSwarming - Conversions between registry hive and registry export formats
without a need for special privileges.
Expand Down Expand Up @@ -30,22 +30,27 @@ A. Yes. First, when you load a hive file using the API RegLoadAppKeyW, all
Second, if a key name contains a closing bracket followed by a newline
character, your .reg file is not parseable. This limitation is also valid
for standard .reg files
Third, when converting from .reg file to a hive, any key containing a single
value named "SymbolicLinkValue" and of type REG_LINK will be recreated as a
symbolic link. This should be what is expected most of the time.

Q. Is the .reg file compatible with reg.exe import?
A. Yes. However the generated .reg file has [(HiveRoot)] as root key. You will
A. Mostly. The generated .reg file has [(HiveRoot)] as root key. You will
have to substitute it globally to make it importable at any desired location.
When converting back, it is not necessary to keep [(HiveRoot)] as the root
key, but the only requirement is that all keys descend of the first one.
When converting back, it is not necessary to keep this name for the root key,
but a requirement is that all keys descend of the first one.

Q. What are requirements for .reg files?
A. .reg files must:
- be encoded as UTF-16, Little-Endian, with a Byte Order Mark
- Use \r\n for line endings
- Start with "Windows Registry Editor Version 5.00" and one blank line
only, followed by the first key
- Have all keys be descendants of the first key
- Start with "Windows Registry Editor Version 5.00" and at least one blank
line
- Have non-empty root key (first key) name
- Have all keys be descendants of the root key
- Have no trailing or leading spaces on lines
- Have no blank lines between a key and its last value
- Have no blank lines between a key and its last value (except inside
string values when the string themselves contain blank lines)
- Have a blank line after the last value of a key (including last key)
- Be importable to the registry
Some third party software, like RegView, will generate invalid files. For
Expand Down
19 changes: 17 additions & 2 deletions RegfileToInternal.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// (C) Stormshield 2020
// (C) Stormshield 2022
// Licensed under the Apache license, version 2.0
// See LICENSE.txt for details

Expand Down Expand Up @@ -252,6 +252,9 @@ static HRESULT ValueListToInternal
}
else if (HasString(Constants::RegFiles::HexByteNewLine))
{
while (HasChar(Constants::RegFiles::LeadingSpace))
{
}
continue;
}
else if (ValueList.length() >= 2 && isxdigit(ValueList[0]) && isxdigit(ValueList[1]))
Expand Down Expand Up @@ -352,6 +355,12 @@ static HRESULT RegListToInternal
HRESULT Result = E_FAIL;
static const std::wstring KeyClosingAtEOL = Constants::RegFiles::KeyClosing + Constants::RegFiles::NewLines;

// remove additional line breaks
while (RegList.length() >= 2 && RegList[0] == L'\r' && RegList[1] == L'\n')
{
RegList.remove_prefix(2);
}

if (RegList.empty())
{
std::wostringstream ErrorMessageStream;
Expand Down Expand Up @@ -386,9 +395,10 @@ static HRESULT RegListToInternal
break;
}
const std::wstring_view KeyName{ &KeyPath[PathPrefix.length()], KeyPath.length() - PathPrefix.length() };

RegistryKey NewKey;
NewKey.Name = KeyName;
// keys may have newlines in their name
GlobalStringSubstitute(NewKey.Name, L"\r\n", L"\n");

RegList.remove_prefix(EndKeyPos + 1);
Expand Down Expand Up @@ -416,6 +426,11 @@ static HRESULT RegListToInternal
}

RegKeys.emplace_back(std::move(NewKey));

while (RegList.length() >= 2 && RegList[0] == L'\r' && RegList[1] == L'\n')
{
RegList.remove_prefix(1);
}
} while (!RegList.empty());

return S_OK;
Expand Down
14 changes: 14 additions & 0 deletions resource.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by HiveSwarming.rc

// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

0 comments on commit aa880f9

Please sign in to comment.