1317 lines
41 KiB
C++
1317 lines
41 KiB
C++
#include "Win-Ops-Master.h"
|
|
#include "NtDefine.h"
|
|
#include <sddl.h>
|
|
#include <iostream>
|
|
#include <threadpoolapiset.h>
|
|
#include <random>
|
|
|
|
DWORD LastError = 0;
|
|
|
|
OpsMaster::OpsMaster()
|
|
{
|
|
LoadLibraryW(L"ntdll.dll");
|
|
HMODULE hm = GetModuleHandleW(L"ntdll.dll");
|
|
_NtRaiseHardError = (NTSTATUS(WINAPI*)(NTSTATUS ErrorStactus, ULONG NumberOfParameters,
|
|
ULONG UnicodeStringParameterMask, PULONG_PTR * Parameters, ULONG ValidResponseOption, PULONG Response))GetProcAddress(hm, "NtRaiseHardError");
|
|
_RtlAdjustPrivilege = (NTSTATUS(WINAPI*) (ULONG Privilege, BOOLEAN Enable, BOOLEAN CurrentThread, PBOOLEAN Enabled))GetProcAddress(hm, "RtlAdjustPrivilege");
|
|
_NtSetInformationFile = (NTSTATUS(WINAPI*) (HANDLE FileHandle,
|
|
PIO_STATUS_BLOCK IoStatusBlock,
|
|
PVOID FileInformation,
|
|
ULONG Length,
|
|
FILE_INFORMATION_CLASS FileInformationClass))GetProcAddress(hm, "NtSetInformationFile");
|
|
_RtlNtStatusToDosError = (ULONG(WINAPI*) (NTSTATUS Status))GetProcAddress(hm, "RtlNtStatusToDosError");
|
|
_RtlInitUnicodeString = (NTSTATUS(WINAPI*)(PUNICODE_STRING, PCWSTR)) GetProcAddress(hm, "RtlInitUnicodeString");
|
|
_NtCreateSymbolicLinkObject = (NTSTATUS(WINAPI*)(
|
|
OUT PHANDLE pHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|
IN PUNICODE_STRING DestinationName))GetProcAddress(hm, "NtCreateSymbolicLinkObject");
|
|
_NtCreateFile = (NTSTATUS(WINAPI*)(
|
|
PHANDLE FileHandle,
|
|
ACCESS_MASK DesiredAccess,
|
|
POBJECT_ATTRIBUTES ObjectAttributes,
|
|
PIO_STATUS_BLOCK IoStatusBlock,
|
|
PLARGE_INTEGER AllocationSize,
|
|
ULONG FileAttributes,
|
|
ULONG ShareAccess,
|
|
ULONG CreateDisposition,
|
|
ULONG CreateOptions,
|
|
PVOID EaBuffer,
|
|
ULONG EaLength))GetProcAddress(hm, "NtCreateFile");
|
|
_NtSetSecurityObject = (NTSTATUS(WINAPI*)(
|
|
HANDLE Handle,
|
|
SECURITY_INFORMATION SecurityInformation,
|
|
PSECURITY_DESCRIPTOR SecurityDescriptor
|
|
))GetProcAddress(hm, "NtSetSecurityObject");
|
|
_NtOpenProcess = (NTSTATUS(WINAPI*)(
|
|
PHANDLE ProcessHandle,
|
|
ACCESS_MASK DesiredAccess,
|
|
POBJECT_ATTRIBUTES ObjectAttributes,
|
|
PCLIENT_ID ClientId
|
|
))GetProcAddress(hm, "NtOpenProcess");
|
|
_NtTerminateProcess = (NTSTATUS(WINAPI*)(
|
|
IN HANDLE ProcessHandle OPTIONAL,
|
|
IN NTSTATUS ExitStatus
|
|
))GetProcAddress(hm, "NtTerminateProcess");
|
|
_NtClose = (NTSTATUS(WINAPI*)(HANDLE Handle))GetProcAddress(hm, "NtClose");
|
|
_NtDeviceIoControlFile = (NTSTATUS(WINAPI*)(
|
|
HANDLE FileHandle,
|
|
HANDLE Event,
|
|
PIO_APC_ROUTINE ApcRoutine,
|
|
PVOID ApcContext,
|
|
PIO_STATUS_BLOCK IoStatusBlock,
|
|
ULONG IoControlCode,
|
|
PVOID InputBuffer,
|
|
ULONG InputBufferLength,
|
|
PVOID OutputBuffer,
|
|
ULONG OutputBufferLength)) GetProcAddress(hm, "NtDeviceIoControlFile");
|
|
_NtCreateDirectoryObjectEx = (NTSTATUS(WINAPI*)(
|
|
PHANDLE, ACCESS_MASK,
|
|
POBJECT_ATTRIBUTES, HANDLE, BOOLEAN
|
|
))GetProcAddress(hm, "NtCreateDirectoryObjectEx");
|
|
_NtOpenDirectoryObject = (NTSTATUS(WINAPI*)(
|
|
PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES
|
|
))GetProcAddress(hm, "NtOpenDirectoryObject");
|
|
_NtWriteFile = (NTSTATUS(WINAPI*)
|
|
(HANDLE FileHandle,
|
|
HANDLE Event,
|
|
PIO_APC_ROUTINE ApcRoutine,
|
|
PVOID ApcContext,
|
|
PIO_STATUS_BLOCK IoStatusBlock,
|
|
PVOID Buffer,
|
|
ULONG Length,
|
|
PLARGE_INTEGER ByteOffset,
|
|
PULONG Key)) GetProcAddress(hm, "NtWriteFile");
|
|
_NtWaitForSingleObject = (NTSTATUS(WINAPI*)(
|
|
IN HANDLE ObjectHandle,
|
|
IN BOOLEAN Alertable,
|
|
IN PLARGE_INTEGER TimeOut OPTIONAL)) GetProcAddress(hm, "NtWaitForSingleObject");
|
|
_NtReadFile = (NTSTATUS(WINAPI*)(
|
|
_In_ HANDLE FileHandle,
|
|
_In_opt_ HANDLE Event,
|
|
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
|
|
_In_opt_ PVOID ApcContext,
|
|
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
|
|
_Out_ PVOID Buffer,
|
|
_In_ ULONG Length,
|
|
_In_opt_ PLARGE_INTEGER ByteOffset,
|
|
_In_opt_ PULONG Key
|
|
))GetProcAddress(hm, "NtReadFile");
|
|
_NtCompareTokens = (NTSTATUS(WINAPI*)(
|
|
_In_ HANDLE FirstTokenHandle,
|
|
_In_ HANDLE SecondTokenHandle,
|
|
_Out_ PBOOLEAN Equal
|
|
)) GetProcAddress(hm, "NtCompareTokens");
|
|
_ZwDeleteFile = (NTSTATUS(WINAPI*)
|
|
(POBJECT_ATTRIBUTES ObjectAttributes))GetProcAddress(hm, "ZwDeleteFile");
|
|
_ZwCreateKey = (NTSTATUS(WINAPI*)
|
|
(PHANDLE KeyHandle,
|
|
ACCESS_MASK DesiredAccess,
|
|
POBJECT_ATTRIBUTES ObjectAttributes,
|
|
ULONG TitleIndex,
|
|
PUNICODE_STRING Class,
|
|
ULONG CreateOptions,
|
|
PULONG Disposition))GetProcAddress(hm, "ZwCreateKey");
|
|
_ZwDeleteKey = (NTSTATUS(WINAPI*)
|
|
(HANDLE KeyHandle))GetProcAddress(hm, "ZwDeleteKey");
|
|
_ZwSetValueKey = (NTSTATUS(WINAPI*)(
|
|
HANDLE KeyHandle,
|
|
PUNICODE_STRING ValueName,
|
|
ULONG TitleIndex,
|
|
ULONG Type,
|
|
PVOID Data,
|
|
ULONG DataSize
|
|
))GetProcAddress(hm, "ZwSetValueKey");
|
|
_NtSuspendProcess = (NTSTATUS(WINAPI*)(
|
|
HANDLE ProcessHandle
|
|
))GetProcAddress(hm, "NtSuspendProcess");
|
|
_NtResumeProcess = (NTSTATUS(WINAPI*)(
|
|
HANDLE ProcessHandle
|
|
))GetProcAddress(hm, "NtResumeProcess");
|
|
_ZwMakeTemporaryObject = (NTSTATUS(WINAPI*)(
|
|
HANDLE Handle
|
|
))GetProcAddress(hm, "ZwMakeTemporaryObject");
|
|
_ZwMakePermanentObject = (NTSTATUS(WINAPI*)(
|
|
HANDLE Handle
|
|
))GetProcAddress(hm, "ZwMakePermanentObject");
|
|
/*_NtOpenSymbolicLinkObject = (NTSTATUS(WINAPI*)(
|
|
_Out_ PHANDLE LinkHandle,
|
|
_In_ ACCESS_MASK DesiredAccess,
|
|
_In_ POBJECT_ATTRIBUTES ObjectAttributes
|
|
))GetProcAddress(hm, "NtOpenSymbolicLinkObject");*/
|
|
|
|
return;
|
|
}
|
|
std::wstring BuildNativePath(std::wstring path) {
|
|
//I am considering any path that start with \ is a native path
|
|
if (path.rfind(L"\\", 0) != std::wstring::npos)
|
|
return path;
|
|
path = L"\\??\\" + path;
|
|
return path;
|
|
}
|
|
|
|
DWORD OpsMaster::NtStatusToDOS(NTSTATUS status) {
|
|
return _RtlNtStatusToDosError(status);
|
|
}
|
|
|
|
DWORD OpsMaster::GetLastErr() {
|
|
return LastError;
|
|
}
|
|
|
|
void SetLastErr(DWORD err) {
|
|
LastError = err;
|
|
}
|
|
|
|
bool OpsMaster::MoveByHandle(HANDLE hfile, std::wstring target)
|
|
{
|
|
target = BuildNativePath(target);
|
|
size_t buffer_sz = sizeof(FILE_RENAME_INFO) + (target.size() * sizeof(wchar_t));
|
|
FILE_RENAME_INFO* rename_info = (FILE_RENAME_INFO*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_sz);
|
|
rename_info->ReplaceIfExists = TRUE;
|
|
rename_info->RootDirectory = NULL;
|
|
rename_info->Flags = 0x00000001 | 0x00000002 | 0x00000040;
|
|
rename_info->FileNameLength = target.size() * sizeof(wchar_t);
|
|
memcpy(&rename_info->FileName[0], target.c_str(), target.size() * sizeof(wchar_t));
|
|
IO_STATUS_BLOCK io = { 0 };
|
|
NTSTATUS status = _NtSetInformationFile(hfile, &io, rename_info, buffer_sz, FileRenameInformationEx);
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return false;
|
|
}
|
|
HeapFree(GetProcessHeap(), NULL, rename_info);
|
|
SetLastErr(GetLastError());
|
|
return true;
|
|
}
|
|
|
|
bool OpsMaster::MoveByHandle(HANDLE hfile, std::string target) {
|
|
return OpsMaster::MoveByHandle(hfile, std::wstring(target.begin(), target.end()));
|
|
}
|
|
|
|
|
|
HANDLE OpsMaster::CreateNativeSymlink(std::wstring link, std::wstring target) {
|
|
HANDLE ret;
|
|
UNICODE_STRING ulnk;
|
|
UNICODE_STRING utarget;
|
|
NTSTATUS status;
|
|
|
|
status = _RtlInitUnicodeString(&ulnk, link.c_str());
|
|
if ((status != STATUS_SUCCESS) && (status != (NTSTATUS)ulnk.MaximumLength)) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return NULL;
|
|
}
|
|
|
|
status = _RtlInitUnicodeString(&utarget, target.c_str());
|
|
if ((status != STATUS_SUCCESS) && (status != (NTSTATUS)utarget.MaximumLength)) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return NULL;
|
|
}
|
|
|
|
OBJECT_ATTRIBUTES objattr;
|
|
InitializeObjectAttributes(&objattr, &ulnk, OBJ_CASE_INSENSITIVE, nullptr, nullptr);
|
|
|
|
NTSTATUS stat = _NtCreateSymbolicLinkObject(&ret, SYMBOLIC_LINK_ALL_ACCESS,
|
|
&objattr, &utarget);
|
|
|
|
if (stat != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(stat));
|
|
return nullptr;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
HANDLE OpsMaster::CreateNativeSymlink(std::string link, std::string target) {
|
|
return OpsMaster::CreateNativeSymlink(std::wstring(link.begin(), link.end()),
|
|
std::wstring(target.begin(), target.end()));
|
|
}
|
|
bool OpsMaster::CreateDosDeviceLink(std::string link, std::string target) {
|
|
return OpsMaster::CreateDosDeviceLink(
|
|
std::wstring(link.begin(), link.end()),
|
|
std::wstring(target.begin(), target.end()));
|
|
}
|
|
|
|
bool OpsMaster::CreateDosDeviceLink(std::wstring link, std::wstring target)
|
|
{
|
|
if (link[0] == L'\\') {
|
|
link = L"Global\\GLOBALROOT" + link;
|
|
}
|
|
target = BuildNativePath(target);
|
|
DWORD LastErr = GetLastError();
|
|
if (DefineDosDeviceW(DDD_NO_BROADCAST_SYSTEM | DDD_RAW_TARGET_PATH, link.c_str(), target.c_str()))
|
|
{
|
|
SetLastErr(GetLastError());
|
|
SetLastError(LastErr);
|
|
return true;
|
|
}
|
|
SetLastErr(GetLastError());
|
|
SetLastError(LastErr);
|
|
return false;
|
|
}
|
|
|
|
bool OpsMaster::RemoveDosDeviceLink(std::string link)
|
|
{
|
|
return OpsMaster::RemoveDosDeviceLink(std::wstring(link.begin(), link.end()));
|
|
}
|
|
|
|
bool OpsMaster::RemoveDosDeviceLink(std::wstring link)
|
|
{
|
|
if (link[0] == L'\\') {
|
|
link = L"Global\\GLOBALROOT" + link;
|
|
}
|
|
DWORD LastErr = GetLastError();
|
|
if (DefineDosDeviceW(DDD_NO_BROADCAST_SYSTEM | DDD_RAW_TARGET_PATH |
|
|
DDD_REMOVE_DEFINITION,
|
|
link.c_str(), NULL))
|
|
{
|
|
SetLastErr(GetLastError());
|
|
SetLastError(LastErr);
|
|
return true;
|
|
}
|
|
SetLastErr(GetLastError());
|
|
SetLastError(LastErr);
|
|
return false;
|
|
}
|
|
|
|
HANDLE OpsMaster::OpenDirectory(std::wstring directory, DWORD access_mask, DWORD share_mode, DWORD creation_disposition, DWORD flags)
|
|
{
|
|
directory = BuildNativePath(directory);
|
|
HANDLE h;
|
|
OBJECT_ATTRIBUTES objattr;
|
|
UNICODE_STRING target;
|
|
IO_STATUS_BLOCK io;
|
|
NTSTATUS status;
|
|
_RtlInitUnicodeString(&target, directory.c_str());
|
|
InitializeObjectAttributes(&objattr, &target, OBJ_CASE_INSENSITIVE, nullptr, nullptr);
|
|
switch (creation_disposition) {
|
|
case CREATE_NEW:
|
|
status = _NtCreateFile(&h, access_mask, &objattr, &io, NULL, FILE_ATTRIBUTE_NORMAL, share_mode,
|
|
FILE_CREATE, flags ? FILE_DIRECTORY_FILE | flags : FILE_DIRECTORY_FILE | FILE_FLAG_OPEN_REPARSE_POINT, NULL, NULL);
|
|
break;
|
|
case OPEN_EXISTING:
|
|
status = _NtCreateFile(&h, access_mask, &objattr, &io, NULL, FILE_ATTRIBUTE_NORMAL, share_mode,
|
|
FILE_OPEN, flags ? FILE_DIRECTORY_FILE | flags : FILE_DIRECTORY_FILE | FILE_FLAG_OPEN_REPARSE_POINT, NULL, NULL);
|
|
break;
|
|
default:
|
|
status = _NtCreateFile(&h, access_mask, &objattr, &io, NULL, FILE_ATTRIBUTE_NORMAL, share_mode,
|
|
FILE_OPEN_IF, flags ? FILE_DIRECTORY_FILE | flags : FILE_DIRECTORY_FILE | FILE_FLAG_OPEN_REPARSE_POINT, NULL, NULL);
|
|
|
|
}
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return NULL;
|
|
}
|
|
return h;
|
|
}
|
|
|
|
HANDLE OpsMaster::OpenDirectory(std::string directory, DWORD access_mask, DWORD share_mode, DWORD creation_disposition, DWORD flags)
|
|
{
|
|
return OpsMaster::OpenDirectory(std::wstring(directory.begin(),
|
|
directory.end()), access_mask, share_mode,
|
|
creation_disposition);
|
|
}
|
|
|
|
HANDLE OpsMaster::OpenFileNative(std::wstring file, DWORD access_mask, DWORD share_mode, DWORD creation_dispostion, DWORD flags)
|
|
{
|
|
file = BuildNativePath(file);
|
|
access_mask |= SYNCHRONIZE;
|
|
OBJECT_ATTRIBUTES objattr;
|
|
UNICODE_STRING target;
|
|
IO_STATUS_BLOCK io;
|
|
_RtlInitUnicodeString(&target, file.c_str());
|
|
InitializeObjectAttributes(&objattr, &target, OBJ_CASE_INSENSITIVE, nullptr, nullptr);
|
|
NTSTATUS status = -1;
|
|
HANDLE ret = 0;
|
|
switch (creation_dispostion) {
|
|
case OPEN_EXISTING:
|
|
status = _NtCreateFile(&ret, access_mask, &objattr, &io, NULL, NULL, share_mode, FILE_OPEN,
|
|
flags ? flags : (FILE_NON_DIRECTORY_FILE | flags), NULL, NULL);
|
|
break;
|
|
case OPEN_ALWAYS:
|
|
status = _NtCreateFile(&ret, access_mask, &objattr, &io, NULL, NULL, share_mode, FILE_OPEN_IF,
|
|
flags ? flags : (FILE_NON_DIRECTORY_FILE | flags), NULL, NULL);
|
|
break;
|
|
case CREATE_ALWAYS:
|
|
status = _NtCreateFile(&ret, access_mask, &objattr, &io, NULL, NULL, share_mode, FILE_OVERWRITE_IF,
|
|
flags ? flags : (FILE_NON_DIRECTORY_FILE | flags), NULL, NULL);
|
|
break;
|
|
case CREATE_NEW:
|
|
status = _NtCreateFile(&ret, access_mask, &objattr, &io, NULL, NULL, share_mode, FILE_CREATE,
|
|
flags ? flags : (FILE_NON_DIRECTORY_FILE | flags), NULL, NULL);
|
|
break;
|
|
case TRUNCATE_EXISTING:
|
|
status = _NtCreateFile(&ret, access_mask, &objattr, &io, NULL, NULL, share_mode, FILE_OVERWRITE,
|
|
FILE_NON_DIRECTORY_FILE | flags, NULL, NULL);
|
|
break;
|
|
}
|
|
if (status != STATUS_SUCCESS)
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return ret;
|
|
}
|
|
|
|
HANDLE OpsMaster::OpenFileNative(std::string file, DWORD access_mask, DWORD share_mode, DWORD creation_dispostion, DWORD flags)
|
|
{
|
|
return OpsMaster::OpenFileNative(std::wstring(file.begin(), file.end()),
|
|
access_mask, share_mode, creation_dispostion);
|
|
}
|
|
|
|
bool OpsMaster::WriteFileNative(HANDLE hfile, PVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten)
|
|
{
|
|
IO_STATUS_BLOCK io;
|
|
LARGE_INTEGER li;
|
|
li.LowPart = 0;
|
|
li.HighPart = 0;
|
|
NTSTATUS status = _NtWriteFile(hfile, NULL,
|
|
NULL, NULL, &io, lpBuffer, nNumberOfBytesToWrite, &li, NULL);
|
|
if (status == STATUS_PENDING)
|
|
status = _NtWaitForSingleObject(hfile, FALSE, NULL);
|
|
if (lpNumberOfBytesWritten != nullptr)
|
|
*lpNumberOfBytesWritten = io.Information;
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool OpsMaster::ReadFileNative(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead)
|
|
{
|
|
if (nNumberOfBytesToRead == 0) {
|
|
LARGE_INTEGER sz;
|
|
GetFileSizeEx(hFile, &sz);
|
|
nNumberOfBytesToRead = sz.QuadPart;
|
|
}
|
|
LARGE_INTEGER offset;
|
|
offset.LowPart = 0;
|
|
offset.HighPart = 0;
|
|
IO_STATUS_BLOCK io;
|
|
NTSTATUS status = _NtReadFile(hFile, NULL, NULL, NULL,
|
|
&io, lpBuffer, nNumberOfBytesToRead, &offset, NULL);
|
|
if (status == STATUS_PENDING)
|
|
status = _NtWaitForSingleObject(hFile, FALSE, NULL);
|
|
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return false;
|
|
}
|
|
if (lpNumberOfBytesRead != nullptr)
|
|
*lpNumberOfBytesRead = io.Information;
|
|
return true;
|
|
}
|
|
|
|
HANDLE OpsMaster::OpenProcessNative(DWORD PID, DWORD access_mask)
|
|
{
|
|
HANDLE hret = nullptr;
|
|
OBJECT_ATTRIBUTES objattr;
|
|
CLIENT_ID id = { (HANDLE)PID,0 };
|
|
InitializeObjectAttributes(&objattr, 0, 0, 0, 0);
|
|
NTSTATUS status = _NtOpenProcess(&hret, access_mask, &objattr, &id);
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
}
|
|
return hret;
|
|
}
|
|
|
|
bool OpsMaster::SuspendProcess(HANDLE hprocess)
|
|
{
|
|
NTSTATUS status = _NtSuspendProcess(hprocess);
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool OpsMaster::ResumeProcess(HANDLE hprocess)
|
|
{
|
|
NTSTATUS status = _NtResumeProcess(hprocess);
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool OpsMaster::TerminateProcessNative(DWORD process_id)
|
|
{
|
|
CLIENT_ID id = { (HANDLE)process_id, 0 };
|
|
OBJECT_ATTRIBUTES objattr;
|
|
InitializeObjectAttributes(&objattr, 0, 0, 0, 0);
|
|
HANDLE proc;
|
|
NTSTATUS status = _NtOpenProcess(&proc, PROCESS_TERMINATE, &objattr, &id);
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return false;
|
|
}
|
|
status = _NtTerminateProcess(proc, STATUS_SUCCESS);
|
|
_NtClose(proc);
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool OpsMaster::TerminateProcessNative(HANDLE hprocess)
|
|
{
|
|
NTSTATUS status = _NtTerminateProcess(hprocess, STATUS_SUCCESS);
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
HANDLE OpsMaster::SetTokenDosDevice(std::wstring device_path, HANDLE htoken)
|
|
{
|
|
if (htoken != NULL) {
|
|
ImpersonateLoggedOnUser(htoken);
|
|
}
|
|
HANDLE hret = OpsMaster::CreateNativeSymlink(std::wstring(L"\\??\\c:"), std::wstring(device_path));
|
|
if (htoken != NULL) {
|
|
RevertToSelf();
|
|
}
|
|
return hret;
|
|
}
|
|
|
|
HANDLE OpsMaster::SetTokenDosDevice(std::string device_path, HANDLE htoken)
|
|
{
|
|
return OpsMaster::SetTokenDosDevice(std::wstring(device_path.begin(), device_path.end()),
|
|
htoken);
|
|
}
|
|
|
|
void OpsMaster::bsod() {
|
|
BOOLEAN b;
|
|
ULONG r;
|
|
_RtlAdjustPrivilege(19, true, false, &b);
|
|
_NtRaiseHardError(0xDeadDead, 0, 0, 0, 6, &r);
|
|
return;
|
|
}
|
|
|
|
HANDLE OpsMaster::OpenNamedPipe(std::wstring pipe_name, DWORD desired_access, DWORD impersonation_level)
|
|
{
|
|
|
|
UNICODE_STRING pipe;
|
|
OBJECT_ATTRIBUTES objattr;
|
|
HANDLE ret;
|
|
IO_STATUS_BLOCK io;
|
|
_RtlInitUnicodeString(&pipe, pipe_name.c_str());
|
|
InitializeObjectAttributes(&objattr, &pipe, OBJ_CASE_INSENSITIVE, nullptr, nullptr);
|
|
DWORD dwattr = FILE_ATTRIBUTE_NORMAL | SECURITY_SQOS_PRESENT | impersonation_level;
|
|
NTSTATUS status = _NtCreateFile(&ret, desired_access, &objattr, &io, NULL, dwattr, ALL_SHARING,
|
|
FILE_OPEN, NULL, NULL, NULL);
|
|
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return NULL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
HANDLE OpsMaster::OpenNamedPipe(std::string pipe_name, DWORD desired_access, DWORD impersonation_level)
|
|
{
|
|
return OpsMaster::OpenNamedPipe(std::wstring(pipe_name.begin(), pipe_name.end()),
|
|
desired_access, impersonation_level);
|
|
}
|
|
|
|
bool OpsMaster::CreateNativeHardLink(HANDLE hfile, std::wstring target)
|
|
{
|
|
target = BuildNativePath(target);
|
|
IO_STATUS_BLOCK io;
|
|
|
|
FILE_LINK_INFORMATION* link_inf = (FILE_LINK_INFORMATION*)_malloca(sizeof(FILE_LINK_INFORMATION) + (target.size() * sizeof(WCHAR)));
|
|
|
|
memset(link_inf, 0, sizeof(FILE_LINK_INFORMATION) + (target.size() * sizeof(WCHAR)));
|
|
|
|
link_inf->FileNameLength = target.size() * sizeof(WCHAR);
|
|
link_inf->ReplaceIfExists = TRUE;
|
|
link_inf->RootDirectory = NULL;
|
|
memcpy(&link_inf->FileName[0], target.c_str(), target.size() * sizeof(WCHAR));
|
|
|
|
NTSTATUS status = _NtSetInformationFile(hfile, &io, link_inf, sizeof(FILE_LINK_INFORMATION) + (target.size() * sizeof(WCHAR)), FileLinkInformation);
|
|
free(link_inf);
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool OpsMaster::CreateNativeHardLink(HANDLE hfile, std::string target)
|
|
{
|
|
return OpsMaster::CreateNativeHardLink(hfile, std::wstring(target.begin(), target.end()));
|
|
}
|
|
|
|
bool OpsMaster::CreateNativeHardLink(std::wstring link, std::wstring target)
|
|
{
|
|
|
|
// Before windows hardlink mitigation, only GENERIC_READ is required to create the hardlink
|
|
// but since the mitigation, WRITE_ATTRIBUTES is now required to create a hardlink
|
|
// the best solution for me here is to open the file with MAXIMUM_ALLOWED
|
|
HANDLE hf = OpsMaster::OpenFileNative(link);
|
|
bool ret = OpsMaster::CreateNativeHardLink(hf, target);
|
|
_NtClose(hf);
|
|
return ret;
|
|
}
|
|
|
|
bool OpsMaster::CreateNativeHardLink(std::string link, std::string target)
|
|
{
|
|
// Before windows hardlink mitigation, only GENERIC_READ is required to create the hardlink
|
|
// but since the mitigation, WRITE_ATTRIBUTES is now required to create a hardlink
|
|
// the best solution for me here is to open the file with MAXIMUM_ALLOWED
|
|
HANDLE hf = OpsMaster::OpenFileNative(link);
|
|
bool ret = OpsMaster::CreateNativeHardLink(hf, target);
|
|
_NtClose(hf);
|
|
return ret;
|
|
}
|
|
|
|
bool OpsMaster::CreateMountPoint(HANDLE hdir, std::wstring target, std::wstring printname)
|
|
{
|
|
|
|
target = BuildNativePath(target);
|
|
size_t targetsz = target.size() * 2;
|
|
size_t printnamesz = printname.size() * 2;
|
|
size_t pathbuffersz = targetsz + printnamesz + 12;
|
|
size_t totalsz = pathbuffersz + REPARSE_DATA_BUFFER_HEADER_LENGTH;
|
|
REPARSE_DATA_BUFFER* rdb = (REPARSE_DATA_BUFFER*)HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, totalsz);
|
|
//memset(rdb, 0, totalsz);
|
|
rdb->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
|
|
rdb->ReparseDataLength = static_cast<USHORT>(pathbuffersz);
|
|
rdb->Reserved = NULL;
|
|
rdb->MountPointReparseBuffer.SubstituteNameOffset = NULL;
|
|
rdb->MountPointReparseBuffer.SubstituteNameLength = static_cast<USHORT>(targetsz);
|
|
memcpy(rdb->MountPointReparseBuffer.PathBuffer, target.c_str(), targetsz + 2);
|
|
rdb->MountPointReparseBuffer.PrintNameOffset = static_cast<USHORT>(targetsz + 2);
|
|
rdb->MountPointReparseBuffer.PrintNameLength = static_cast<USHORT>(printnamesz);
|
|
memcpy(rdb->MountPointReparseBuffer.PathBuffer + target.size() + 1, printname.c_str(), printnamesz + 2);
|
|
DWORD cb = 0;
|
|
OVERLAPPED ov = { 0 };
|
|
HANDLE hevent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
ov.hEvent = hevent;
|
|
bool ret = false;
|
|
DeviceIoControl(hdir, FSCTL_SET_REPARSE_POINT, rdb, totalsz, NULL, NULL, NULL, &ov);
|
|
if (GetLastError() == ERROR_SUCCESS)
|
|
ret = true;
|
|
if (GetLastError() == ERROR_IO_PENDING) {
|
|
GetOverlappedResult(hdir, &ov, &cb, TRUE);
|
|
if (ov.Internal == STATUS_SUCCESS)
|
|
ret = true;
|
|
else
|
|
SetLastErr(_RtlNtStatusToDosError(ov.Internal));
|
|
}
|
|
_NtClose(hevent);
|
|
HeapFree(GetProcessHeap(), NULL, rdb);
|
|
return ret;
|
|
}
|
|
|
|
bool OpsMaster::CreateMountPoint(HANDLE hdir, std::string target, std::string printname)
|
|
{
|
|
return OpsMaster::CreateMountPoint(hdir, std::wstring(target.begin(), target.end()),
|
|
std::wstring(printname.begin(), printname.end()));
|
|
}
|
|
|
|
bool OpsMaster::CreateMountPoint(std::wstring dir, std::wstring target, std::wstring printname)
|
|
{
|
|
|
|
HANDLE hdir = OpenDirectory(dir, FILE_WRITE_DATA, ALL_SHARING, OPEN_ALWAYS);
|
|
bool ret = CreateMountPoint(hdir, target, printname);
|
|
_NtClose(hdir);
|
|
return ret;
|
|
}
|
|
|
|
bool OpsMaster::CreateMountPoint(std::string dir, std::string target, std::string printname)
|
|
{
|
|
return OpsMaster::CreateMountPoint(std::wstring(dir.begin(), dir.end()),
|
|
std::wstring(target.begin(), target.end()), std::wstring(printname.begin(), printname.end()));
|
|
}
|
|
|
|
bool OpsMaster::DeleteMountPoint(HANDLE hdir)
|
|
{
|
|
REPARSE_GUID_DATA_BUFFER rp_buffer = { 0 };
|
|
rp_buffer.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
|
|
DWORD cb = 0;
|
|
OVERLAPPED ov = { 0 };
|
|
HANDLE hevent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
ov.hEvent = hevent;
|
|
bool ret = false;
|
|
DeviceIoControl(hdir, FSCTL_DELETE_REPARSE_POINT, &rp_buffer, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE,
|
|
nullptr, NULL, &cb, &ov);
|
|
if (GetLastError() == ERROR_SUCCESS)
|
|
ret = true;
|
|
if (GetLastError() == ERROR_IO_PENDING) {
|
|
GetOverlappedResult(hdir, &ov, &cb, TRUE);
|
|
if (ov.Internal == STATUS_SUCCESS)
|
|
ret = true;
|
|
else
|
|
SetLastErr(_RtlNtStatusToDosError(ov.Internal));
|
|
}
|
|
_NtClose(hevent);
|
|
return ret;
|
|
}
|
|
|
|
bool OpsMaster::DeleteMountPoint(std::wstring dir)
|
|
{
|
|
HANDLE hdir = OpenDirectory(dir, FILE_WRITE_DATA, ALL_SHARING, OPEN_EXISTING);
|
|
bool rt = OpsMaster::DeleteMountPoint(hdir);
|
|
_NtClose(hdir);
|
|
return rt;
|
|
}
|
|
|
|
bool OpsMaster::DeleteMountPoint(std::string dir)
|
|
{
|
|
HANDLE hdir = OpenDirectory(dir, FILE_WRITE_DATA, ALL_SHARING, OPEN_EXISTING);
|
|
bool rt = OpsMaster::DeleteMountPoint(hdir);
|
|
_NtClose(hdir);
|
|
return rt;
|
|
}
|
|
|
|
std::wstring OpsMaster::GetMountPointData(HANDLE hdir, std::wstring)
|
|
{
|
|
REPARSE_DATA_BUFFER* rdb = (REPARSE_DATA_BUFFER*)_malloca(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
|
|
|
|
DWORD rd = 0;
|
|
|
|
if (!DeviceIoControl(hdir, FSCTL_GET_REPARSE_POINT, NULL,
|
|
NULL, rdb, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &rd, nullptr))
|
|
return L"";
|
|
WCHAR* bs = &rdb->MountPointReparseBuffer.PathBuffer[rdb->MountPointReparseBuffer.SubstituteNameOffset / 2];
|
|
std::wstring ret = std::wstring(bs, bs + (rdb->MountPointReparseBuffer.SubstituteNameLength / 2));
|
|
free(rdb);
|
|
return ret;
|
|
}
|
|
|
|
std::string OpsMaster::GetMountPointData(HANDLE hdir, std::string)
|
|
{
|
|
std::wstring rt = OpsMaster::GetMountPointData(hdir, L"");
|
|
return std::string(rt.begin(), rt.end());
|
|
}
|
|
|
|
std::wstring OpsMaster::GetMountPointData(std::wstring dir)
|
|
{
|
|
HANDLE hdir = OpsMaster::OpenDirectory(dir, GENERIC_READ, ALL_SHARING, OPEN_EXISTING);
|
|
std::wstring ret = OpsMaster::GetMountPointData(hdir, L"");
|
|
_NtClose(hdir);
|
|
return ret;
|
|
}
|
|
|
|
std::string OpsMaster::GetMountPointData(std::string dir)
|
|
{
|
|
HANDLE hdir = OpsMaster::OpenDirectory(dir, GENERIC_READ, ALL_SHARING, OPEN_EXISTING);
|
|
std::string ret = OpsMaster::GetMountPointData(hdir, "");
|
|
_NtClose(hdir);
|
|
return ret;
|
|
}
|
|
|
|
HANDLE OpsMaster::CreateObjDir(std::wstring dir)
|
|
{
|
|
HANDLE rt = NULL;
|
|
OBJECT_ATTRIBUTES objattr;
|
|
UNICODE_STRING target;
|
|
_RtlInitUnicodeString(&target, dir.c_str());
|
|
InitializeObjectAttributes(&objattr, &target, OBJ_CASE_INSENSITIVE, nullptr, nullptr);
|
|
|
|
NTSTATUS status = _NtCreateDirectoryObjectEx(&rt, MAXIMUM_ALLOWED, &objattr, nullptr, FALSE);
|
|
|
|
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return NULL;
|
|
}
|
|
return rt;
|
|
}
|
|
|
|
HANDLE OpsMaster::CreateObjDir(std::string dir)
|
|
{
|
|
return OpsMaster::CreateObjDir(std::wstring(dir.begin(), dir.end()));
|
|
}
|
|
|
|
HANDLE OpsMaster::OpenObjDir(std::wstring dir)
|
|
{
|
|
OBJECT_ATTRIBUTES objattr;
|
|
HANDLE ret;
|
|
UNICODE_STRING udir;
|
|
_RtlInitUnicodeString(&udir, dir.c_str());
|
|
InitializeObjectAttributes(&objattr, &udir, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|
NTSTATUS status = _NtOpenDirectoryObject(&ret, MAXIMUM_ALLOWED, &objattr);
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return NULL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
HANDLE OpsMaster::OpenObjDir(std::string dir)
|
|
{
|
|
return OpsMaster::OpenObjDir(std::wstring(dir.begin(), dir.end()));
|
|
}
|
|
|
|
bool OpsMaster::MakePermanentObj(HANDLE hobj)
|
|
{
|
|
NTSTATUS status = _ZwMakePermanentObject(hobj);
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool OpsMaster::CreateAndWaitLock(std::wstring file, _UserCallback cb, bool IsDirectory)
|
|
{
|
|
HANDLE h;
|
|
if (IsDirectory)
|
|
h = OpenDirectory(file);
|
|
|
|
else
|
|
h = OpenFileNative(file);
|
|
if (h == INVALID_HANDLE_VALUE)
|
|
return false;
|
|
lock_ptr lk = FileOpLock::CreateLock(h, cb);
|
|
if (lk != nullptr) { lk->WaitForLock(INFINITE); }
|
|
else {
|
|
_NtClose(h);
|
|
delete lk;
|
|
return false;
|
|
}
|
|
_NtClose(h);
|
|
delete lk;
|
|
return true;
|
|
}
|
|
|
|
bool OpsMaster::CreateAndWaitLock(std::string file, _UserCallback cb, bool IsDirectory)
|
|
{
|
|
return OpsMaster::CreateAndWaitLock(std::wstring(file.begin(), file.end()), cb, IsDirectory);
|
|
}
|
|
|
|
bool OpsMaster::CreateAndWaitLock(HANDLE h, _UserCallback cb)
|
|
{
|
|
FileOpLock* lk = FileOpLock::CreateLock(h, cb);
|
|
if (lk != nullptr) {
|
|
lk->WaitForLock(INFINITE);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
lock_ptr OpsMaster::CreateLock(HANDLE h, _UserCallback cb)
|
|
{
|
|
lock_ptr lk = FileOpLock::CreateLock(h, cb);
|
|
return lk;
|
|
}
|
|
|
|
lock_ptr OpsMaster::CreateLock(std::wstring file, _UserCallback cb, bool IsDirectory)
|
|
{
|
|
HANDLE g;
|
|
if (IsDirectory)
|
|
g = OpsMaster::OpenDirectory(file);
|
|
else
|
|
g = OpsMaster::OpenFileNative(file);
|
|
return OpsMaster::CreateLock(g, cb);
|
|
}
|
|
|
|
lock_ptr OpsMaster::CreateLock(std::string file, _UserCallback cb, bool IsDirectory)
|
|
{
|
|
return OpsMaster::CreateLock(std::wstring(file.begin(), file.end()), cb, IsDirectory);
|
|
}
|
|
|
|
bool OpsMaster::MoveFileToTempDir(HANDLE h, DWORD temp_location, std::wstring loc)
|
|
{
|
|
|
|
std::wstring randomstr = this->GenerateRandomStr();
|
|
std::wstring path_to_move;
|
|
WCHAR temp_path[MAX_PATH];
|
|
switch (temp_location) {
|
|
case USE_USER_TEMP_DIR:
|
|
ExpandEnvironmentStringsW(L"%TEMP%", temp_path, MAX_PATH);
|
|
path_to_move = temp_path + std::wstring(L"\\") + randomstr;
|
|
return MoveByHandle(h, path_to_move);
|
|
break;
|
|
case USE_SYSTEM_TEMP_DIR:
|
|
GetWindowsDirectoryW(temp_path, MAX_PATH);
|
|
path_to_move = temp_path + std::wstring(L"\\Temp\\") + randomstr;
|
|
return MoveByHandle(h, path_to_move);
|
|
break;
|
|
case USE_CUSTOM_TEMP_DIR:
|
|
path_to_move = loc + std::wstring(L"\\") + randomstr;
|
|
return MoveByHandle(h, path_to_move);
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool OpsMaster::MoveFileToTempDir(std::wstring file, bool IsDirectory, DWORD temp_location, std::wstring loc)
|
|
{
|
|
HANDLE g;
|
|
if (IsDirectory)
|
|
g = OpsMaster::OpenDirectory(file, DELETE, ALL_SHARING, OPEN_EXISTING);
|
|
else
|
|
g = OpsMaster::OpenFileNative(file, DELETE, ALL_SHARING, OPEN_EXISTING);
|
|
return OpsMaster::MoveFileToTempDir(g, temp_location, L"");
|
|
}
|
|
|
|
bool OpsMaster::MoveFileToTempDir(std::string file, bool IsDirectory, DWORD temp_location, std::string loc)
|
|
{
|
|
return OpsMaster::MoveFileToTempDir(std::wstring(file.begin(), file.end()), IsDirectory, temp_location,
|
|
std::wstring(loc.begin(), loc.end()));
|
|
}
|
|
|
|
bool OpsMaster::DeleteChild(HANDLE root, std::wstring child)
|
|
{
|
|
OBJECT_ATTRIBUTES objattr;
|
|
UNICODE_STRING _child;
|
|
_RtlInitUnicodeString(&_child, child.c_str());
|
|
InitializeObjectAttributes
|
|
(
|
|
&objattr,//object attributes pointer
|
|
&_child,//object name in this case the file to be deleted
|
|
OBJ_CASE_INSENSITIVE,//object attributes
|
|
root,//root directory HANDLE
|
|
NULL//security descriptor must be null
|
|
);
|
|
NTSTATUS status = _ZwDeleteFile(&objattr);
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool OpsMaster::DeleteFileNative(std::wstring full_path) {
|
|
full_path = BuildNativePath(full_path);
|
|
OBJECT_ATTRIBUTES objattr;
|
|
UNICODE_STRING _full_path;
|
|
_RtlInitUnicodeString(&_full_path, full_path.c_str());
|
|
InitializeObjectAttributes
|
|
(
|
|
&objattr,
|
|
&_full_path,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
NTSTATUS status = _ZwDeleteFile(&objattr);
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool OpsMaster::DeleteFileNative(std::string full_path) {
|
|
return OpsMaster::DeleteFileNative(std::wstring(full_path.begin(), full_path.end()));
|
|
}
|
|
|
|
bool OpsMaster::RRemoveDirectory(std::wstring dir)
|
|
{
|
|
//this code isn't designed to handle symbolic link, only junctions
|
|
DWORD fst_attr = GetFileAttributesW(dir.c_str());
|
|
if (fst_attr & FILE_ATTRIBUTE_NORMAL)
|
|
return OpsMaster::DeleteFileNative(dir);
|
|
if (fst_attr & FILE_ATTRIBUTE_REPARSE_POINT)
|
|
return RemoveDirectoryW(dir.c_str());
|
|
std::wstring search_path = std::wstring(dir) + L"\\*.*";
|
|
std::wstring s_p = std::wstring(dir) + std::wstring(L"\\");
|
|
WIN32_FIND_DATAW fd;
|
|
HANDLE hFind = FindFirstFileW(search_path.c_str(), &fd);
|
|
if (hFind != INVALID_HANDLE_VALUE) {
|
|
do {
|
|
if (wcscmp(fd.cFileName, L".") == 0 || wcscmp(fd.cFileName, L"..") == 0)
|
|
{
|
|
continue;
|
|
}
|
|
if (fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
|
|
RemoveDirectoryW(std::wstring(s_p + fd.cFileName).c_str());
|
|
continue;
|
|
}
|
|
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
|
OpsMaster::DeleteFileNative(std::wstring(s_p + fd.cFileName));
|
|
continue;
|
|
}
|
|
if (wcscmp(fd.cFileName, L".") != 0 && wcscmp(fd.cFileName, L"..") != 0)
|
|
{
|
|
OpsMaster::RRemoveDirectory(s_p + fd.cFileName);
|
|
}
|
|
} while (FindNextFileW(hFind, &fd));
|
|
FindClose(hFind);
|
|
}
|
|
if (RemoveDirectoryW(dir.c_str()) != 0) {
|
|
SetLastErr(GetLastErr());
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
bool OpsMaster::RRemoveDirectory(std::string dir)
|
|
{
|
|
return OpsMaster::RRemoveDirectory(std::wstring(dir.begin(), dir.end()));
|
|
}
|
|
|
|
bool OpsMaster::DeleteByHandle(HANDLE hfile)
|
|
{
|
|
FILE_DISPOSITION_INFORMATION_EX dispositioninfo = { 0 };
|
|
dispositioninfo.Flags = FILE_DISPOSITION_DELETE | FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE | FILE_DISPOSITION_POSIX_SEMANTICS;
|
|
IO_STATUS_BLOCK io;
|
|
NTSTATUS status = _NtSetInformationFile(hfile, &io, &dispositioninfo, sizeof(FILE_DISPOSITION_INFORMATION_EX), FileDispositionInformationEx);
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
std::wstring OpsMaster::GenerateRandomStr()
|
|
{
|
|
GUID gg;
|
|
HRESULT hs = CoCreateGuid(&gg);
|
|
WCHAR mx[MAX_PATH];
|
|
int x = StringFromGUID2(gg, mx, MAX_PATH);
|
|
return mx;
|
|
}
|
|
|
|
|
|
|
|
|
|
OpsMaster::FileOpLock::FileOpLock(UserCallback cb) :
|
|
g_inputBuffer({ 0 }), g_outputBuffer({ 0 }), g_o({ 0 }), g_hFile(INVALID_HANDLE_VALUE), g_hLockCompleted(nullptr), g_wait(nullptr), _cb(cb)
|
|
{
|
|
g_inputBuffer.StructureVersion = REQUEST_OPLOCK_CURRENT_VERSION;
|
|
g_inputBuffer.StructureLength = sizeof(g_inputBuffer);
|
|
g_inputBuffer.RequestedOplockLevel = OPLOCK_LEVEL_CACHE_READ | OPLOCK_LEVEL_CACHE_HANDLE;
|
|
g_inputBuffer.Flags = REQUEST_OPLOCK_INPUT_FLAG_REQUEST;
|
|
g_outputBuffer.StructureVersion = REQUEST_OPLOCK_CURRENT_VERSION;
|
|
g_outputBuffer.StructureLength = sizeof(g_outputBuffer);
|
|
}
|
|
|
|
|
|
OpsMaster::FileOpLock::~FileOpLock()
|
|
{
|
|
if (g_wait)
|
|
{
|
|
SetThreadpoolWait(g_wait, nullptr, nullptr);
|
|
CloseThreadpoolWait(g_wait);
|
|
g_wait = nullptr;
|
|
}
|
|
|
|
if (g_o.hEvent)
|
|
{
|
|
CloseHandle(g_o.hEvent);
|
|
g_o.hEvent = nullptr;
|
|
}
|
|
|
|
if (g_hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(g_hFile);
|
|
g_hFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
bool OpsMaster::FileOpLock::BeginLock(HANDLE h)
|
|
{
|
|
g_hLockCompleted = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
|
g_o.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
|
|
|
g_hFile = h;
|
|
g_wait = CreateThreadpoolWait(WaitCallback, this, nullptr);
|
|
if (g_wait == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
SetThreadpoolWait(g_wait, g_o.hEvent, nullptr);
|
|
|
|
DeviceIoControl(g_hFile, FSCTL_REQUEST_OPLOCK,
|
|
&g_inputBuffer, sizeof(g_inputBuffer),
|
|
&g_outputBuffer, sizeof(g_outputBuffer),
|
|
nullptr, &g_o);
|
|
|
|
SetLastErr(GetLastError());
|
|
if (GetLastError() != ERROR_IO_PENDING) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
OpsMaster::FileOpLock* OpsMaster::FileOpLock::CreateLock(HANDLE h, OpsMaster::FileOpLock::UserCallback cb)
|
|
{
|
|
OpsMaster::FileOpLock* ret = new OpsMaster::FileOpLock(cb);
|
|
if (ret->BeginLock(h))
|
|
{
|
|
return ret;
|
|
}
|
|
else
|
|
{
|
|
delete ret;
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
void OpsMaster::FileOpLock::WaitForLock(UINT Timeout)
|
|
{
|
|
WaitForSingleObject(g_hLockCompleted, Timeout);
|
|
}
|
|
|
|
void OpsMaster::FileOpLock::WaitCallback(PTP_CALLBACK_INSTANCE Instance,
|
|
PVOID Parameter, PTP_WAIT Wait,
|
|
TP_WAIT_RESULT WaitResult)
|
|
{
|
|
UNREFERENCED_PARAMETER(Instance);
|
|
UNREFERENCED_PARAMETER(Wait);
|
|
UNREFERENCED_PARAMETER(WaitResult);
|
|
|
|
OpsMaster::FileOpLock* lock = reinterpret_cast<FileOpLock*>(Parameter);
|
|
|
|
lock->DoWaitCallback();
|
|
}
|
|
|
|
void OpsMaster::FileOpLock::DoWaitCallback()
|
|
{
|
|
DWORD dwBytes;
|
|
if (!GetOverlappedResult(g_hFile, &g_o, &dwBytes, TRUE)) {
|
|
}
|
|
|
|
if (_cb)
|
|
{
|
|
_cb();
|
|
}
|
|
|
|
CloseHandle(g_hFile);
|
|
g_hFile = INVALID_HANDLE_VALUE;
|
|
SetEvent(g_hLockCompleted);
|
|
}
|
|
|
|
std::wstring OpsMaster::GetUserSid(HANDLE htoken) {
|
|
|
|
//I'm gonna change this later, but too lazy to actually do it. I guess I'll stick with this for a while
|
|
//It does work so there will be a quite long time before I touch this again
|
|
DWORD dwSize;
|
|
|
|
GetTokenInformation(htoken, TokenUser, nullptr, 0, &dwSize);
|
|
|
|
std::vector<BYTE> userbuffer(dwSize);
|
|
|
|
GetTokenInformation(htoken, TokenUser, &userbuffer[0], dwSize, &dwSize);
|
|
|
|
PTOKEN_USER user = reinterpret_cast<PTOKEN_USER>(&userbuffer[0]);
|
|
|
|
LPWSTR lpUser;
|
|
std::wstring ret = L"";
|
|
|
|
if (ConvertSidToStringSidW(user->User.Sid, &lpUser))
|
|
{
|
|
ret = lpUser;
|
|
LocalFree(lpUser);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
HANDLE OpsMaster::GetAnonymousToken()
|
|
{
|
|
HANDLE htoken = NULL;
|
|
HANDLE hret = NULL;
|
|
ImpersonateAnonymousToken(GetCurrentThread());
|
|
OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &htoken);
|
|
//just in case
|
|
DuplicateHandle(GetCurrentProcess(), htoken, GetCurrentProcess(),
|
|
&hret, TOKEN_ALL_ACCESS, FALSE, DUPLICATE_CLOSE_SOURCE);
|
|
return hret;
|
|
}
|
|
|
|
bool OpsMaster::MakeTemporaryObj(HANDLE hobj)
|
|
{
|
|
NTSTATUS status = _ZwMakeTemporaryObject(hobj);
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
std::wstring OpsMaster::GetCurrentExeDir()
|
|
{
|
|
WCHAR mx[MAX_PATH];
|
|
GetModuleFileNameW(GetModuleHandle(NULL), mx, MAX_PATH);
|
|
std::wstring ret = mx;
|
|
for (int i = ret.size(); i > 0; i--) {
|
|
if (ret[i] != L'\\') {
|
|
continue;
|
|
}
|
|
ret.erase(i, ret.size());
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
std::wstring OpsMaster::GetCurrentExeDirWithFileAppended(std::wstring file)
|
|
{
|
|
|
|
return OpsMaster::GetCurrentExeDir() + L"\\" + file;
|
|
}
|
|
|
|
std::wstring OpsMaster::RegPathToNative(LPCWSTR lpPath)
|
|
{
|
|
std::wstring regpath = L"\\REGISTRY\\";
|
|
|
|
// Already native rooted
|
|
if (lpPath[0] == '\\')
|
|
{
|
|
return lpPath;
|
|
}
|
|
|
|
if (_wcsnicmp(lpPath, L"HKLM\\", 5) == 0)
|
|
{
|
|
return regpath + L"MACHINE\\" + &lpPath[5];
|
|
}
|
|
else if (_wcsnicmp(lpPath, L"HKEY_LOCAL_MACHINE\\", 19) == 0) {
|
|
return regpath + L"MACHINE\\" + &lpPath[19];
|
|
}
|
|
else if (_wcsnicmp(lpPath, L"HKU\\", 4) == 0)
|
|
{
|
|
return regpath + L"USER\\" + &lpPath[4];
|
|
}
|
|
else if (_wcsnicmp(lpPath, L"HKEY_USERS\\", 11) == 0)
|
|
{
|
|
return regpath + L"USER\\" + &lpPath[11];
|
|
}
|
|
else if (_wcsnicmp(lpPath, L"HKCU\\", 5) == 0)
|
|
{
|
|
std::wstring ret = regpath + L"USER\\" + GetUserSid().c_str() + L"\\" + &lpPath[5];
|
|
return ret;
|
|
}
|
|
else if (_wcsnicmp(lpPath, L"HKEY_CURRENT_USER\\", 18) == 0)
|
|
{
|
|
std::wstring ret = regpath + L"USER\\" + GetUserSid().c_str() + L"\\" + &lpPath[18];
|
|
return ret;
|
|
}
|
|
else
|
|
{
|
|
//error
|
|
return L"";
|
|
}
|
|
}
|
|
|
|
HANDLE OpsMaster::RegCreateKeyNative(std::wstring target, DWORD desired_access, bool OpenLink, bool CreateLink)
|
|
{
|
|
HANDLE hret = NULL;
|
|
UNICODE_STRING _target;
|
|
target = RegPathToNative(target.c_str());
|
|
_RtlInitUnicodeString(&_target, target.c_str());
|
|
DWORD _objflag = OBJ_CASE_INSENSITIVE | (OpenLink ? OBJ_OPENLINK : NULL);
|
|
OBJECT_ATTRIBUTES objattr;
|
|
InitializeObjectAttributes(&objattr, &_target, _objflag, NULL, NULL);
|
|
NTSTATUS status = _ZwCreateKey(&hret, desired_access,
|
|
&objattr, NULL, NULL,
|
|
(CreateLink ? INTERNAL_REG_OPTION_CREATE_LINK : NULL) | REG_OPTION_NON_VOLATILE, NULL);
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
}
|
|
return hret;
|
|
}
|
|
|
|
HANDLE OpsMaster::RegCreateKeyNative(std::string target, DWORD desired_access, bool OpenLink, bool CreateLink) {
|
|
return OpsMaster::RegCreateKeyNative(
|
|
std::wstring(target.begin(), target.end()),
|
|
desired_access, OpenLink, CreateLink
|
|
);
|
|
}
|
|
|
|
bool OpsMaster::RegDeleteKeyNative(HANDLE hkey) {
|
|
|
|
NTSTATUS status = _ZwDeleteKey(hkey);
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool OpsMaster::RegDeleteKeyNative(std::wstring target) {
|
|
HANDLE hk = OpsMaster::RegCreateKeyNative(target, DELETE, true);
|
|
bool ret = OpsMaster::RegDeleteKeyNative(hk);
|
|
_NtClose(hk);
|
|
return ret;
|
|
}
|
|
|
|
bool OpsMaster::RegDeleteKeyNative(std::string target) {
|
|
return OpsMaster::RegDeleteKeyNative(std::wstring(target.begin(), target.end()));
|
|
}
|
|
|
|
bool OpsMaster::RegCreateNativeLink(HANDLE hkey, std::wstring target) {
|
|
|
|
UNICODE_STRING value;
|
|
target = RegPathToNative(target.c_str());
|
|
_RtlInitUnicodeString(&value, L"SymbolicLinkValue");
|
|
|
|
NTSTATUS status = _ZwSetValueKey(hkey, &value, NULL, REG_LINK,
|
|
(PVOID)target.c_str(), target.length() * sizeof(WCHAR));
|
|
if (status != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(status));
|
|
return false;
|
|
}
|
|
return true;
|
|
|
|
}
|
|
bool OpsMaster::RegCreateNativeLink(HANDLE hkey, std::string target) {
|
|
return OpsMaster::RegCreateNativeLink(hkey, std::wstring(target.begin(), target.end()));
|
|
}
|
|
bool OpsMaster::RegCreateNativeLink(std::wstring link, std::wstring target) {
|
|
HANDLE hk = OpsMaster::RegCreateKeyNative(link, KEY_CREATE_LINK | KEY_WRITE, true, true);
|
|
if (!hk) {
|
|
return false;
|
|
}
|
|
bool ret = OpsMaster::RegCreateNativeLink(hk, target);
|
|
_NtClose(hk);
|
|
return ret;
|
|
}
|
|
bool OpsMaster::RegCreateNativeLink(std::string link, std::string target) {
|
|
std::wstring lnk = std::wstring(link.begin(), link.end());
|
|
std::wstring _target = std::wstring(target.begin(), target.end());
|
|
return OpsMaster::RegCreateNativeLink(lnk,
|
|
_target);
|
|
}
|
|
|
|
bool OpsMaster::SetShortFileNameNative(HANDLE hfile, std::wstring short_name) {
|
|
|
|
size_t fni_sz = sizeof(FILE_NAME_INFORMATION) + (short_name.size() * sizeof(WCHAR));
|
|
FILE_NAME_INFORMATION* fni = (FILE_NAME_INFORMATION*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, fni_sz);
|
|
fni->FileNameLength = short_name.size() * sizeof(WCHAR);
|
|
memcpy(&fni->FileName[0], short_name.c_str(), fni->FileNameLength);
|
|
IO_STATUS_BLOCK io_status = { 0 };
|
|
NTSTATUS stat = _NtSetInformationFile(hfile, &io_status, fni, fni_sz, FileShortNameInformation);
|
|
HeapFree(GetProcessHeap(), NULL, fni);
|
|
if (stat != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(stat));
|
|
return false;
|
|
}
|
|
return true;
|
|
|
|
}
|
|
|
|
bool OpsMaster::SetCaseSensitiveDirectory(HANDLE hf, bool enable) {
|
|
;
|
|
FILE_CASE_SENSITIVE_INFORMATION fcsi = { FILE_CS_FLAG_CASE_SENSITIVE_DIR };
|
|
IO_STATUS_BLOCK io = { 0 };
|
|
NTSTATUS stat = _NtSetInformationFile(hf, &io, &fcsi, sizeof(fcsi), FileCaseSensitiveInformation);
|
|
if (stat != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(stat));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
HANDLE OpsMaster::OpenObjLink(std::wstring link,DWORD desired_access) {
|
|
|
|
UNICODE_STRING lnk;
|
|
_RtlInitUnicodeString(&lnk, link.c_str());
|
|
OBJECT_ATTRIBUTES objattr;
|
|
InitializeObjectAttributes(&objattr, &lnk, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|
|
|
HANDLE hd = NULL;
|
|
NTSTATUS stat = _NtOpenSymbolicLinkObject(&hd, desired_access, &objattr);
|
|
if (stat != STATUS_SUCCESS) {
|
|
SetLastErr(_RtlNtStatusToDosError(stat));
|
|
return NULL;
|
|
}
|
|
return hd;
|
|
}
|
|
//not tested yet
|
|
*/ |