/** * @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__