void print_bek_header(dataset_t* bek) { time_t ts; char rec_id[37]; ntfs2utc(bek->timestamp, &ts); format_guid(bek->hash, rec_id); xprintf(L_INFO, "==[ Generic BEK file information ]==\n"); xprintf(L_INFO, "Total Size: %hu bytes\n", bek->size); xprintf(L_INFO, "Unknown: %hu\n", bek->unknown1); xprintf(L_INFO, "Header Size: %d bytes\n", bek->header_size); xprintf(L_INFO, "Recovery Key Id: %16s \n", rec_id); xprintf(L_INFO, "Next counter: %d\n", bek->next_counter); xprintf(L_INFO, "Reserved field: 0x%x\n", bek->algo_zeroed); xprintf(L_INFO, "Epoch Timestamp: %ud sec, or %s\n", (unsigned int)ts, asctime(gmtime(&ts))); }
void print_ext_info_header(external_info_header_t* header) { char rec_id[37] = {0,}; time_t ts; char* type_str = NULL; ntfs2utc(header->timestamp, &ts); format_guid(header->guid, rec_id); type_str = datumtypestr(header->datum_type); xprintf(L_INFO, "===[ Header information ]===\n"); xprintf(L_INFO, "Size: %hu bytes\n", header->size); xprintf(L_INFO, "Unknown1: %#.4x\n", header->unknown1); xprintf(L_INFO, "Datum type: %s (%#.4x)\n", type_str, header->datum_type); xprintf(L_INFO, "Error status: %hu\n", header->error_status); xprintf(L_INFO, "Recovery Key Id: %s\n", rec_id); xprintf(L_INFO, "Epoch Timestamp: %ud sec, or %s\n", (unsigned int)ts, asctime(gmtime(&ts))); xfree(type_str); }
_format_message_dn(char *buf, size_t size, const_efidp dp) { ssize_t off = 0; ssize_t sz; switch (dp->subtype) { case EFIDP_MSG_ATAPI: off += format(buf, size, off, "Ata(%d,%d,%d)", dp->atapi.primary, dp->atapi.slave, dp->atapi.lun); break; case EFIDP_MSG_SCSI: off += format(buf, size, off, "SCSI(%d,%d)", dp->scsi.target, dp->scsi.lun); break; case EFIDP_MSG_FIBRECHANNEL: off += format(buf, size, off, "Fibre(%"PRIx64",%"PRIx64")", le64_to_cpu(dp->fc.wwn), le64_to_cpu(dp->fc.lun)); break; case EFIDP_MSG_FIBRECHANNELEX: off += format(buf, size, off, "Fibre(%"PRIx64",%"PRIx64")", be64_to_cpu(dp->fc.wwn), be64_to_cpu(dp->fc.lun)); break; case EFIDP_MSG_1394: off += format(buf, size, off, "I1394(0x%"PRIx64")", dp->firewire.guid); break; case EFIDP_MSG_USB: off += format(buf, size, off, "USB(%d,%d)", dp->usb.parent_port, dp->usb.interface); break; case EFIDP_MSG_I2O: off += format(buf, size, off, "I2O(%d)", dp->i2o.target); break; case EFIDP_MSG_INFINIBAND: if (dp->infiniband.resource_flags & EFIDP_INFINIBAND_RESOURCE_IOC_SERVICE) { off += format(buf, size, off, "Infiniband(%08x,%"PRIx64"%"PRIx64",%"PRIx64",%"PRIu64",%"PRIu64")", dp->infiniband.resource_flags, dp->infiniband.port_gid[1], dp->infiniband.port_gid[0], dp->infiniband.service_id, dp->infiniband.target_port_id, dp->infiniband.device_id); } else { off += format(buf, size, off, "Infiniband(%08x,%"PRIx64"%"PRIx64",", dp->infiniband.resource_flags, dp->infiniband.port_gid[1], dp->infiniband.port_gid[0]); off += format_guid(buf, size, off, (efi_guid_t *) &dp->infiniband.ioc_guid); off += format(buf, size, off, ",%"PRIu64",%"PRIu64")", dp->infiniband.target_port_id, dp->infiniband.device_id); } break; case EFIDP_MSG_MAC_ADDR: off += format(buf, size, off, "MAC("); off += format_hex(buf, size, off, dp->mac_addr.mac_addr, dp->mac_addr.if_type < 2 ? 6 : sizeof(dp->mac_addr.mac_addr)); off += format(buf, size, off, ",%d)", dp->mac_addr.if_type); break; case EFIDP_MSG_IPv4: { efidp_ipv4_addr const *a = &dp->ipv4_addr; off += format(buf, size, off, "IPv4(%hhu.%hhu.%hhu.%hhu:%hu<->%hhu.%hhu.%hhu.%hhu:%hu,%hx,%hhx)", a->local_ipv4_addr[0], a->local_ipv4_addr[1], a->local_ipv4_addr[2], a->local_ipv4_addr[3], a->local_port, a->remote_ipv4_addr[0], a->remote_ipv4_addr[1], a->remote_ipv4_addr[2], a->remote_ipv4_addr[3], a->remote_port, a->protocol, a->static_ip_addr); break; } case EFIDP_MSG_VENDOR: { struct { efi_guid_t guid; char label[40]; ssize_t (*formatter)(char *buf, size_t size, const_efidp dp); } subtypes[] = { { EFIDP_PC_ANSI_GUID, "VenPcAnsi" }, { EFIDP_VT_100_GUID, "VenVt100" }, { EFIDP_VT_100_PLUS_GUID, "VenVt100Plus" }, { EFIDP_VT_UTF8_GUID, "VenUtf8" }, { EFIDP_MSG_DEBUGPORT_GUID, "DebugPort" }, { EFIDP_MSG_UART_GUID, "", format_uart }, { EFIDP_MSG_SAS_GUID, "", format_sas }, { efi_guid_empty, "" } }; char *label = NULL; ssize_t (*formatter)(char *buf, size_t size, const_efidp dp) = NULL; for (int i = 0; !efi_guid_is_zero(&subtypes[i].guid); i++) { if (efi_guid_cmp(&subtypes[i].guid, &dp->msg_vendor.vendor_guid)) continue; label = subtypes[i].label; formatter = subtypes[i].formatter; break; } if (!label && !formatter) { off += format_vendor(buf, size, off, "VenMsg", dp); break; } else if (formatter) { off += format_helper(formatter, buf, size, off, dp); break; } off += format(buf, size, off, "%s(", label); if (efidp_node_size(dp) > (ssize_t)(sizeof (efidp_header) + sizeof (efi_guid_t))) { off += format_hex(buf, size, off, dp->msg_vendor.vendor_data, efidp_node_size(dp) - sizeof (efidp_header) - sizeof (efi_guid_t)); } break; } case EFIDP_MSG_IPv6: { efidp_ipv6_addr const *a = &dp->ipv6_addr; char *addr0 = NULL; char *addr1 = NULL; sz = format_ipv6_port(addr0, 0, 0, a->local_ipv6_addr, a->local_port); if (sz < 0) return sz; addr0 = alloca(sz+1); sz = format_ipv6_port(addr0, sz, 0, a->local_ipv6_addr, a->local_port); if (sz < 0) return sz; sz = format_ipv6_port(addr1, 0, 0, a->remote_ipv6_addr, a->remote_port); if (sz < 0) return sz; addr1 = alloca(sz+1); sz = format_ipv6_port(addr1, sz, 0, a->remote_ipv6_addr, a->remote_port); if (sz < 0) return sz; off += format(buf, size, off, "IPv6(%s<->%s,%hx,%hhx)", addr0, addr1, a->protocol, a->ip_addr_origin); break; } case EFIDP_MSG_UART: { int parity = dp->uart.parity; char parity_label[] = "DNEOMS"; int stop_bits = dp->uart.stop_bits; char *sb_label[] = {"D", "1", "1.5", "2"}; off += format(buf, size, off, "Uart(%"PRIu64",%d,", dp->uart.baud_rate ? dp->uart.baud_rate : 115200, dp->uart.data_bits ? dp->uart.data_bits : 8); off += format(buf, size, off, parity > 5 ? "%d," : "%c,", parity > 5 ? parity : parity_label[parity]); if (stop_bits > 3) off += format(buf, size, off, "%d)", stop_bits); else off += format(buf, size, off, "%s)", sb_label[stop_bits]); break; } case EFIDP_MSG_USB_CLASS: off += format_helper(format_usb_class, buf, size, off, dp); break; case EFIDP_MSG_USB_WWID: off += format(buf, size, off, "UsbWwid(%"PRIx16",%"PRIx16",%d,", dp->usb_wwid.vendor_id, dp->usb_wwid.product_id, dp->usb_wwid.interface); off += format_ucs2(buf, size, off, dp->usb_wwid.serial_number, (efidp_node_size(dp) - offsetof(efidp_usb_wwid, serial_number)) / 2 + 1); off += format(buf, size, off, ")"); break; case EFIDP_MSG_LUN: off += format(buf, size, off, "Unit(%d)", dp->lun.lun); break; case EFIDP_MSG_SATA: off += format(buf, size, off, "Sata(%d,%d,%d)", dp->sata.hba_port, dp->sata.port_multiplier_port, dp->sata.lun); break; case EFIDP_MSG_ISCSI: { size_t sz = efidp_node_size(dp) - offsetof(efidp_iscsi, target_name); if (sz > EFIDP_ISCSI_MAX_TARGET_NAME_LEN) sz = EFIDP_ISCSI_MAX_TARGET_NAME_LEN; char target_name[sz + 1]; memcpy(target_name, dp->iscsi.target_name, sz); target_name[sz] = '\0'; uint64_t lun; memcpy(&lun, dp->iscsi.lun, sizeof (lun)); off += format(buf, size, off, "iSCSI(%s,%d,0x%"PRIx64",%s,%s,%s,%s)", target_name, dp->iscsi.tpgt, be64_to_cpu(lun), (dp->iscsi.options >> EFIDP_ISCSI_HEADER_DIGEST_SHIFT) & EFIDP_ISCSI_HEADER_CRC32 ? "CRC32" : "None", (dp->iscsi.options >> EFIDP_ISCSI_DATA_DIGEST_SHIFT) & EFIDP_ISCSI_DATA_CRC32 ? "CRC32" : "None", (dp->iscsi.options >> EFIDP_ISCSI_AUTH_SHIFT) & EFIDP_ISCSI_AUTH_NONE ? "None" : \ (dp->iscsi.options >> EFIDP_ISCSI_CHAP_SHIFT) & EFIDP_ISCSI_CHAP_UNI ? "CHAP_UNI" : "CHAP_BI", dp->iscsi.protocol == 0 ? "TCP" : "Unknown"); break; } case EFIDP_MSG_VLAN: off += format(buf, size, off, "Vlan(%d)", dp->vlan.vlan_id); break; case EFIDP_MSG_SAS_EX: off += format_sas(buf, size, dp); break; case EFIDP_MSG_NVME: off += format(buf, size, off, "NVMe(0x%"PRIx32"," "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X)", dp->nvme.namespace_id, dp->nvme.ieee_eui_64[0], dp->nvme.ieee_eui_64[1], dp->nvme.ieee_eui_64[2], dp->nvme.ieee_eui_64[3], dp->nvme.ieee_eui_64[4], dp->nvme.ieee_eui_64[5], dp->nvme.ieee_eui_64[6], dp->nvme.ieee_eui_64[7]); break; case EFIDP_MSG_URI: { size_t sz = efidp_node_size(dp) - offsetof(efidp_uri, uri); char uri[sz + 1]; memcpy(uri, dp->uri.uri, sz); uri[sz] = '\0'; off += format(buf, size, off, "Uri(%s)", uri); break; } case EFIDP_MSG_UFS: off += format(buf, size, off, "UFS(%d,0x%02x)", dp->ufs.target_id, dp->ufs.lun); break; case EFIDP_MSG_SD: off += format(buf, size, off, "SD(%d)", dp->sd.slot_number); break; default: off += format(buf, size, off, "Msg(%d,", dp->subtype); off += format_hex(buf, size, off, (uint8_t *)dp+4, efidp_node_size(dp)-4); off += format(buf,size,off,")"); break; } return off; }
/** * Get the VMK datum using a bek file (external key) * * @param dataset The dataset of BitLocker's metadata on the volume * @param bek_file The path to the .BEK file to use * @param vmk_datum The datum_key_t found, containing the unencrypted VMK * @return TRUE if result can be trusted, FALSE otherwise */ int get_vmk_from_bekfile2(dis_metadata_t dis_meta, char* bek_file, void** vmk_datum) { // Check parameters if(!dis_meta || !vmk_datum) return FALSE; guid_t key_guid = {0,}; char rec_id[37] = {0,}; bitlocker_dataset_t* bek_dataset = NULL; uint8_t* recovery_key = NULL; size_t rk_size = 0; int result = FALSE; int fd_bek = 0; if(bek_file) { /* Check if the bek file exists */ fd_bek = dis_open(bek_file, O_RDONLY); if(fd_bek < 0) { dis_printf(L_ERROR, "Cannot open FVEK file (%s)\n", bek_file); return FALSE; } } else { dis_printf( L_ERROR, "Using bekfile method (USB) but missing the bekfile name. Abort.\n" ); return FALSE; } dis_printf( L_INFO, "Using the bekfile '%s' to decrypt the VMK.\n", bek_file ); /* * We need the recovery key id which can be found in the bek file * to find its match in a datum of the volume's metadata */ if(!get_bek_dataset(fd_bek, (void**) &bek_dataset)) { dis_printf(L_ERROR, "Unable to retrieve the dataset. Abort.\n"); dis_close(fd_bek); return FALSE; } /* We have what we wanted, so close the file */ dis_close(fd_bek); /* Get the external datum */ void* dataset = dis_metadata_set_dataset(dis_meta, bek_dataset); get_next_datum( dis_meta, UINT16_MAX, DATUMS_VALUE_EXTERNAL_KEY, NULL, vmk_datum ); dis_metadata_set_dataset(dis_meta, dataset); /* Check the result datum */ if(!*vmk_datum || !datum_value_type_must_be(*vmk_datum, DATUMS_VALUE_EXTERNAL_KEY)) { dis_printf( L_ERROR, "Error processing the bekfile: datum of type %hd not found. " "Internal failure, abort.\n", DATUMS_VALUE_EXTERNAL_KEY ); *vmk_datum = NULL; memclean(bek_dataset, bek_dataset->size); return FALSE; } /* Now that we are sure of the type, take care of copying the recovery key id */ datum_external_t* datum_exte = (datum_external_t*) *vmk_datum; memcpy(key_guid, datum_exte->guid, 16); format_guid(key_guid, rec_id); dis_printf( L_INFO, "Bekfile GUID found: '%s', looking for the same in metadata...\n", rec_id ); /* Grab the datum nested in the last, we will need it to decrypt the VMK */ if(!get_nested_datumvaluetype(*vmk_datum, DATUMS_VALUE_KEY, vmk_datum) || !*vmk_datum) { dis_printf( L_ERROR, "Error processing the bekfile: no nested datum found. " "Internal failure, abort.\n" ); *vmk_datum = NULL; memclean(bek_dataset, bek_dataset->size); return FALSE; } if(!get_payload_safe(*vmk_datum, (void**) &recovery_key, &rk_size)) { dis_printf( L_ERROR, "Error getting the key to decrypt VMK from the bekfile. " "Internal failure, abort.\n" ); *vmk_datum = NULL; memclean(bek_dataset, bek_dataset->size); return FALSE; } memclean(bek_dataset, bek_dataset->size); /* * Now that we have the key to decrypt the VMK, we need to * find the VMK datum in the BitLocker metadata in order to * decrypt the VMK using this already found key in the bekfile */ if(!get_vmk_datum_from_guid(dis_meta, key_guid, vmk_datum)) { format_guid(key_guid, rec_id); dis_printf( L_ERROR, "\n\tError, can't find a valid and matching VMK datum.\n" "\tThe GUID researched was '%s', check if you have the right " "bek file for the right volume.\n" "\tAbort.\n", rec_id ); *vmk_datum = NULL; dis_free(recovery_key); return FALSE; } dis_printf( L_INFO, "VMK datum of id '%s' found. Trying to reach the Key datum...\n", rec_id ); /* * We have the datum containing other data, so get in there and take the * nested one with type 5 (aes-ccm) */ if(!get_nested_datumvaluetype(*vmk_datum, DATUMS_VALUE_AES_CCM, vmk_datum)) { dis_printf( L_ERROR, "Error looking for the nested datum in the VMK one. " "Internal failure, abort.\n" ); *vmk_datum = NULL; dis_free(recovery_key); return FALSE; } dis_printf(L_INFO, "Key datum found and payload extracted!\n"); result = get_vmk( (datum_aes_ccm_t*) *vmk_datum, recovery_key, rk_size, (datum_key_t**) vmk_datum ); dis_free(recovery_key); return result; }
ssize_t _format_media_dn(char *buf, size_t size, const_efidp dp) { ssize_t off = 0; switch (dp->subtype) { case EFIDP_MEDIA_HD: off += format(buf, size, off, "HD(%d,", dp->hd.partition_number); switch (dp->hd.signature_type) { case EFIDP_HD_SIGNATURE_MBR: off += format(buf, size, off, "MBR,0x%"PRIu32",0x%"PRIx64",0x%"PRIx64")", *(char *)dp->hd.signature, dp->hd.start, dp->hd.size); break; case EFIDP_HD_SIGNATURE_GUID: off += format(buf, size, off, "GPT,"); off += format_guid(buf, size, off, (efi_guid_t *)dp->hd.signature); off += format(buf, size, off, ",0x%"PRIx64",0x%"PRIx64")", dp->hd.start, dp->hd.size); break; default: off += format(buf, size, off, "%d,", dp->hd.signature_type); off += format_hex(buf, size, off, dp->hd.signature, sizeof(dp->hd.signature)); off += format(buf, size, off, ",0x%"PRIx64",0x%"PRIx64")", dp->hd.start, dp->hd.size); break; } break; case EFIDP_MEDIA_CDROM: off += format(buf, size, off, "CDROM(%d,0x%"PRIx64",0x%"PRIx64")", dp->cdrom.boot_catalog_entry, dp->cdrom.partition_rba, dp->cdrom.sectors); break; case EFIDP_MEDIA_VENDOR: off += format_vendor(buf, size, off, "VenMedia", dp); break; case EFIDP_MEDIA_FILE: off += format(buf, size, off, "File("); off += format_ucs2(buf, size, off, dp->file.name, (efidp_node_size(dp) - offsetof(efidp_file, name)) / 2); off += format(buf, size, off, ")"); break; case EFIDP_MEDIA_PROTOCOL: off += format(buf, size, off, "Media("); off += format_guid(buf, size, off, &dp->protocol.protocol_guid); off += format(buf, size, off, ")"); break; case EFIDP_MEDIA_FIRMWARE_FILE: off += format(buf, size, off, "FvFile("); off += format_guid(buf, size, off, &dp->protocol.protocol_guid); off += format(buf, size, off, ")"); break; case EFIDP_MEDIA_FIRMWARE_VOLUME: off += format(buf, size, off, "FvVol("); off += format_guid(buf, size, off, &dp->protocol.protocol_guid); off += format(buf, size, off, ")"); break; case EFIDP_MEDIA_RELATIVE_OFFSET: off = format(buf, size, off, "Offset(0x%"PRIx64",0x%"PRIx64")", dp->relative_offset.first_byte, dp->relative_offset.last_byte); break; case EFIDP_MEDIA_RAMDISK: { struct { efi_guid_t guid; char label[40]; } subtypes[] = { { EFIDP_VIRTUAL_DISK_GUID, "VirtualDisk" }, { EFIDP_VIRTUAL_CD_GUID, "VirtualCD" }, { EFIDP_PERSISTENT_VIRTUAL_DISK_GUID, "PersistentVirtualDisk" }, { EFIDP_PERSISTENT_VIRTUAL_CD_GUID, "PersistentVirtualCD" }, { efi_guid_empty, "" } }; char *label = NULL; for (int i = 0; !efi_guid_is_zero(&subtypes[i].guid); i++) { if (efi_guid_cmp(&subtypes[i].guid, &dp->ramdisk.disk_type_guid)) continue; label = subtypes[i].label; break; } if (label) { off += format(buf, size, off, "%s(0x%"PRIx64",0x%"PRIx64",%d)", label, dp->ramdisk.start_addr, dp->ramdisk.end_addr, dp->ramdisk.instance_number); break; } off += format(buf, size, off, "Ramdisk(0x%"PRIx64",0x%"PRIx64",%d,", dp->ramdisk.start_addr, dp->ramdisk.end_addr, dp->ramdisk.instance_number); off += format_guid(buf, size, off, &dp->ramdisk.disk_type_guid); off += format(buf, size, off, ")"); break; } default: off += format(buf, size, off, "MediaPath(%d,", dp->subtype); off += format_hex(buf, size, off, (uint8_t *)dp+4, (efidp_node_size(dp)-4) / 2); off += format(buf,size,off,")"); break; } return off; }