Skip to content

Commit

Permalink
Added /RemoveStreams
Browse files Browse the repository at this point in the history
- Added /RemoveStreams command to remove any extra alternate data streams.
- Adjusted thread local storage to use non-Microsoft syntax.
- Removed redundant 'ERROR:' qualifier in some output strings.
  • Loading branch information
NoMoreFood committed Jul 2, 2021
1 parent 166c151 commit 2d63ee7
Show file tree
Hide file tree
Showing 15 changed files with 163 additions and 16 deletions.
Binary file modified Build/Release/x64/repacls.exe
Binary file not shown.
Binary file modified Build/Release/x86/repacls.exe
Binary file not shown.
Binary file modified Build/Repacls.zip
Binary file not shown.
2 changes: 1 addition & 1 deletion Build/build.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ CLS
SET PATH=%WINDIR%\system32;%WINDIR%\system32\WindowsPowerShell\v1.0

:: cert info to use for signing
SET CERT=193A6FACBFBFC43ADB74ABB669543FCBC1C4F26C
SET CERT=BC4F81C0B3B32755A8CC9A6B91713958294788F0
set TSAURL=http://time.certum.pl/
set LIBNAME=Repacls
set LIBURL=https://github.com/NoMoreFood/Repacls
Expand Down
4 changes: 2 additions & 2 deletions OperationBackupSecurity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ bool OperationBackupSecurity::ProcessSdAction(std::wstring & sFileName, ObjectEn
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION,
&sInfo, NULL) == 0)
{
InputOutput::AddError(L"ERROR: Unable to generate string security descriptor.");
InputOutput::AddError(L"Unable to generate string security descriptor.");
return false;
}

Expand All @@ -55,7 +55,7 @@ bool OperationBackupSecurity::ProcessSdAction(std::wstring & sFileName, ObjectEn
if (WriteToFile(sToWrite, hFile) == 0)
{
LocalFree(sInfo);
InputOutput::AddError(L"ERROR: Unable to write security descriptor to file.");
InputOutput::AddError(L"Unable to write security descriptor to file.");
return false;
}

Expand Down
7 changes: 5 additions & 2 deletions OperationHelp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ this way is preferable to multiple commands because the security descriptor is
only read and written once for the entire command which is especially helpful
for large volumes.
Commands That Do Not Alter Security
Commands That Do Not Alter Settings
-----------------------------------
/PrintDescriptor
Prints out the security descriptor to the screen. This is somewhat useful
Expand Down Expand Up @@ -156,7 +156,7 @@ Commands That Do Not Alter Security
regular expression to refine what part of the security descriptor to scan.
See Other Notes & Limitations section for more information.
Commands That Can Alter Security (When /WhatIf Is Not Present)
Commands That Can Alter Settings (When /WhatIf Is Not Present)
--------------------------------
/GrantPerms <Name|Sid>:<Flags>
/DenyPerms <Name|Sid>:<Flags>
Expand Down Expand Up @@ -228,6 +228,9 @@ Commands That Can Alter Security (When /WhatIf Is Not Present)
have been littered from the old cacls.exe command that didn't understand
how to set up inheritance.
/RemoveStreams
Removes any alternate data streams on targeted files.
/ReplaceAccount <SearchName|SearchSid>:<ReplaceName|ReplaceSid>
Search for an account and replace it with another account.
Expand Down
2 changes: 1 addition & 1 deletion OperationLocate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,6 @@ void OperationLocate::ProcessObjectAction(ObjectEntry & tObjectEntry)
L"," + Q(sSize) + L"," + Q(sAttributes) + L"\r\n";
if (WriteToFile(sToWrite, hReportFile) == 0)
{
InputOutput::AddError(L"ERROR: Unable to write security information to report file.");
InputOutput::AddError(L"Unable to write security information to report file.");
}
}
8 changes: 4 additions & 4 deletions OperationLocateHash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,10 @@ void OperationLocateHash::ProcessObjectAction(ObjectEntry & tObjectEntry)

