BitLocker是微软Windows自带的用于加密磁盘分卷的技术。
通常,解开后的加密卷通过Windows自带的命令工具“manage-bde”可以查看其恢复密钥串,如下图所示:
如图,这里的数字密码下面的一长串字符串即是下面要提取恢复密钥。
在计算机取证界,经常遇到嫌疑人的目标电脑的磁盘是经过BitLocker加密的,此时通常的做法是通过某种手段(WinPmem、DumpIt、DMA PCILeech,ColdBoot等)取得目标机内存镜像,同时对目标机的磁盘做一个磁盘镜像(WinFE,WinHex,FTKImage等)。
而后,对获取的内存镜像分析(MemProcFS、Volatility等工具)取得BitLocker的VMK密钥,然后通过VMK密钥解密目标磁盘镜像(取证大师等工具),进而获取磁盘中的文件。
这里讲的是通过VMK密钥 + 加密磁盘镜像获取明文恢复密钥串的方法,该方法国外的工具有Elcomsoft、Passware Kit等。
(文字的东西不想多说了,直接上代码,卷起来!)
关键参考代码如下:
//
// @Noema 2021-08-27
// 以下提取恢复密钥明文的方法通过逆向fveapi.dll得来
// 重点关注fveapi.dll中的CFveApiBase::GetAuthMethodInformation函数中的第一个FveDatumVmkQuerySavedKey函数
// 主要逻辑是通过VMK密钥解密Volume Master Key中的stretch key,从而得到恢复密钥的十六进制值,进而得到明文的恢复密钥
//
int libbde_volume_read_recovery_password(
libbde_volume_t *volume,
libbde_key_protector_t *key_protector,
wchar_t *recovery_password_plain,
uint32_t recovery_password_plain_length
)
{
INT retn = -1;
NTSTATUS ret;
BCRYPT_ALG_HANDLE ba_handle = NULL;
BCRYPT_KEY_HANDLE bk_handle = NULL;
BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO paddinginfo = {0};
BCRYPT_KEY_LENGTHS_STRUCT auth_tag_length_info = {0};
UCHAR nonce[12] = {0};
UCHAR tag[16] = {0};
UCHAR data[1024] = {0};
PUCHAR stretch_data = NULL;
DWORD result = 0;
DWORD object_length = 0;
USHORT *recovery_data = NULL;
WCHAR recovery_password[64] = {0};
INT idx = 0;
INT order = 0;
uint8_t * volume_master_key = NULL;
libbde_internal_volume_t *internal_volume = NULL;
libbde_internal_key_protector_t *internal_key_protector = NULL;
if (volume == NULL)
{
return -1;
}
if (key_protector == NULL)
{
return -1;
}
if (recovery_password_plain == NULL)
{
return -1;
}
internal_volume = (libbde_internal_volume_t *)volume;
volume_master_key = internal_volume->io_handle->volume_master_key;
internal_key_protector = (libbde_internal_key_protector_t *)key_protector;
if (internal_key_protector->volume_master_key->protection_type != LIBBDE_KEY_PROTECTION_TYPE_RECOVERY_PASSWORD)
{
return -1;
}
do
{
ret = BCryptOpenAlgorithmProvider(&ba_handle, L"AES", NULL, 0);
if (ret != 0)
{
break;
}
ret = BCryptSetProperty(ba_handle, BCRYPT_CHAINING_MODE, (PUCHAR)BCRYPT_CHAIN_MODE_CCM, 0x20u, 0);
if (ret != 0)
{
break;
}
ret = BCryptGetProperty(ba_handle, L"ObjectLength", (PUCHAR)&object_length, sizeof(object_length), &result, 0);
if (ret != 0)
{
break;
}
ret = BCryptGetProperty(ba_handle, BCRYPT_AUTH_TAG_LENGTH, (PUCHAR)&auth_tag_length_info, sizeof(auth_tag_length_info), &result, 0);
if (ret != 0)
{
break;
}
ret = BCryptGenerateSymmetricKey(ba_handle, &bk_handle, 0, 0, volume_master_key, 0x20, 0);
if (ret != 0)
{
break;
}
stretch_data = internal_key_protector->volume_master_key->stretch_key->data;
if (stretch_data == NULL)
{
break;
}
// nonce
memcpy_s(nonce, 12, stretch_data + 8, 12);
// auth tag
memcpy_s(tag, 16, stretch_data + 8 + 12, 16);
// encrypted data
memcpy_s(data, sizeof(data), stretch_data + 8 + 12 + 16, 0x1C);
// fill structure
paddinginfo.cbSize = sizeof(paddinginfo);
paddinginfo.dwInfoVersion = 1;
paddinginfo.pbNonce = nonce;
paddinginfo.cbNonce = 0x0c;
paddinginfo.pbTag = tag;
paddinginfo.cbTag = 0x10;
// 解密
ret = BCryptDecrypt(bk_handle, data, 0x1c, &paddinginfo, 0, 0, data, 0x1c, &result, 0);
if (ret != 0)
{
break;
}
// 判断合法性
if (*(PWORD)(data) < 0x0C || *(PWORD)(data) != 0x1C)
{
break;
}
if ( *(PWORD)(data + 8) != 0x1000)
{
break;
}
// 偏移到恢复密钥存储位置
recovery_data = (USHORT *)(data + 0x0C);
// 转换恢复密钥为字符串
for ( ; idx<8; idx++, order += 7)
{
wsprintfW(&recovery_password[order], L"%06d-", recovery_data[idx] * 11);
}
recovery_password[wcslen(recovery_password) - 1] = L'\0';
wcsncpy_s(recovery_password_plain, recovery_password_plain_length, recovery_password, _TRUNCATE);
retn = 0;
} while (0);
if (bk_handle)
{
ret = BCryptDestroyKey(bk_handle);
}
if (ba_handle)
{
BCryptCloseAlgorithmProvider(ba_handle, 0);
}
return retn;
}
相关引用:
https://github.com/libyal/libbde
https://github.com/ufrisk/pcileech
https://github.com/ufrisk/pcileech-fpga
https://github.com/ufrisk/MemProcFS
https://github.com/volatilityfoundation/volatility
https://github.com/volatilityfoundation/volatility3