Get device encryption support information

Viewed 118

I want to detect the device encryption support in my program. This info is available in the System Information program. Please check out the screenshot below:

enter image description here

What kind of Win API functions are used/available to detect the device encryption support? What System Information program uses to detect it? I just need some information.

1 Answers

TL;DR: it uses undocumented functions from fveapi.dll (Windows Bitlocker Drive Encryption API). It seems to rely only on the TPM capabilities.


Note that I only spent like 15 mins on it, but I doubt I missed something crucial, althoug this might be possible.

A bit of Reverse engineering

Typed system information in search bar, saw it spawned msinfo32.exe. Put the binary in a disassembler. It uses a MUI file so I'll have to search for the strings in the MUI file and not the executable.

Searching Device Encryption Support leads to string ID 951 (0x3b7)

STRINGTABLE
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
{
  951,  "Device Encryption Support|%s"

Searching for the contant in the disassembler leads to a function named:

DeviceEncryptionDataPoints(struct CWMIHelper *, struct CPtrList *)

The load ing of the aforementioned string is almost right at the start:

.text:00000001400141E9                 mov     edx, 3B7h
.text:00000001400141EE                 lea     rcx, [rsp+2C8h+var_280]
.text:00000001400141F3
.text:00000001400141F3 loc_1400141F3:
.text:00000001400141F3 ;   try {
.text:00000001400141F3                 call    cs:__imp_?LoadStringW@CString@@QEAAHI@Z ; CString::LoadStringW(uint)

So we are definitely in the right function.

It loads the fveapi.dll module:

.text:0000000140014269                 xor     edx, edx        ; hFile
.text:000000014001426B                 mov     r8d, 800h       ; dwFlags
.text:0000000140014271                 lea     rcx, LibFileName ; "fveapi.dll"
.text:0000000140014278                 call    cs:__imp_LoadLibraryExW

Gets a pointer on FveQueryDeviceEncryptionSupport:

.text:00000001400142AB                 lea     rdx, aFvequerydevice ; "FveQueryDeviceEncryptionSupport"
.text:00000001400142B2                 mov     rcx, rdi        ; hModule
.text:00000001400142B5                 call    cs:__imp_GetProcAddress

And immediately calls the function (this is a protected CFG call, but it's here):

.text:00000001400142CA                 mov     [rsp+2C8h+var_254], rbx
.text:00000001400142CF                 mov     [rsp+2C8h+var_260], 14h
.text:00000001400142D7                 mov     [rsp+2C8h+var_25C], 1
.text:00000001400142DF                 mov     [rsp+2C8h+var_258], 1
.text:00000001400142E7                 lea     rcx, [rsp+2C8h+var_260]
.text:00000001400142EC                 call    cs:__guard_dispatch_icall_fptr

Return value

If the function fails:

.text:00000001400142EC                 call    cs:__guard_dispatch_icall_fptr
.text:00000001400142F2                 mov     esi, eax
.text:00000001400142F4                 test    eax, eax
.text:00000001400142F6                 js      loc_1400143F0 ; check failure

We land here:

.text:00000001400143F7                 mov     edx, 2FFh
.text:00000001400143FC                 lea     rcx, [rsp+2C8h+var_288]
.text:0000000140014401                 call    cs:__imp_?LoadStringW@CString@@QEAAHI@Z ; CString::LoadStringW(uint)

The string 0x2FF (767) is:

 767,   "Elevation Required to View"

If the call succeed, the code checks one of the parameter which is definitly an out parameter:

.text:00000001400142EC                 call    cs:__guard_dispatch_icall_fptr
.text:00000001400142F2                 mov     esi, eax
.text:00000001400142F4                 test    eax, eax
.text:00000001400142F6                 js      loc_1400143F0
.text:00000001400142FC                 cmp     dword ptr [rsp+2C8h+var_254], ebx ; rbx = 0
.text:0000000140014300                 jnz     short loc_14001431D
.text:0000000140014302                 mov     edx, 3B8h
.text:0000000140014307                 lea     rcx, [rsp+2C8h+var_288]
.text:000000014001430C                 call    cs:__imp_?LoadStringW@CString@@QEAAHI@Z ; CString::LoadStringW(uint)

If it's 0, the string 0x3b8 (952) is used:

  952,  "Meets prerequisites"

Otherwise various failure functions are called.

Failure

In case of a failure, the UpdateDeviceEncryptionStateFailureString function is called:

.text:0000000140014325                 lea     r9, [rsp+2C8h+var_294] ; int *
.text:000000014001432A                 lea     r8, [rsp+2C8h+var_290] ; int *
.text:000000014001432F                 mov     edx, 3C1h       ; unsigned int
.text:0000000140014334                 lea     rcx, [rsp+2C8h+var_288] ; struct CString *
.text:0000000140014339                 call    ?UpdateDeviceEncryptionStateFailureString@@YAXPEAVCString@@IPEAH1@Z ; UpdateDeviceEncryptionStateFailureString(CString *,uint,int *,int *)

Its main goal is to fetch some string from the resource file.

One that stands out is 0x3b9:

.text:0000000140013A37                 mov     edx, 3B9h
.text:0000000140013A3C                 mov     rcx, rbx
.text:0000000140013A3F                 call    cs:__imp_?LoadStringW@CString@@QEAAHI@Z ; CString::LoadStringW(uint)
  953,  "Reasons for failed automatic device encryption"

Which is the case for me since I don't have a TPM.

Other Functions

All of the other functions called from the DeviceEncryptionDataPoints (at least to get the needed results) are all from the fveapi.dll.

There are a lot in a function called PerformIndividualHardwareTests(HINSTANCE hModule, struct CString *, int *, int *):

.text:0000000140013AEF                 lea     rdx, aNgscbcheckisao ; "NgscbCheckIsAOACDevice"
.text:0000000140013AF6                 mov     [rbp+var_1F], 0
.text:0000000140013AFA                 mov     rdi, r9
.text:0000000140013AFD                 mov     [rbp+var_20], 0
.text:0000000140013B01                 mov     rsi, r8
.text:0000000140013B04                 mov     [rbp+var_1E], 0
.text:0000000140013B08                 mov     rbx, rcx
.text:0000000140013B0B                 call    cs:__imp_GetProcAddress
.text:0000000140013B12                 nop     dword ptr [rax+rax+00h]
.text:0000000140013B17                 mov     r12, rax
.text:0000000140013B1A                 test    rax, rax
.text:0000000140013B1D                 jz      loc_140013CB9
.text:0000000140013B23                 lea     rdx, aNgscbcheckishs ; "NgscbCheckIsHSTIVerified"
.text:0000000140013B2A                 mov     rcx, rbx        ; hModule
.text:0000000140013B2D                 call    cs:__imp_GetProcAddress
.text:0000000140013B34                 nop     dword ptr [rax+rax+00h]
.text:0000000140013B39                 mov     r15, rax
.text:0000000140013B3C                 test    rax, rax
.text:0000000140013B3F                 jz      loc_140013CB9
.text:0000000140013B45                 lea     rdx, aNgscbcheckhsti ; "NgscbCheckHSTIPrerequisitesVerified"
.text:0000000140013B4C                 mov     rcx, rbx        ; hModule
.text:0000000140013B4F                 call    cs:__imp_GetProcAddress
.text:0000000140013B56                 nop     dword ptr [rax+rax+00h]
.text:0000000140013B5B                 mov     r13, rax
.text:0000000140013B5E                 test    rax, rax
.text:0000000140013B61                 jz      loc_140013CB9
.text:0000000140013B67                 lea     rdx, aNgscbcheckdmas ; "NgscbCheckDmaSecurity"
.text:0000000140013B6E                 mov     rcx, rbx        ; hModule
.text:0000000140013B71                 call    cs:__imp_GetProcAddress

There's also a registry key checked SYSTEM\CurrentControlSet\Control\BitLocker\AutoDE\HSTI:

.text:0000000140013C10                 lea     r8, ?NGSCB_AUTODE_HSTI_REQUIRED@@3QBGB ; "HSTIVerificationRequired"
.text:0000000140013C17                 mov     [rsp+60h+pcbData], rax ; pcbData
.text:0000000140013C1C                 lea     rdx, ?NGSCB_AUTODE_HSTI_PREREQS@@3QBGB ; "SYSTEM\\CurrentControlSet\\Control\\Bit"...
.text:0000000140013C23                 lea     rax, [rbp+var_1C]
.text:0000000140013C27                 mov     r9d, 10h        ; dwFlags
.text:0000000140013C2D                 mov     [rsp+60h+pvData], rax ; pvData
.text:0000000140013C32                 mov     rcx, 0FFFFFFFF80000002h ; hkey
.text:0000000140013C39                 and     [rsp+60h+var_40], 0
.text:0000000140013C3F                 call    cs:__imp_RegGetValueW

and some other functions (NgscbCheckPreventDeviceEncryption, NgscbGetWinReConfiguration, FveCheckTpmCapability, ...) , once again, all from the fveapi.dll module.

So basically the checks are all based on functions from this DLL. It seems that none of them are documented (as far as I can see with a quick search).

I didn't find anything around in the DeviceEncryptionDataPoints caller (which is basically the main() function), since the next calls are dealing with checking the hypervisor capabilities.

Related