// initialize hash for this thread
static constexpr size_t iFileBuffer = 2 * 1024 * 1024;
__declspec(thread) static BCRYPT_HASH_HANDLE HashHandle = NULL;
__declspec(thread) static PBYTE Hash = nullptr;
__declspec(thread) static PBYTE FileBuffer = nullptr;
__declspec(thread) static DWORD HashLength = 0;
thread_local static BCRYPT_HASH_HANDLE HashHandle = NULL;
thread_local static PBYTE Hash = nullptr;
thread_local static PBYTE FileBuffer = nullptr;
thread_local static DWORD HashLength = 0;
if (Hash == nullptr)
{
BCRYPT_ALG_HANDLE AlgHandle = NULL;
Expand Down
8 changes: 4 additions & 4 deletions OperationLocateShortcut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,14 @@ void OperationLocateShortcut::ProcessObjectAction(ObjectEntry & tObjectEntry)
if (!std::regex_match(sFileName, tRegexLink)) return;

// initialize com for this thread
__declspec(thread) static bool bComInitialized = false;
thread_local static bool bComInitialized = false;
if (!bComInitialized)
{
bComInitialized = true;
const HRESULT hComInit = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
if (hComInit != S_OK && hComInit != S_FALSE)
{
wprintf(L"ERROR: Could not initialize COM.\n");
wprintf(L"Could not initialize COM.\n");
exit(-1);
}
}
Expand All @@ -98,7 +98,7 @@ void OperationLocateShortcut::ProcessObjectAction(ObjectEntry & tObjectEntry)
WIN32_FILE_ATTRIBUTE_DATA tData;
if (GetFileAttributesExW(tObjectEntry.Name.c_str(), GetFileExInfoStandard, &tData) == 0)
{
InputOutput::AddError(L"ERROR: Unable to read file attributes.");
InputOutput::AddError(L"Unable to read file attributes.");
}

// get common file attributes
Expand Down Expand Up @@ -137,7 +137,7 @@ void OperationLocateShortcut::ProcessObjectAction(ObjectEntry & tObjectEntry)
Q(sAttributes) + L"," + Q(sTargetPath) + L"," + Q(sWorkingDirectory) + L"\r\n";
if (WriteToFile(sToWrite, hReportFile) == 0)
{
InputOutput::AddError(L"ERROR: Unable to write security information to report file.");
InputOutput::AddError(L"Unable to write security information to report file.");
}
}

Expand Down
76 changes: 76 additions & 0 deletions OperationRemoveStreams.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#include "OperationRemoveStreams.h"
#include "InputOutput.h"
#include "Functions.h"

ClassFactory<OperationRemoveStreams> OperationRemoveStreams::RegisteredFactory(GetCommand());

OperationRemoveStreams::OperationRemoveStreams(std::queue<std::wstring>& oArgList, const std::wstring& sCommand) : Operation(oArgList)
{

// load function pointer to query file information
HMODULE hModule = GetModuleHandle(L"ntdll.dll");
if (hModule == NULL || (NtQueryInformationFile = (decltype(NtQueryInformationFile))
GetProcAddress(hModule, "NtQueryInformationFile")) == NULL)
{
wprintf(L"ERROR: Unable to obtain function pointer in parameter '%s'.\n", GetCommand().c_str());
exit(-1);
}

// only flag this to apply to the core object with the file name
AppliesToObject = true;
}

void OperationRemoveStreams::ProcessObjectAction(ObjectEntry& tObjectEntry)
{
HANDLE hFile = CreateFile(tObjectEntry.Name.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
InputOutput::AddError(L"Unable open file for stream deletion.");
return;
}

// loop until we can fill the stream into a buffer
NTSTATUS iStatus;
thread_local std::vector<BYTE> sInfoBuffer(16 * 1024, 0);
for (iStatus = STATUS_BUFFER_OVERFLOW; iStatus == STATUS_BUFFER_OVERFLOW;
sInfoBuffer.resize(sInfoBuffer.size() * 2, 0))
{
IO_STATUS_BLOCK tIOStatus = {};
iStatus = NtQueryInformationFile(hFile, &tIOStatus, sInfoBuffer.data(), (ULONG) sInfoBuffer.size(), FileStreamInformation);
if (iStatus == STATUS_SUCCESS) break;
}

// cleanup and verify we got the data we needed
CloseHandle(hFile);
if (iStatus != STATUS_SUCCESS) return;

// Loop for all streams
for (PFILE_STREAM_INFORMATION pStreamInfo = (PFILE_STREAM_INFORMATION)sInfoBuffer.data(); pStreamInfo->StreamNameLength != 0;
pStreamInfo = (PFILE_STREAM_INFORMATION)((LPBYTE)pStreamInfo + pStreamInfo->NextEntryOffset))
{
// skip main data stream
const WCHAR sData[] = L"::$DATA";
if (_countof(sData) - 1 == pStreamInfo->StreamNameLength / sizeof(WCHAR) &&
_wcsnicmp(pStreamInfo->StreamName, sData, _countof(sData) - 1) == 0)
{
if (pStreamInfo->NextEntryOffset == 0) break;
continue;
}

// remove the stream
std::wstring sStream((const wchar_t *) pStreamInfo->StreamName, (size_t) (pStreamInfo->StreamNameLength / sizeof(WCHAR)));
std::wstring sFullStreamName = (tObjectEntry.Name + sStream);
if (InputOutput::InWhatIfMode() || (SetFileAttributes(sFullStreamName.c_str(), FILE_ATTRIBUTE_NORMAL) != 0 && DeleteFile(sFullStreamName.c_str()) != 0))
{
InputOutput::AddInfo(L"Removed stream: " + sStream, L"");
}
else
{
InputOutput::AddError(L"Unable delete stream: " + sStream);
}

// break if no next stream
if (pStreamInfo->NextEntryOffset == 0) break;
}
}
60 changes: 60 additions & 0 deletions OperationRemoveStreams.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#pragma once

