C++ Win32 API Check Encryption Bitlocker FDE

Hello,

I'm trying to run the below script, but it's failing. The end goal here is to tap into the Win32 API to see the shell values for System.Volume.BitLockerProtection as i need to be able to check on BitLocker status without elevation.

It's present in the Windows interface to any user, so i'm sure there must be a way that doesn't require admin rights.

I tried the following, but it's telling me '

 
[Error] redeclaration of 'Unknown'


I'd appreciate any pointers to help me on my way, unless anyone has any better ideas?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <shlobj.h>
#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "propsys.lib")
using namespace std;

enum DriveEncryptionStatus{
    Unprotected,
    Protected,
    Unknown
};




DriveEncryptionStatus getDriveEncryptionStatus(LPCWSTR parsingName)
{
    IShellItem2 *drive = NULL;
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
    hr = SHCreateItemFromParsingName(parsingName, NULL, IID_PPV_ARGS(&drive));
    if (SUCCEEDED(hr)) {
        PROPERTYKEY pKey;
        hr = PSGetPropertyKeyFromName(L"System.Volume.BitLockerProtection", &pKey);
        if (SUCCEEDED(hr)) {
            PROPVARIANT prop;
            PropVariantInit(&prop);
            hr = drive->GetProperty(pKey, &prop);
            if (SUCCEEDED(hr)) {
                int status = prop.intVal;

                drive->Release();

                if (status == 1 || status == 3 || status == 5)
                    return DriveEncryptionStatus::Protected;
                else
                    return DriveEncryptionStatus::Unprotected;
            }
        }
    }

    if (drive)
        drive->Release();

    return DriveEncryptionStatus::Unknown;
}

int main()
{
    DriveEncryptionStatus status = getDriveEncryptionStatus(L"C:");
    return 0;
}
Last edited on
Your DriveEncryptionStatus should look like this:
1
2
3
4
5
enum class DriveEncryptionStatus {
  Unprotected,
  Protected,
  Unknown
};

Then it compiles and runs.
Thanks for the hint, what IDE are you using? I've made the change, switched my profile to c++ 11 and still get an error, showing that

1
2
3
4
In function `getDriveEncryptionStatus(wchar_t const*)':
undefined reference to `__imp_SHCreateItemFromParsingName'
undefined reference to `__imp_PSGetPropertyKeyFromName'
[Error] ld returned 1 exit status 


It seems odd that all is OK on your side. I tried adding -lkernel32 -lole32 to my compiler options, however that also seemed to fail.

Here is the latest version of the code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <shlobj.h>
#include <shobjidl_core.h>
#include<stdlib.h>
#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "propsys.lib")
using namespace std;

enum class DriveEncryptionStatus{
    Unprotected,
    Protected,
    Unknown
};




DriveEncryptionStatus getDriveEncryptionStatus(LPCWSTR ParsingName)
{
    IShellItem2 *drive = NULL;
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
    hr = SHCreateItemFromParsingName(ParsingName, NULL, IID_PPV_ARGS(&drive));
    if (SUCCEEDED(hr)) {
        PROPERTYKEY pKey;
        hr = PSGetPropertyKeyFromName(L"System.Volume.BitLockerProtection", &pKey);
        if (SUCCEEDED(hr)) {
            PROPVARIANT prop;
            PropVariantInit(&prop);
            hr = drive->GetProperty(pKey, &prop);
            if (SUCCEEDED(hr)) {
                int status = prop.intVal;

                drive->Release();

                if (status == 1 || status == 3 || status == 5)
                    return DriveEncryptionStatus::Protected;
                else
                    return DriveEncryptionStatus::Unprotected;
            }
        }
    }

    if (drive)
        drive->Release();

    return DriveEncryptionStatus::Unknown;
}

int main()
{
    DriveEncryptionStatus status = getDriveEncryptionStatus(L"C:");
    return 0;
}
I am using VS 2017 CE.
By default it adds kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;
shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib
You asked what IDE/compiler Thomas was using, but you didn't say which compiler you were using. Since this is Windows code, I assume you're using some variant of MinGW, but can you say specifically what build/version?

Your library #pragma comments might only be supported in Visual Studio, not MinGW, although I'm not completely sure.
Last edited on
Yes, apologies.

Thanks for the help Thomas, I'm up to speed now somewhat and able to compile.
I'm using Visual Studio Microsoft Visual C++ 2019.

It returns OK with an exit code 0, however this is where i risk sounding like a complete fool.... How do i now show the value from my main()?

I tried to cout the status, and DriveEncryptionStatus from within the main section, but it doesn't look like it sees it as defined.

Thanks,
You're asking how to print the enum?

The easiest thing to do would be a simple if-else chain.
1
2
3
4
5
6
7
8
9
10
11
12
13
    DriveEncryptionStatus status = getDriveEncryptionStatus(L"C:");
    if (status == DriveEncryptionStatus::Unprotected)
    {
        cout << "Unprotected\n";
    }
    else if (status == DriveEncryptionStatus::Protected)
    {
        cout << "Protected\n";
    }
    else
    {
        cout << "Unknown\n";
    }


edit: typo, forgot "else" in second statement
Last edited on
I see, that makes sense and i can now poll my application output into PowerShell, so much much appreciated, and apologies for the beginner slip ups.

Topic archived. No new replies allowed.