发布时间:2025-12-09 16:09:27 浏览次数:3
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;}// noncememcpy_s(nonce, 12, stretch_data + 8, 12);// auth tagmemcpy_s(tag, 16, stretch_data + 8 + 12, 16);// encrypted datamemcpy_s(data, sizeof(data), stretch_data + 8 + 12 + 16, 0x1C);// fill structurepaddinginfo.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