#define UMDF_USING_NTSTATUS
#include <ntstatus.h>

#include <regex>

#include "Operation.h"

class OperationRemoveStreams : public Operation
{
private:

// statics used by command registration utility
static std::wstring GetCommand() { return L"RemoveStreams"; }
static ClassFactory<OperationRemoveStreams> RegisteredFactory;

//
// Definitions below avoid need to install Windows Driver Development Kit
//

typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
};
ULONG_PTR Information;
} IO_STATUS_BLOCK, * PIO_STATUS_BLOCK;

typedef enum _FILE_INFORMATION_CLASS {
FileStreamInformation = 22
} FILE_INFORMATION_CLASS, * PFILE_INFORMATION_CLASS;

#pragma pack(push, 4)
typedef struct _FILE_STREAM_INFORMATION { // Information Class 22
ULONG NextEntryOffset;
ULONG StreamNameLength;
LARGE_INTEGER EndOfStream;
LARGE_INTEGER AllocationSize;
WCHAR StreamName[1];
} FILE_STREAM_INFORMATION, * PFILE_STREAM_INFORMATION;
#pragma pack(pop)

typedef NTSTATUS(NTAPI* NTQUERYINFORMATIONFILE)(
IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass);

NTQUERYINFORMATIONFILE NtQueryInformationFile;

public:

// overrides
void ProcessObjectAction(ObjectEntry & tObjectEntry) override;

// constructors
OperationRemoveStreams(std::queue<std::wstring> & oArgList, const std::wstring & sCommand);
};
4 changes: 2 additions & 2 deletions OperationReport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ SidActionResult OperationReport::DetermineSid(const WCHAR * const sSdPart, Objec
std::wstring sToWrite = Q(tObjectEntry.Name) + L"," + Q(sSdPart) + L"," + Q(sAccount) + L"\r\n";
if (WriteToFile(sToWrite, hReportFile) == 0)
{
InputOutput::AddError(L"ERROR: Unable to write security information to report file.");
InputOutput::AddError(L"Unable to write security information to report file.");
}

return SidActionResult::Nothing;
Expand Down Expand Up @@ -117,7 +117,7 @@ bool OperationReport::ProcessAclAction(const WCHAR * const sSdPart, ObjectEntry
Q(sAccount) + L"," + Q(sMask) + L"," + Q(sFlags) + L"\r\n";
if (WriteToFile(sToWrite, hReportFile) == 0)
{
InputOutput::AddError(L"ERROR: Unable to write security information to report file.");
InputOutput::AddError(L"Unable to write security information to report file.");
}
}

Expand Down
Binary file modified Resource.rc
Binary file not shown.
2 changes: 2 additions & 0 deletions repacls.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@
<ClCompile Include="OperationLocateShortcut.cpp" />
<ClCompile Include="OperationLog.cpp" />
<ClCompile Include="OperationPathList.cpp" />
<ClCompile Include="OperationRemoveStreams.cpp" />
<ClCompile Include="OperationReplaceMap.cpp" />
<ClCompile Include="OperationRestoreSecurity.cpp" />
<ClCompile Include="OperationInheritChildren.cpp" />
Expand Down Expand Up @@ -249,6 +250,7 @@
<ClInclude Include="OperationLocate.h" />
<ClInclude Include="OperationLog.h" />
<ClInclude Include="OperationPathList.h" />
<ClInclude Include="OperationRemoveStreams.h" />
<ClInclude Include="OperationReplaceMap.h" />
<ClInclude Include="OperationRestoreSecurity.h" />
<ClInclude Include="OperationSharePaths.h" />
Expand Down
6 changes: 6 additions & 0 deletions repacls.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@
<ClCompile Include="OperationCopyMap.cpp">
<Filter>Source\Operations</Filter>
</ClCompile>
<ClCompile Include="OperationRemoveStreams.cpp">
<Filter>Source\Operations</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ConcurrentQueue.h">
Expand Down Expand Up @@ -258,6 +261,9 @@
<ClInclude Include="OperationCopyMap.h">
<Filter>Includes\Operations</Filter>
</ClInclude>
<ClInclude Include="OperationRemoveStreams.h">
<Filter>Includes\Operations</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Includes">
Expand Down

0 comments on commit 2d63ee7

Please sign in to comment.