Decrypt key from \\.\PhysicalDrive0 > Volume:4
diff --git a/Sources/Commands/command_btree.cpp b/Sources/Commands/command_btree.cpp
index 578b955..fd5a10d 100644
--- a/Sources/Commands/command_btree.cpp
+++ b/Sources/Commands/command_btree.cpp
@@ -19,11 +19,7 @@
int print_btree_info(std::shared_ptr disk, std::shared_ptr vol, std::shared_ptr opts)
{
- if ((vol->filesystem() != "NTFS") && (vol->filesystem() != "Bitlocker"))
- {
- std::cerr << "[!] NTFS volume required" << std::endl;
- return 1;
- }
+ if (!commands::helpers::is_ntfs(disk, vol)) return 1;
std::shared_ptr explorer = std::make_shared(vol);
std::shared_ptr record = commands::helpers::find_record(explorer, opts);
diff --git a/Sources/Commands/command_efs_backup.cpp b/Sources/Commands/command_efs_backup.cpp
index deca96b..86468f8 100644
--- a/Sources/Commands/command_efs_backup.cpp
+++ b/Sources/Commands/command_efs_backup.cpp
@@ -6,16 +6,12 @@
#include
#include
#include
-#include
+#include
int backup_keys(std::shared_ptr disk, std::shared_ptr vol, std::shared_ptr opts)
{
- if ((vol->filesystem() != "NTFS") && (vol->filesystem() != "Bitlocker"))
- {
- std::cerr << "[!] NTFS volume required" << std::endl;
- return 1;
- }
+ if (!commands::helpers::is_ntfs(disk, vol)) return 1;
std::cout << std::setfill('0');
utils::ui::title("Backup certificates and keys from " + disk->name() + " > Volume:" + std::to_string(vol->index()));
@@ -214,7 +210,7 @@ int backup_keys(std::shared_ptr disk, std::shared_ptr vol, std::sh
auto decrypted_private_key = keyfile->private_key()->decrypt_with_masterkey(masterkey);
if (decrypted_private_key != nullptr)
{
- std::shared_ptr pkcs12 = std::make_shared(cert, decrypted_private_key);
+ std::shared_ptr pkcs12 = std::make_shared(cert, decrypted_private_key);
if (opts->output == "")
{
opts->output = cert->hash();
diff --git a/Sources/Commands/command_efs_certificate.cpp b/Sources/Commands/command_efs_certificate.cpp
index db8696e..d5287b0 100644
--- a/Sources/Commands/command_efs_certificate.cpp
+++ b/Sources/Commands/command_efs_certificate.cpp
@@ -5,15 +5,9 @@
#include "EFS/certificate_file.h"
-const std::vector format = { "pem" };
-
int show_certificate(std::shared_ptr disk, std::shared_ptr vol, std::shared_ptr opts)
{
- if ((vol->filesystem() != "NTFS") && (vol->filesystem() != "Bitlocker"))
- {
- std::cerr << "[!] NTFS volume required" << std::endl;
- return 1;
- }
+ if (!commands::helpers::is_ntfs(disk, vol)) return 1;
std::cout << std::setfill('0');
utils::ui::title("Display certificate from " + disk->name() + " > Volume:" + std::to_string(vol->index()));
@@ -126,29 +120,13 @@ int show_certificate(std::shared_ptr disk, std::shared_ptr vol, st
}
else
{
- if (opts->format == "")
- {
- opts->format = format[0];
- }
- else
- {
- opts->format = utils::strings::lower(opts->format);
- }
-
- if (std::find(format.begin(), format.end(), opts->format) == format.end())
+ if (certificate_file->export_to_PEM(opts->output) == 0)
{
- std::cerr << "[!] Invalid output format (" << opts->format << ")" << std::endl;
+ std::cout << "[+] Certificate exported to " << opts->output << ".pem" << std::endl;
}
else
{
- if (certificate_file->export_to_PEM(opts->output) == 0)
- {
- std::cout << "[+] Certificate exported to " << opts->output << ".pem" << std::endl;
- }
- else
- {
- std::cerr << "[!] Unable to export the certificate" << std::endl;
- }
+ std::cerr << "[!] Unable to export the certificate" << std::endl;
}
}
@@ -157,11 +135,7 @@ int show_certificate(std::shared_ptr disk, std::shared_ptr vol, st
int list_certificates(std::shared_ptr disk, std::shared_ptr vol, std::shared_ptr opts)
{
- if ((vol->filesystem() != "NTFS") && (vol->filesystem() != "Bitlocker"))
- {
- std::cerr << "[!] NTFS volume required" << std::endl;
- return 1;
- }
+ if (!commands::helpers::is_ntfs(disk, vol)) return 1;
std::cout << std::setfill('0');
utils::ui::title("List certificates from " + disk->name() + " > Volume:" + std::to_string(vol->index()));
diff --git a/Sources/Commands/command_efs_decrypt.cpp b/Sources/Commands/command_efs_decrypt.cpp
new file mode 100644
index 0000000..f6da2a2
--- /dev/null
+++ b/Sources/Commands/command_efs_decrypt.cpp
@@ -0,0 +1,274 @@
+#include "Commands/commands.h"
+#include "Utils/table.h"
+#include "Utils/constant_names.h"
+#include
+#include
+#include
+#include
+
+static unsigned char EFS_IV[16] = { 0x12, 0x13, 0x16, 0xe9, 0x7b, 0x65, 0x16, 0x58, 0x61, 0x89, 0x91, 0x44, 0xbe, 0xad, 0x89, 0x19 };
+
+std::shared_ptr> decrypt_fek(RSA* private_key, std::shared_ptr> encrypted_fek)
+{
+ if (encrypted_fek && private_key)
+ {
+ std::shared_ptr> decrypted_fek = std::make_shared>(encrypted_fek->size());
+ int ret = RSA_private_decrypt(encrypted_fek->size(), encrypted_fek->data(), decrypted_fek->address(), private_key, RSA_PKCS1_PADDING);
+ if (ret == -1)
+ {
+ return nullptr;
+ }
+ else
+ {
+ decrypted_fek->shrink(ret);
+ return decrypted_fek;
+ }
+ }
+ return nullptr;
+}
+
+void decrypt_block(std::pair block, std::shared_ptr> fek, DWORD64 index)
+{
+ EVP_CIPHER_CTX* pctx = EVP_CIPHER_CTX_new();
+ unsigned char iv[16];
+
+ memcpy_s(iv, 16, EFS_IV, 16);
+
+ ((DWORD64*)iv)[0] += (index * 512);
+ ((DWORD64*)iv)[1] += (index * 512);
+
+ int outl = block.second;
+ EVP_DecryptInit(pctx, utils::crypto::cryptoapi::encryption_to_evp(fek->data()->Algorithm), fek->data()->Key, iv);
+ EVP_DecryptUpdate(pctx, block.first, &outl, block.first, block.second);
+ block.second = outl;
+ EVP_CIPHER_CTX_free(pctx);
+}
+
+int decrypt_file(std::shared_ptr record, std::shared_ptr> fek, std::shared_ptr opts)
+{
+ int ret = 0;
+ if (opts->output == "")
+ {
+ opts->output = utils::strings::to_utf8(record->filename() + L".decrypted");
+ }
+
+ BIO* output = BIO_new_file(opts->output.c_str(), "wb");
+ if (output)
+ {
+ DWORD64 written_bytes = 0ULL;
+ DWORD res_write = 0;
+ DWORD index_block = 0;
+ DWORD64 clear_size = record->datasize();
+ for (auto data_block : record->process_data("", 512, true))
+ {
+ if (data_block.second == 512)
+ {
+ decrypt_block(data_block, fek, index_block);
+
+ int need_to_write = static_cast(min(clear_size - written_bytes, data_block.second));
+ if (need_to_write)
+ {
+ res_write = BIO_write(output, data_block.first, need_to_write);
+ if (res_write == 0 || res_write == -1)
+ {
+ std::cout << "[!] Failed to write decrypted file" << std::endl;
+ ret = 3;
+ }
+ else
+ {
+ written_bytes += res_write;
+ }
+ }
+ }
+ else
+ {
+ std::cerr << "[!] Wrong block size during decryption (" << data_block.second << ")" << std::endl;
+ ret = 4;
+ break;
+ }
+ index_block++;
+ }
+ BIO_free(output);
+ }
+ else
+ {
+ std::cout << "[!] Failed to create decrypted file" << std::endl;
+ ret = 1;
+ }
+
+ return ret;
+}
+
+int load_key_and_decrypt_file(std::shared_ptr disk, std::shared_ptr vol, std::shared_ptr opts)
+{
+ utils::ui::title("Decrypt EFS file from " + disk->name() + " > Volume:" + std::to_string(vol->index()));
+
+ if (!commands::helpers::is_ntfs(disk, vol)) return 1;
+
+ std::string keyid;
+
+ std::cout << "[+] Loading PKCS12 input file" << std::endl;
+ std::shared_ptr pkcs12 = std::make_shared(opts->pfx, opts->password);
+ if (pkcs12->certificate() && pkcs12->key())
+ {
+ keyid = pkcs12->certificate_hash();
+ std::cout << "[-] KeyID : " << keyid << std::endl;
+
+ }
+ else
+ {
+ std::cout << "[!] Failed to load PKCS12 file" << std::endl;
+ return 2;
+ }
+
+ std::shared_ptr explorer = std::make_shared(vol);
+
+ std::shared_ptr record = commands::helpers::find_record(explorer, opts);
+
+ PMFT_RECORD_ATTRIBUTE_STANDARD_INFORMATION stdinfo = nullptr;
+ PMFT_RECORD_ATTRIBUTE_HEADER stdinfo_att = record->attribute_header($STANDARD_INFORMATION);
+ if (stdinfo_att)
+ {
+ stdinfo = POINTER_ADD(PMFT_RECORD_ATTRIBUTE_STANDARD_INFORMATION, stdinfo_att, stdinfo_att->Form.Resident.ValueOffset);
+ }
+ if (stdinfo)
+ {
+ if (stdinfo->u.Permission.encrypted == 0)
+ {
+ std::cout << "[!] File is not encrypted" << std::endl;
+ return 1;
+ }
+ }
+
+ std::cout << "[+] Parsing $EFS streams" << std::endl;
+ PMFT_RECORD_ATTRIBUTE_HEADER pLogged_utility_attr_header = record->attribute_header($LOGGED_UTILITY_STREAM, "$EFS");
+ if (pLogged_utility_attr_header)
+ {
+ auto efs_header = record->attribute_data(pLogged_utility_attr_header);
+ if (efs_header)
+ {
+ PMFT_RECORD_ATTRIBUTE_EFS_ARRAY_HEADER efs_arr_header = nullptr;
+ if (efs_header->data()->OffsetToDDF != 0)
+ {
+ efs_arr_header = POINTER_ADD(PMFT_RECORD_ATTRIBUTE_EFS_ARRAY_HEADER, efs_header->data(), efs_header->data()->OffsetToDDF);
+ std::cout << "[-] " << efs_arr_header->Count << " data decryption field(s) found" << std::endl;
+
+ uint32_t i = 0;
+ PMFT_RECORD_ATTRIBUTE_EFS_DATA_DECRYPTION_ENTRY_HEADER entry_header = POINTER_ADD(PMFT_RECORD_ATTRIBUTE_EFS_DATA_DECRYPTION_ENTRY_HEADER, efs_arr_header, 4);
+ while (i < efs_arr_header->Count)
+ {
+ auto fek_enc = std::make_shared>(POINTER_ADD(PBYTE, entry_header, entry_header->FEKOffset), entry_header->FEKSize);
+ fek_enc->reverse_bytes();
+
+ PMFT_RECORD_ATTRIBUTE_EFS_DATA_DECRYPTION_ENTRY entry = POINTER_ADD(PMFT_RECORD_ATTRIBUTE_EFS_DATA_DECRYPTION_ENTRY, entry_header, entry_header->CredentialHeaderOffset);
+ PMFT_RECORD_ATTRIBUTE_EFS_DF_CERTIFICATE_THUMBPRINT_HEADER thumprint_header = POINTER_ADD(PMFT_RECORD_ATTRIBUTE_EFS_DF_CERTIFICATE_THUMBPRINT_HEADER, entry, entry->cert_thumbprint_header_offset);
+
+ auto cert_fingerprint = std::make_shared>(POINTER_ADD(PBYTE, thumprint_header, thumprint_header->thumbprint_offset), thumprint_header->thumbprint_size);
+ std::string ddf_id = utils::strings::to_utf8(cert_fingerprint->to_hex());
+
+ if (ddf_id == keyid)
+ {
+ std::cout << "[+] Decrypting FEK" << std::endl;
+ std::shared_ptr> decrypted_fek = decrypt_fek(EVP_PKEY_get0_RSA(pkcs12->key()), fek_enc);
+ if (decrypted_fek)
+ {
+ std::cout << "[-] FEK" << std::endl;
+ std::shared_ptr table = std::make_shared();
+ table->set_margin_left(4);
+ table->add_header_line("Property");
+ table->add_header_line("Value");
+
+ table->add_item_line("Entropy");
+ table->add_item_line(std::to_string(decrypted_fek->data()->Entropy));
+ table->new_line();
+
+ table->add_item_line("Algorithm");
+ table->add_item_line(constants::efs::enc_algorithm(decrypted_fek->data()->Algorithm));
+ table->new_line();
+
+ table->add_item_line("Key (" + std::to_string((decrypted_fek->size() - 16) * 8) + "bits)");
+ table->add_item_line(utils::convert::to_hex(decrypted_fek->data()->Key, decrypted_fek->size() - 16));
+ table->new_line();
+
+ table->render(std::cout);
+ table = nullptr;
+
+ std::cout << "[+] Decrypting file" << std::endl;
+ if (!decrypt_file(record, decrypted_fek, opts))
+ {
+ std::cout << "[-] Decrypted file written to " << opts->output << " (" << utils::format::size(record->datasize()) << ")" << std::endl;
+ }
+ else
+ {
+ std::cerr << "[!] Failed to decrypt the file using FEK" << std::endl;
+ return 6;
+ }
+ }
+ else
+ {
+ std::cerr << "[!] Failed to decrypt encrypted FEK" << std::endl;
+ return 5;
+ }
+ }
+ else
+ {
+ std::cout << "[-] Skipping field: " << i + 1 << " (cert/key not match)" << std::endl;
+ }
+
+ entry_header = POINTER_ADD(PMFT_RECORD_ATTRIBUTE_EFS_DATA_DECRYPTION_ENTRY_HEADER, entry_header, entry_header->Length);
+ i++;
+ }
+ }
+ else
+ {
+ std::cout << "[!] Empty data decryption field" << std::endl;
+ return 4;
+ }
+ }
+ }
+ else
+ {
+ std::cout << "[!] Unable to find $EFS stream in file" << std::endl;
+ return 3;
+ }
+ return 0;
+}
+
+
+namespace commands
+{
+ namespace efs
+ {
+ namespace decrypt
+ {
+ int dispatch(std::shared_ptr opts)
+ {
+ std::ios_base::fmtflags flag_backup(std::cout.flags());
+
+ std::shared_ptr disk = get_disk(opts);
+ if (disk != nullptr)
+ {
+ std::shared_ptr volume = disk->volumes(opts->volume);
+ if (volume != nullptr)
+ {
+ if (opts->pfx == "") invalid_option(opts, "pfx", opts->pfx);
+ if (opts->password == "") invalid_option(opts, "password", opts->password);
+
+ load_key_and_decrypt_file(disk, volume, opts);
+ }
+ else
+ {
+ invalid_option(opts, "volume", opts->volume);
+ }
+ }
+ else
+ {
+ invalid_option(opts, "disk", opts->disk);
+ }
+
+ std::cout.flags(flag_backup);
+ return 0;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sources/Commands/command_efs_key.cpp b/Sources/Commands/command_efs_key.cpp
index 015f628..cf18950 100644
--- a/Sources/Commands/command_efs_key.cpp
+++ b/Sources/Commands/command_efs_key.cpp
@@ -6,15 +6,9 @@
#include
#include
-const std::vector format = { "pem" };
-
int decrypt_key(std::shared_ptr disk, std::shared_ptr vol, std::shared_ptr opts)
{
- if ((vol->filesystem() != "NTFS") && (vol->filesystem() != "Bitlocker"))
- {
- std::cerr << "[!] NTFS volume required" << std::endl;
- return 1;
- }
+ if (!commands::helpers::is_ntfs(disk, vol)) return 1;
std::cout << std::setfill('0');
utils::ui::title("Decrypt key from " + disk->name() + " > Volume:" + std::to_string(vol->index()));
@@ -22,181 +16,144 @@ int decrypt_key(std::shared_ptr disk, std::shared_ptr vol, std::sh
std::cout << "[+] Opening " << (vol->name().empty() ? reinterpret_cast(vol->parent())->name() : vol->name()) << std::endl;
std::shared_ptr explorer = std::make_shared(vol);
+ std::shared_ptr key_file_record = commands::helpers::find_record(explorer, opts);
- std::shared_ptr key_file_record = nullptr;
-
- std::cout << "[+] Reading key file record: ";
- if (opts->from != "")
- {
- std::cout << opts->from << std::endl;
- key_file_record = explorer->mft()->record_from_path(opts->from);
- }
- else
+ auto data = key_file_record->data();
+ std::shared_ptr key_file = std::make_shared(data->data(), data->size());
+ if (!key_file->is_loaded())
{
- std::cout << opts->inode << std::endl;
- key_file_record = explorer->mft()->record_from_number(opts->inode);
+ std::cerr << "[!] Failed to parse key file from record: " << opts->inode << std::endl;
+ return 3;
}
- if (key_file_record == nullptr)
- {
- std::cerr << "[!] Err: Failed to read record: " << opts->inode << std::endl;
- return 2;
- }
- else
+ auto key = key_file->private_key();
+ if (key)
{
- auto data = key_file_record->data();
- std::shared_ptr key_file = std::make_shared(data->data(), data->size());
- if (!key_file->is_loaded())
+ std::cout << "[-] Key" << std::endl;
+ std::cout << " Encryption Algorithm : " << constants::efs::enc_algorithm(key->header()->EncryptionAlgorithm) << std::endl;
+ std::cout << " Hash Algorithm : " << constants::efs::hash_algorithm(key->header()->HashAlgorithm) << std::endl;
+ std::cout << " Salt : " << utils::convert::to_hex(key->salt()->data(), key->salt()->size()) << std::endl;
+
+ std::cout << "[+] Decrypting key" << std::endl;
+ std::shared_ptr res = key->decrypt_with_masterkey(opts->masterkey);
+ if (res == nullptr)
{
- std::cerr << "[!] Err: Failed to parse key file from record: " << opts->inode << std::endl;
- return 3;
+ std::cout << "[!] Failed to decrypt. Check masterkey." << std::endl;
}
-
- auto key = key_file->private_key();
- if (key)
+ else
{
- std::cout << "[-] Key" << std::endl;
- std::cout << " Encryption Algorithm : " << constants::efs::enc_algorithm(key->header()->EncryptionAlgorithm) << std::endl;
- std::cout << " Hash Algorithm : " << constants::efs::hash_algorithm(key->header()->HashAlgorithm) << std::endl;
- std::cout << " Salt : " << utils::convert::to_hex(key->salt()->data(), key->salt()->size()) << std::endl;
-
- std::cout << "[+] Decrypting key" << std::endl;
- std::shared_ptr res = key->decrypt_with_masterkey(opts->masterkey);
- if (res == nullptr)
- {
- std::cout << "[!] Failed to decrypt. Check masterkey." << std::endl;
- }
- else
+ if (opts->output != "")
{
- if (opts->output != "")
+ if (res->export_public_to_PEM(opts->output) == 0)
{
- if (opts->format == "")
- {
- opts->format = format[0];
- }
- else
- {
- opts->format = utils::strings::lower(opts->format);
- }
-
- if (std::find(format.begin(), format.end(), opts->format) == format.end())
- {
- std::cerr << "[!] Err: Invalid output format. (" << opts->format << ")" << std::endl;
- }
- else
- {
- if (res->export_public_to_PEM(opts->output) == 0)
- {
- std::cout << "[+] Public key exported to " << opts->output << ".pub.pem" << "." << std::endl;
- }
- else
- {
- std::cerr << "[!] Err: Unable to export the public key." << std::endl;
- }
- if (res->export_private_to_PEM(opts->output) == 0)
- {
- std::cout << "[+] Private key exported to " << opts->output << ".priv.pem" << "." << std::endl;
- }
- else
- {
- std::cerr << "[!] Err: Unable to export the private key." << std::endl;
- }
- }
+ std::cout << "[+] Public key exported to " << opts->output << ".pub.pem" << "." << std::endl;
}
else
{
+ std::cerr << "[!] Unable to export the public key." << std::endl;
+ }
+ if (res->export_private_to_PEM(opts->output) == 0)
+ {
+ std::cout << "[+] Private key exported to " << opts->output << ".priv.pem" << "." << std::endl;
+ }
+ else
+ {
+ std::cerr << "[!] Unable to export the private key." << std::endl;
+ }
+ }
+ else
+ {
+ std::cout << "[+] Clear key (" << res->header()->Bitsize << "bits):" << std::endl;
- std::cout << "[+] Clear key (" << res->header()->Bitsize << "bits):" << std::endl;
-
- std::shared_ptr tab = std::make_shared();
- tab->set_margin_left(4);
- tab->set_interline(true);
- tab->add_header_line("Id", utils::ui::TableAlign::RIGHT);
- tab->add_header_line("Property");
- tab->add_header_line("Value");
+ std::shared_ptr tab = std::make_shared();
+ tab->set_margin_left(4);
+ tab->set_interline(true);
+ tab->add_header_line("Id", utils::ui::TableAlign::RIGHT);
+ tab->add_header_line("Property");
+ tab->add_header_line("Value");
- int i = 0;
- tab->add_item_line(std::to_string(i++));
- tab->add_item_line("Magic");
- std::string magic_str = { ((char*)(&res->header()->Magic))[0],((char*)(&res->header()->Magic))[1],((char*)(&res->header()->Magic))[2],((char*)(&res->header()->Magic))[3] };
- tab->add_item_line(magic_str);
+ int i = 0;
+ tab->add_item_line(std::to_string(i++));
+ tab->add_item_line("Magic");
+ std::string magic_str = { ((char*)(&res->header()->Magic))[0],((char*)(&res->header()->Magic))[1],((char*)(&res->header()->Magic))[2],((char*)(&res->header()->Magic))[3] };
+ tab->add_item_line(magic_str);
- tab->new_line();
+ tab->new_line();
- tab->add_item_line(std::to_string(i++));
- tab->add_item_line("Bitsize");
- tab->add_item_line(std::to_string(res->header()->Bitsize));
+ tab->add_item_line(std::to_string(i++));
+ tab->add_item_line("Bitsize");
+ tab->add_item_line(std::to_string(res->header()->Bitsize));
- tab->new_line();
+ tab->new_line();
- tab->add_item_line(std::to_string(i++));
- tab->add_item_line("Permissions");
- tab->add_item_multiline(constants::efs::permissions(res->header()->Permissions));
+ tab->add_item_line(std::to_string(i++));
+ tab->add_item_line("Permissions");
+ tab->add_item_multiline(constants::efs::permissions(res->header()->Permissions));
- tab->new_line();
+ tab->new_line();
- tab->add_item_line(std::to_string(i++));
- tab->add_item_line("Exponent");
- tab->add_item_line(std::to_string(res->header()->Exponent));
+ tab->add_item_line(std::to_string(i++));
+ tab->add_item_line("Exponent");
+ tab->add_item_line(std::to_string(res->header()->Exponent));
- tab->new_line();
+ tab->new_line();
- tab->add_item_line(std::to_string(i++));
- tab->add_item_line("Modulus");
- tab->add_item_line(utils::convert::to_hex(res->modulus()->data(), res->modulus()->size()));
+ tab->add_item_line(std::to_string(i++));
+ tab->add_item_line("Modulus");
+ tab->add_item_line(utils::convert::to_hex(res->modulus()->data(), res->modulus()->size()));
- tab->new_line();
+ tab->new_line();
- tab->add_item_line(std::to_string(i++));
- tab->add_item_line("Prime1");
- tab->add_item_line(utils::convert::to_hex(res->prime1()->data(), res->prime1()->size()));
+ tab->add_item_line(std::to_string(i++));
+ tab->add_item_line("Prime1");
+ tab->add_item_line(utils::convert::to_hex(res->prime1()->data(), res->prime1()->size()));
- tab->new_line();
+ tab->new_line();
- tab->add_item_line(std::to_string(i++));
- tab->add_item_line("Prime2");
- tab->add_item_line(utils::convert::to_hex(res->prime2()->data(), res->prime2()->size()));
+ tab->add_item_line(std::to_string(i++));
+ tab->add_item_line("Prime2");
+ tab->add_item_line(utils::convert::to_hex(res->prime2()->data(), res->prime2()->size()));
- tab->new_line();
+ tab->new_line();
- tab->add_item_line(std::to_string(i++));
- tab->add_item_line("Exponent1");
- tab->add_item_line(utils::convert::to_hex(res->exponent1()->data(), res->exponent1()->size()));
+ tab->add_item_line(std::to_string(i++));
+ tab->add_item_line("Exponent1");
+ tab->add_item_line(utils::convert::to_hex(res->exponent1()->data(), res->exponent1()->size()));
- tab->new_line();
+ tab->new_line();
- tab->add_item_line(std::to_string(i++));
- tab->add_item_line("Exponent2");
- tab->add_item_line(utils::convert::to_hex(res->exponent2()->data(), res->exponent2()->size()));
+ tab->add_item_line(std::to_string(i++));
+ tab->add_item_line("Exponent2");
+ tab->add_item_line(utils::convert::to_hex(res->exponent2()->data(), res->exponent2()->size()));
- tab->new_line();
+ tab->new_line();
- tab->add_item_line(std::to_string(i++));
- tab->add_item_line("Coefficient");
- tab->add_item_line(utils::convert::to_hex(res->coefficient()->data(), res->coefficient()->size()));
+ tab->add_item_line(std::to_string(i++));
+ tab->add_item_line("Coefficient");
+ tab->add_item_line(utils::convert::to_hex(res->coefficient()->data(), res->coefficient()->size()));
- tab->new_line();
+ tab->new_line();
- tab->add_item_line(std::to_string(i++));
- tab->add_item_line("Private Exponent");
- tab->add_item_line(utils::convert::to_hex(res->private_exponent()->data(), res->private_exponent()->size()));
+ tab->add_item_line(std::to_string(i++));
+ tab->add_item_line("Private Exponent");
+ tab->add_item_line(utils::convert::to_hex(res->private_exponent()->data(), res->private_exponent()->size()));
- tab->new_line();
+ tab->new_line();
- tab->render(std::cout);
- }
+ tab->render(std::cout);
}
}
- else
- {
- std::cerr << "[!] Err: No key in specified file." << std::endl;
- return 3;
- }
-
- return 0;
}
+ else
+ {
+ std::cerr << "[!] No key in specified file." << std::endl;
+ return 3;
+ }
+
+ return 0;
}
+
std::vector print_encrypted_private_key(std::shared_ptr private_key)
{
std::vector cell =
@@ -237,11 +194,7 @@ std::vector print_encrypted_private_key(std::shared_ptr disk, std::shared_ptr vol, std::shared_ptr opts)
{
- if ((vol->filesystem() != "NTFS") && (vol->filesystem() != "Bitlocker"))
- {
- std::cerr << "[!] NTFS volume required" << std::endl;
- return 1;
- }
+ if (!commands::helpers::is_ntfs(disk, vol)) return 1;
std::cout << std::setfill('0');
utils::ui::title("Display key from " + disk->name() + " > Volume:" + std::to_string(vol->index()));
@@ -255,7 +208,7 @@ int show_key(std::shared_ptr disk, std::shared_ptr vol, std::share
std::shared_ptr key_file = std::make_shared(data->data(), data->size());
if (!key_file->is_loaded())
{
- std::cerr << "[!] Err: Failed to parse key file from record: " << opts->inode << std::endl;
+ std::cerr << "[!] Failed to parse key file from record: " << opts->inode << std::endl;
return 3;
}
@@ -396,11 +349,7 @@ int show_key(std::shared_ptr disk, std::shared_ptr vol, std::share
int list_keys(std::shared_ptr disk, std::shared_ptr vol, std::shared_ptr opts)
{
- if ((vol->filesystem() != "NTFS") && (vol->filesystem() != "Bitlocker"))
- {
- std::cerr << "[!] NTFS volume required" << std::endl;
- return 1;
- }
+ if (!commands::helpers::is_ntfs(disk, vol)) return 1;
std::cout << std::setfill('0');
utils::ui::title("List keys from " + disk->name() + " > Volume:" + std::to_string(vol->index()));
diff --git a/Sources/Commands/command_efs_masterkey.cpp b/Sources/Commands/command_efs_masterkey.cpp
index 2c5a400..b9b5700 100644
--- a/Sources/Commands/command_efs_masterkey.cpp
+++ b/Sources/Commands/command_efs_masterkey.cpp
@@ -7,11 +7,7 @@
int decrypt_masterkey(std::shared_ptr disk, std::shared_ptr vol, std::shared_ptr opts)
{
- if ((vol->filesystem() != "NTFS") && (vol->filesystem() != "Bitlocker"))
- {
- std::cerr << "[!] NTFS volume required" << std::endl;
- return 1;
- }
+ if (!commands::helpers::is_ntfs(disk, vol)) return 1;
std::cout << std::setfill('0');
utils::ui::title("Decrypt masterkey from " + disk->name() + " > Volume:" + std::to_string(vol->index()));
@@ -25,7 +21,7 @@ int decrypt_masterkey(std::shared_ptr disk, std::shared_ptr vol, s
std::shared_ptr masterkey_file = std::make_shared(data->data(), data->size());
if (!masterkey_file->is_loaded())
{
- std::cerr << "[!] Err: Failed to parse masterkey file from record: " << opts->inode << std::endl;
+ std::cerr << "[!] Failed to parse masterkey file from record: " << opts->inode << std::endl;
return 3;
}
@@ -57,7 +53,7 @@ int decrypt_masterkey(std::shared_ptr disk, std::shared_ptr vol, s
}
else
{
- std::cerr << "[!] Err: No masterkey in specified file." << std::endl;
+ std::cerr << "[!] No masterkey in specified file." << std::endl;
return 3;
}
@@ -67,11 +63,7 @@ int decrypt_masterkey(std::shared_ptr disk, std::shared_ptr vol, s
int show_masterkey(std::shared_ptr disk, std::shared_ptr vol, std::shared_ptr opts)
{
- if ((vol->filesystem() != "NTFS") && (vol->filesystem() != "Bitlocker"))
- {
- std::cerr << "[!] NTFS volume required" << std::endl;
- return 1;
- }
+ if (!commands::helpers::is_ntfs(disk, vol)) return 1;
std::cout << std::setfill('0');
utils::ui::title("Display masterkey from " + disk->name() + " > Volume:" + std::to_string(vol->index()));
@@ -85,7 +77,7 @@ int show_masterkey(std::shared_ptr disk, std::shared_ptr vol, std:
std::shared_ptr masterkey_file = std::make_shared(data->data(), data->size());
if (!masterkey_file->is_loaded())
{
- std::cerr << "[!] Err: Failed to parse masterkey file from record: " << opts->inode << std::endl;
+ std::cerr << "[!] Failed to parse masterkey file from record: " << opts->inode << std::endl;
return 3;
}
@@ -214,11 +206,7 @@ int show_masterkey(std::shared_ptr disk, std::shared_ptr vol, std:
int list_masterkeys(std::shared_ptr disk, std::shared_ptr vol, std::shared_ptr opts)
{
- if ((vol->filesystem() != "NTFS") && (vol->filesystem() != "Bitlocker"))
- {
- std::cerr << "[!] NTFS volume required" << std::endl;
- return 1;
- }
+ if (!commands::helpers::is_ntfs(disk, vol)) return 1;
std::cout << std::setfill('0');
utils::ui::title("List masterkeys from " + disk->name() + " > Volume:" + std::to_string(vol->index()));
diff --git a/Sources/Commands/command_extract.cpp b/Sources/Commands/command_extract.cpp
index 116358b..f8ca2fb 100644
--- a/Sources/Commands/command_extract.cpp
+++ b/Sources/Commands/command_extract.cpp
@@ -18,11 +18,7 @@
int extract_file(std::shared_ptr disk, std::shared_ptr vol, std::shared_ptr opts)
{
- if ((vol->filesystem() != "NTFS") && (vol->filesystem() != "Bitlocker"))
- {
- std::cerr << "[!] NTFS volume required" << std::endl;
- return 1;
- }
+ if (!commands::helpers::is_ntfs(disk, vol)) return 1;
std::cout << std::setfill('0');
utils::ui::title("Extract file from " + disk->name() + " > Volume:" + std::to_string(vol->index()));
diff --git a/Sources/Commands/command_help.cpp b/Sources/Commands/command_help.cpp
index 69e199c..3db13ea 100644
--- a/Sources/Commands/command_help.cpp
+++ b/Sources/Commands/command_help.cpp
@@ -9,7 +9,7 @@
#include
#include
-#define VERSION "1.35"
+#define VERSION "1.4"
void usage(const char* binname)
{
@@ -28,6 +28,7 @@ void usage(const char* binname)
std::cerr << " bitdecrypt : decrypt volume to an image file" << std::endl;
std::cerr << " fve : display FVE metadata" << std::endl;
std::cerr << " efs.backup : Export EFS keys from a volume" << std::endl;
+ std::cerr << " efs.decrypt : Decrypt EFS encrypted file from backup key" << std::endl;
std::cerr << " efs.certificate : list, display and export system certificates" << std::endl;
std::cerr << " efs.key : list, display, decrypt and export private keys" << std::endl;
std::cerr << " efs.masterkey : list, display and decrypt masterkeys" << std::endl;
@@ -181,6 +182,14 @@ void print_help_efs_backup(const char* name)
command_examples(name, "Export EFS keys for disk 1, volume 2 using password:123456", "efs.backup disk=1 volume=2 password=123456");
}
+void print_help_efs_decrypt(const char* name)
+{
+ command_header("efs.decrypt");
+ command_description(name, "efs.decrypt [disk id] [volume id] [inode|from] [pfx] [password] (output)", "Decrypt file from inode or path using pfx archive (protected by password) to output");
+ command_examples(name, "Decrypt EFS file inode:1234 for disk 1 and volume 2 using backup.pfx protected by password 123456 to mydecryptedfile",
+ "efs.decrypt disk=1 volume=2 inode=1234 pfx=backup.pfx password=123456 output=mydecryptedfile");
+}
+
void print_help_efs_key(const char* name)
{
command_header("efs.key");
@@ -188,7 +197,7 @@ void print_help_efs_key(const char* name)
command_examples(name, "List keys for disk 1, volume 2", "efs.key disk=1 volume=2");
command_examples(name, "Display a key for disk 1, volume 2 and inode 0x1337", "efs.key disk=1 volume=2 inode=0x1337");
command_examples(name, "Decrypt a key for inode 0x1337 with masterkey", "efs.key disk=1 volume=2 inode=0x1337 masterkey=DEADBEEF123...321");
- command_examples(name, "Export a key to mykey.pem (format in [pem])", "efs.key disk=1 volume=2 inode=0x1337 masterkey=DEADBEEF123...321 output=mykey format=pem");
+ command_examples(name, "Export a key to mykey.pem", "efs.key disk=1 volume=2 inode=0x1337 masterkey=DEADBEEF123...321 output=mykey");
}
void print_help_efs_certificate(const char* name)
@@ -197,7 +206,7 @@ void print_help_efs_certificate(const char* name)
command_description(name, "efs.certificate [disk id] [volume id] [inode|from] (output) (format)", "List and display certificate on a volume");
command_examples(name, "List certificates for disk 1, volume 2", "efs.certificate disk=1 volume=2");
command_examples(name, "Display a certificate for disk 1, volume 2 and inode 0x1337", "efs.certificate disk=1 volume=2 inode=0x1337");
- command_examples(name, "Export a certificate to mycert.pem (format in [pem])", "efs.certificate disk=1 volume=2 inode=0x1337 output=mycert format=pem");
+ command_examples(name, "Export a certificate to mycert.pem", "efs.certificate disk=1 volume=2 inode=0x1337 output=mycert");
}
void print_help_extract(const char* name)
@@ -291,10 +300,11 @@ namespace commands
if (opts->subcommand == "logfile") { print_help_logfile(name.c_str()); return; }
if (opts->subcommand == "reparse") { print_help_reparse(name.c_str()); return; }
if (opts->subcommand == "usn") { print_help_usn(name.c_str()); return; }
+ if (opts->subcommand == "efs.backup") { print_help_efs_backup(name.c_str()); return; }
if (opts->subcommand == "efs.certificate") { print_help_efs_certificate(name.c_str()); return; }
+ if (opts->subcommand == "efs.decrypt") { print_help_efs_decrypt(name.c_str()); return; }
if (opts->subcommand == "efs.key") { print_help_efs_key(name.c_str()); return; }
if (opts->subcommand == "efs.masterkey") { print_help_efs_masterkey(name.c_str()); return; }
- if (opts->subcommand == "efs.backup") { print_help_efs_backup(name.c_str()); return; }
if (opts->subcommand == "undelete") { print_help_undelete(name.c_str()); return; }
if (opts->subcommand == "shell") { print_help_shell(name.c_str()); return; }
if (opts->subcommand == "smart") { print_help_smart(name.c_str()); return; }
diff --git a/Sources/Commands/command_logfile.cpp b/Sources/Commands/command_logfile.cpp
index 127d069..4f06f32 100644
--- a/Sources/Commands/command_logfile.cpp
+++ b/Sources/Commands/command_logfile.cpp
@@ -118,12 +118,9 @@ void print_record_log(HANDLE outputfile, PRECORD_LOG rl, const std::string& form
if (!FAILED(SizeTToDWord(to_write.size(), &write_size))) WriteFile(outputfile, to_write.c_str(), write_size, &written, NULL);
}
-int print_logfile_records(std::shared_ptr disk, std::shared_ptr vol, const std::string& format, std::string output) {
- if ((vol->filesystem() != "NTFS") && (vol->filesystem() != "Bitlocker"))
- {
- std::cerr << "[!] NTFS volume required" << std::endl;
- return 1;
- }
+int print_logfile_records(std::shared_ptr disk, std::shared_ptr vol, const std::string& format, std::string output)
+{
+ if (!commands::helpers::is_ntfs(disk, vol)) return 1;
utils::ui::title("LogFile from " + disk->name() + " > Volume:" + std::to_string(vol->index()));
diff --git a/Sources/Commands/command_mft.cpp b/Sources/Commands/command_mft.cpp
index a26b8a8..b1def50 100644
--- a/Sources/Commands/command_mft.cpp
+++ b/Sources/Commands/command_mft.cpp
@@ -263,7 +263,7 @@ void print_efs_entry(std::vector& ret, PMFT_RECORD_ATTRIBUTE_EFS_AR
ret.push_back("");
if (entry->Type == MFT_ATTRIBUTE_EFS_CONTAINER)
{
-
+ ret.push_back("EFS Container not implemented");
}
else if (entry->Type == MFT_ATTRIBUTE_EFS_CERTIFICATE)
{
@@ -745,11 +745,7 @@ int commands::mft::print_mft_info_details(std::shared_ptr record, ULO
int print_mft_info(std::shared_ptr disk, std::shared_ptr vol, std::shared_ptr opts)
{
- if ((vol->filesystem() != "NTFS") && (vol->filesystem() != "Bitlocker"))
- {
- std::cerr << "[!] NTFS volume required" << std::endl;
- return 1;
- }
+ if (!commands::helpers::is_ntfs(disk, vol)) return 1;
std::shared_ptr explorer = std::make_shared(vol);
diff --git a/Sources/Commands/command_reparse.cpp b/Sources/Commands/command_reparse.cpp
index a637496..7656100 100644
--- a/Sources/Commands/command_reparse.cpp
+++ b/Sources/Commands/command_reparse.cpp
@@ -19,11 +19,7 @@
int print_reparse(std::shared_ptr disk, std::shared_ptr vol, const std::string& format, std::string output)
{
- if ((vol->filesystem() != "NTFS") && (vol->filesystem() != "Bitlocker"))
- {
- std::cerr << "[!] NTFS volume required" << std::endl;
- return 1;
- }
+ if (!commands::helpers::is_ntfs(disk, vol)) return 1;
utils::ui::title("Reparse points from " + disk->name() + " > Volume:" + std::to_string(vol->index()));
diff --git a/Sources/Commands/command_shadow.cpp b/Sources/Commands/command_shadow.cpp
index f4f080b..ffe7823 100644
--- a/Sources/Commands/command_shadow.cpp
+++ b/Sources/Commands/command_shadow.cpp
@@ -18,12 +18,9 @@
#include
-int print_volumeshadow(std::shared_ptr disk, std::shared_ptr vol) {
- if ((vol->filesystem() != "NTFS") && (vol->filesystem() != "Bitlocker"))
- {
- std::cerr << "[!] NTFS volume required" << std::endl;
- return 1;
- }
+int print_volumeshadow(std::shared_ptr disk, std::shared_ptr vol)
+{
+ if (!commands::helpers::is_ntfs(disk, vol)) return 1;
std::cout << std::setfill('0');
utils::ui::title("Volume Shadow from " + disk->name() + " > Volume:" + std::to_string(vol->index()));
diff --git a/Sources/Commands/command_shell.cpp b/Sources/Commands/command_shell.cpp
index d6967e1..aa1bac9 100644
--- a/Sources/Commands/command_shell.cpp
+++ b/Sources/Commands/command_shell.cpp
@@ -79,11 +79,8 @@ std::string clean_disk_name(std::shared_ptr disk)
int explorer(std::shared_ptr disk, std::shared_ptr vol)
{
- if ((vol->filesystem() != "NTFS") && (vol->filesystem() != "Bitlocker"))
- {
- std::cerr << "[!] NTFS volume required" << std::endl;
- return 1;
- }
+ if (!commands::helpers::is_ntfs(disk, vol)) return 1;
+
std::shared_ptr explorer = std::make_shared(vol);
std::shared_ptr current_dir_record = explorer->mft()->record_from_number(ROOT_FILE_NAME_INDEX_NUMBER);
std::string current_dir = "\\";
diff --git a/Sources/Commands/command_streams.cpp b/Sources/Commands/command_streams.cpp
index b1d0b00..9b9305f 100644
--- a/Sources/Commands/command_streams.cpp
+++ b/Sources/Commands/command_streams.cpp
@@ -18,11 +18,7 @@
int list_streams(std::shared_ptr disk, std::shared_ptr vol, std::shared_ptr opts)
{
- if ((vol->filesystem() != "NTFS") && (vol->filesystem() != "Bitlocker"))
- {
- std::cerr << "[!] NTFS volume required" << std::endl;
- return 1;
- }
+ if (!commands::helpers::is_ntfs(disk, vol)) return 1;
std::cout << std::setfill('0');
utils::ui::title("Listing streams from " + disk->name() + " > Volume:" + std::to_string(vol->index()));
diff --git a/Sources/Commands/command_undelete.cpp b/Sources/Commands/command_undelete.cpp
index 4790311..c710200 100644
--- a/Sources/Commands/command_undelete.cpp
+++ b/Sources/Commands/command_undelete.cpp
@@ -15,6 +15,7 @@
#include "Utils/utils.h"
#include "Utils/constant_names.h"
#include "Utils/table.h"
+#include
bool valid_record(PMFT_RECORD_HEADER ph)
{
@@ -257,11 +258,7 @@ int print_deleted_files(std::shared_ptr disk, std::shared_ptr vol,
int extract_deleted_file(std::shared_ptr disk, std::shared_ptr vol, std::shared_ptr opts)
{
- if ((vol->filesystem() != "NTFS") && (vol->filesystem() != "Bitlocker"))
- {
- std::cerr << "[!] NTFS volume required" << std::endl;
- return 1;
- }
+ if (!commands::helpers::is_ntfs(disk, vol)) return 1;
std::cout << std::setfill('0');
utils::ui::title("Extract deleted file from " + disk->name() + " > Volume:" + std::to_string(vol->index()));
diff --git a/Sources/Commands/command_usn.cpp b/Sources/Commands/command_usn.cpp
index 0fa88b6..a4a0c6e 100644
--- a/Sources/Commands/command_usn.cpp
+++ b/Sources/Commands/command_usn.cpp
@@ -16,12 +16,9 @@
#include
#include
-int print_usn_journal(std::shared_ptr disk, std::shared_ptr vol, const std::string& format, std::string output) {
- if ((vol->filesystem() != "NTFS") && (vol->filesystem() != "Bitlocker"))
- {
- std::cerr << "[!] NTFS volume required" << std::endl;
- return 1;
- }
+int print_usn_journal(std::shared_ptr disk, std::shared_ptr vol, const std::string& format, std::string output)
+{
+ if (!commands::helpers::is_ntfs(disk, vol)) return 1;
std::cout << std::setfill('0');
utils::ui::title("USN Journals from " + disk->name() + " > Volume:" + std::to_string(vol->index()));
diff --git a/Sources/Commands/commands.cpp b/Sources/Commands/commands.cpp
index 18544a7..db59840 100644
--- a/Sources/Commands/commands.cpp
+++ b/Sources/Commands/commands.cpp
@@ -2,6 +2,16 @@
#include "Utils/utils.h"
+int commands::helpers::is_ntfs(std::shared_ptr disk, std::shared_ptr vol)
+{
+ if ((vol->filesystem() != "NTFS") && (vol->filesystem() != "Bitlocker"))
+ {
+ std::cerr << "[!] NTFS volume required" << std::endl;
+ return 0;
+ }
+ return 1;
+}
+
std::shared_ptr commands::helpers::find_record(std::shared_ptr ex, std::shared_ptr opts)
{
std::shared_ptr rec = nullptr;
@@ -25,5 +35,7 @@ std::shared_ptr commands::helpers::find_record(std::shared_ptrheader()->MFTRecordIndex << std::endl;
+
return rec;
}
\ No newline at end of file
diff --git a/Sources/Commands/commands.h b/Sources/Commands/commands.h
index 5b4f068..281c180 100644
--- a/Sources/Commands/commands.h
+++ b/Sources/Commands/commands.h
@@ -13,6 +13,8 @@ namespace commands {
namespace helpers
{
+ int is_ntfs(std::shared_ptr disk, std::shared_ptr vol);
+
std::shared_ptr find_record(std::shared_ptr ex, std::shared_ptr opts);
}
@@ -39,6 +41,10 @@ namespace commands {
{
int dispatch(std::shared_ptr opts);
}
+ namespace decrypt
+ {
+ int dispatch(std::shared_ptr opts);
+ }
}
namespace mbr
diff --git a/Sources/EFS/certificate_file.cpp b/Sources/EFS/certificate_file.cpp
index 3ed061a..2b572eb 100644
--- a/Sources/EFS/certificate_file.cpp
+++ b/Sources/EFS/certificate_file.cpp
@@ -54,6 +54,7 @@ CertificateFile::CertificateFile(PBYTE data, DWORD size)
int CertificateFile::export_to_PEM(std::string name)
{
+ int ret = 1;
for (auto element : _fields)
{
DWORD prop_id = std::get<0>(element);
@@ -64,25 +65,28 @@ int CertificateFile::export_to_PEM(std::string name)
X509* x = d2i_X509(NULL, &bufder, std::get<1>(element)->size());
if (x)
{
- FILE* fp = nullptr;
- fopen_s(&fp, (name + ".pem").c_str(), "wb");
- if (!fp)
+ BIO* out = BIO_new_file((name + ".pem").c_str(), "wb");
+ if (out)
{
- return 1;
+ if (!PEM_write_bio_X509(out, x))
+ {
+ ret = 3;
+ }
+ else
+ {
+ ret = 0;
+ }
+ BIO_free(out);
}
else
{
- if (!PEM_write_X509(fp, x))
- {
- return 2;
- }
- fclose(fp);
+ ret = 2;
}
X509_free(x);
}
}
}
- return 0;
+ return ret;
}
X509* CertificateFile::export_to_X509()
diff --git a/Sources/EFS/fek.h b/Sources/EFS/fek.h
new file mode 100644
index 0000000..605b9ff
--- /dev/null
+++ b/Sources/EFS/fek.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include
+#include
+
+#pragma pack(push, 1)
+
+typedef struct {
+ DWORD KeyLength;
+ DWORD Entropy;
+ ALG_ID Algorithm;
+ DWORD Reserved;
+ BYTE Key[1];
+} EFS_FEK, * PEFS_FEK;
+
+#pragma pack(pop)
diff --git a/Sources/EFS/pkcs12_archive.cpp b/Sources/EFS/pkcs12_archive.cpp
new file mode 100644
index 0000000..d06827c
--- /dev/null
+++ b/Sources/EFS/pkcs12_archive.cpp
@@ -0,0 +1,295 @@
+#include "EFS/pkcs12_archive.h"
+
+int parse_bag(PKCS12_SAFEBAG* bag, const char* pass, int passlen,
+ EVP_PKEY** pkey, STACK_OF(X509)* ocerts);
+
+int parse_bags(const STACK_OF(PKCS12_SAFEBAG)* bags, const char* pass,
+ int passlen, EVP_PKEY** pkey, STACK_OF(X509)* ocerts);
+
+int parse_pk12(PKCS12* p12, const char* pass, int passlen,
+ EVP_PKEY** pkey, STACK_OF(X509)* ocerts);
+
+PKCS12Archive::PKCS12Archive(std::shared_ptr cert, std::shared_ptr private_key)
+{
+ _cert = _build_x509_cert(cert);
+ _key = _build_evp_key(private_key);
+}
+
+int parse_bag(PKCS12_SAFEBAG* bag, const char* pass, int passlen,
+ EVP_PKEY** pkey, STACK_OF(X509)* ocerts)
+{
+ PKCS8_PRIV_KEY_INFO* p8;
+ X509* x509;
+ const ASN1_TYPE* attrib;
+ ASN1_BMPSTRING* fname = NULL;
+ ASN1_OCTET_STRING* lkid = NULL;
+
+ if ((attrib = PKCS12_SAFEBAG_get0_attr(bag, NID_friendlyName)))
+ fname = attrib->value.bmpstring;
+
+ if ((attrib = PKCS12_SAFEBAG_get0_attr(bag, NID_localKeyID)))
+ lkid = attrib->value.octet_string;
+
+ switch (PKCS12_SAFEBAG_get_nid(bag)) {
+ case NID_keyBag:
+ if (pkey == NULL || *pkey != NULL)
+ return 1;
+ *pkey = EVP_PKCS82PKEY(PKCS12_SAFEBAG_get0_p8inf(bag));
+ if (*pkey == NULL)
+ return 0;
+ break;
+
+ case NID_pkcs8ShroudedKeyBag:
+ if (pkey == NULL || *pkey != NULL)
+ return 1;
+ if ((p8 = PKCS12_decrypt_skey(bag, pass, passlen)) == NULL)
+ return 0;
+ *pkey = EVP_PKCS82PKEY(p8);
+ PKCS8_PRIV_KEY_INFO_free(p8);
+ if (!(*pkey))
+ return 0;
+ break;
+
+ case NID_certBag:
+ if (ocerts == NULL
+ || PKCS12_SAFEBAG_get_bag_nid(bag) != NID_x509Certificate)
+ return 1;
+ if ((x509 = PKCS12_SAFEBAG_get1_cert(bag)) == NULL)
+ return 0;
+ if (lkid && !X509_keyid_set1(x509, lkid->data, lkid->length)) {
+ X509_free(x509);
+ return 0;
+ }
+ if (fname) {
+ int len, r;
+ unsigned char* data;
+
+ len = ASN1_STRING_to_UTF8(&data, fname);
+ if (len >= 0) {
+ r = X509_alias_set1(x509, data, len);
+ OPENSSL_free(data);
+ if (!r) {
+ X509_free(x509);
+ return 0;
+ }
+ }
+ }
+
+ if (!sk_X509_push(ocerts, x509)) {
+ X509_free(x509);
+ return 0;
+ }
+
+ break;
+
+ case NID_safeContentsBag:
+ return parse_bags(PKCS12_SAFEBAG_get0_safes(bag), pass, passlen, pkey,
+ ocerts);
+
+ default:
+ return 1;
+ }
+ return 1;
+}
+
+int parse_bags(const STACK_OF(PKCS12_SAFEBAG)* bags, const char* pass,
+ int passlen, EVP_PKEY** pkey, STACK_OF(X509)* ocerts)
+{
+ int i;
+ for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) {
+ if (!parse_bag(sk_PKCS12_SAFEBAG_value(bags, i),
+ pass, passlen, pkey, ocerts))
+ return 0;
+ }
+ return 1;
+}
+
+int parse_pk12(PKCS12* p12, const char* pass, int passlen,
+ EVP_PKEY** pkey, STACK_OF(X509)* ocerts)
+{
+ STACK_OF(PKCS7)* asafes;
+ STACK_OF(PKCS12_SAFEBAG)* bags;
+ int i, bagnid;
+ PKCS7* p7;
+
+ if ((asafes = PKCS12_unpack_authsafes(p12)) == NULL)
+ return 0;
+ for (i = 0; i < sk_PKCS7_num(asafes); i++) {
+ p7 = sk_PKCS7_value(asafes, i);
+ bagnid = OBJ_obj2nid(p7->type);
+ if (bagnid == NID_pkcs7_data) {
+ bags = PKCS12_unpack_p7data(p7);
+ }
+ else if (bagnid == NID_pkcs7_encrypted) {
+ bags = PKCS12_unpack_p7encdata(p7, pass, passlen);
+ }
+ else
+ continue;
+ if (!bags) {
+ sk_PKCS7_pop_free(asafes, PKCS7_free);
+ return 0;
+ }
+ if (!parse_bags(bags, pass, passlen, pkey, ocerts)) {
+ sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
+ sk_PKCS7_pop_free(asafes, PKCS7_free);
+ return 0;
+ }
+ sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
+ }
+ sk_PKCS7_pop_free(asafes, PKCS7_free);
+ return 1;
+}
+
+EVP_PKEY* PKCS12Archive::_build_evp_key(std::shared_ptr privatekey_file)
+{
+ if (privatekey_file)
+ {
+ EVP_PKEY* key = EVP_PKEY_new();
+ RSA* rsa_key = privatekey_file->export_private_to_RSA();
+ if (rsa_key)
+ {
+ if (EVP_PKEY_assign_RSA(key, rsa_key))
+ {
+ EVP_PKEY_add1_attr_by_NID(key, NID_ms_csp_name, MBSTRING_ASC, (const unsigned char*)"Microsoft Enhanced Cryptographic Provider v1.0", -1);
+ return key;
+ }
+ }
+ if (key)
+ {
+ EVP_PKEY_free(key);
+ }
+ }
+ return nullptr;
+}
+
+X509* PKCS12Archive::_build_x509_cert(std::shared_ptr certfile)
+{
+ if (certfile)
+ {
+ X509* cert = certfile->export_to_X509();
+ if (cert)
+ {
+ return cert;
+ }
+ }
+ return nullptr;
+}
+
+PKCS12Archive::PKCS12Archive(std::string filename, std::string password)
+{
+ bool err = true;
+
+ PKCS12* p12 = NULL;
+ BIO* in = BIO_new_file(filename.c_str(), "rb");
+ if (in)
+ {
+ p12 = d2i_PKCS12_bio(in, &p12);
+ if (p12)
+ {
+ STACK_OF(X509)* _ca = sk_X509_new_null();
+ STACK_OF(X509)* ocerts = sk_X509_new_null();
+ if (parse_pk12(p12, password.c_str(), static_cast(password.size()), &_key, ocerts))
+ {
+ X509* x = NULL;
+ while ((x = sk_X509_shift(ocerts)) != NULL)
+ {
+ if (_key != NULL && _cert == NULL)
+ {
+ if (X509_check_private_key(x, _key))
+ {
+ _cert = x;
+ continue;
+ }
+ }
+ }
+ if (_ca)
+ {
+ sk_X509_push(_ca, x);
+ }
+ sk_X509_free(ocerts);
+
+ err = false;
+ }
+ PKCS12_free(p12);
+ }
+
+ BIO_free(in);
+ }
+
+ if (err)
+ {
+ if (_key)
+ {
+ EVP_PKEY_free(_key);
+ _key = nullptr;
+ }
+ if (_cert)
+ {
+ X509_free(_cert);
+ _cert = nullptr;
+ }
+ if (_ca_chain)
+ {
+ sk_X509_free(_ca_chain);
+ _ca_chain = nullptr;
+ }
+ }
+}
+
+int PKCS12Archive::export_to_pfx(std::string filename, std::string password)
+{
+ int err = 0;
+
+ if (_cert && _key)
+ {
+ if (X509_check_private_key(_cert, _key))
+ {
+ X509_keyid_set1(_cert, NULL, 0);
+ X509_alias_set1(_cert, NULL, 0);
+
+ PKCS12* p12 = PKCS12_create(password.c_str(), NULL, _key, _cert, sk_X509_new_null(), NID_undef, NID_undef, 0, -1, KEY_EX);
+ if (p12)
+ {
+ BIO* out = BIO_new_file(filename.c_str(), "wb");
+ if (out)
+ {
+ i2d_PKCS12_bio(out, p12);
+ BIO_free(out);
+ }
+ else
+ {
+ err = 4;
+ }
+ PKCS12_free(p12);
+ }
+ else
+ {
+ err = 3;
+ }
+ }
+ else
+ {
+ err = 2;
+ }
+ }
+ else
+ {
+ err = 1;
+ }
+
+ return err;
+}
+
+std::string PKCS12Archive::certificate_hash()
+{
+ if (_cert)
+ {
+ unsigned int fprint_size;
+ auto fprint_type = EVP_sha1();
+ unsigned char fprint[EVP_MAX_MD_SIZE];
+
+ X509_digest(_cert, fprint_type, fprint, &fprint_size);
+ return utils::strings::lower(utils::convert::to_hex(fprint, fprint_size));
+ }
+ return "";
+}
diff --git a/Sources/EFS/pkcs12_archive.h b/Sources/EFS/pkcs12_archive.h
new file mode 100644
index 0000000..f71ae53
--- /dev/null
+++ b/Sources/EFS/pkcs12_archive.h
@@ -0,0 +1,38 @@
+#pragma once
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+
+class PKCS12Archive
+{
+private:
+ EVP_PKEY* _key = nullptr;
+ X509* _cert = nullptr;
+ STACK_OF(X509)* _ca_chain = nullptr;
+
+ EVP_PKEY* _build_evp_key(std::shared_ptr privatekey_file);
+
+ X509* _build_x509_cert(std::shared_ptr certfile);
+
+public:
+ explicit PKCS12Archive(std::shared_ptr cert, std::shared_ptr private_key);
+
+ PKCS12Archive(std::string filename, std::string password);
+
+ int export_to_pfx(std::string filename, std::string password);
+
+ std::string certificate_hash();
+
+ X509* certificate() { return _cert; }
+
+ EVP_PKEY* key() { return _key; }
+
+ STACK_OF(X509)* certs_chain() { return _ca_chain; }
+};
\ No newline at end of file
diff --git a/Sources/EFS/pkcs12_backup.h b/Sources/EFS/pkcs12_backup.h
deleted file mode 100644
index 3a5e88d..0000000
--- a/Sources/EFS/pkcs12_backup.h
+++ /dev/null
@@ -1,111 +0,0 @@
-
-#include
-#include
-
-
-#include
-#include
-
-class PKCS12Backup
-{
-private:
- std::shared_ptr _cert = nullptr;
- std::shared_ptr _private_key = nullptr;
-
- EVP_PKEY* _build_evp_key()
- {
- if (_private_key)
- {
- EVP_PKEY* key = EVP_PKEY_new();
- RSA* rsa_key = _private_key->export_private_to_RSA();
- if (rsa_key)
- {
- if (EVP_PKEY_assign_RSA(key, rsa_key))
- {
- EVP_PKEY_add1_attr_by_NID(key, NID_ms_csp_name, MBSTRING_ASC, (const unsigned char*)"Microsoft Enhanced Cryptographic Provider v1.0", -1);
- return key;
- }
- }
- if (key)
- {
- EVP_PKEY_free(key);
- }
- }
- return nullptr;
- }
-
- X509* _build_x509_cert()
- {
- if (_cert)
- {
- X509* cert = _cert->export_to_X509();
- if (cert)
- {
- return cert;
- }
- }
- return nullptr;
- }
-
-public:
- PKCS12Backup(std::shared_ptr cert, std::shared_ptr private_key)
- {
- _cert = cert;
- _private_key = private_key;
- }
-
- int export_to_pfx(std::string filename, std::string password)
- {
- int err = 0;
-
- if (_cert && _private_key)
- {
- X509* cert = _build_x509_cert();
- if (cert)
- {
- EVP_PKEY* key = _build_evp_key();
- if (key)
- {
- if (X509_check_private_key(cert, key))
- {
- X509_keyid_set1(cert, NULL, 0);
- X509_alias_set1(cert, NULL, 0);
-
- PKCS12* p12 = PKCS12_create(password.c_str(), NULL, key, cert, sk_X509_new_null(), NID_undef, NID_undef, 0, -1, KEY_EX);
- if (p12)
- {
- BIO* out = BIO_new_file(filename.c_str(), "wb");
- if (out)
- {
- i2d_PKCS12_bio(out, p12);
- BIO_free(out);
- }
- else
- {
- err = 4;
- }
- PKCS12_free(p12);
- }
- else
- {
- err = 3;
- }
- }
- else
- {
- err = 2;
- }
-
- EVP_PKEY_free(key);
- }
- X509_free(cert);
- }
- }
- else
- {
- err = 1;
- }
-
- return err;
- }
-};
\ No newline at end of file
diff --git a/Sources/EFS/private_key.cpp b/Sources/EFS/private_key.cpp
index 2554fa9..72f8dff 100644
--- a/Sources/EFS/private_key.cpp
+++ b/Sources/EFS/private_key.cpp
@@ -38,8 +38,9 @@ PrivateKey::PrivateKey(PBYTE data, DWORD size)
int PrivateKey::export_private_to_PEM(std::string filename)
{
- RSA* rsa = RSA_new();
+ int ret = 1;
+ RSA* rsa = RSA_new();
if (rsa != nullptr)
{
BIGNUM* p, * q, * n, * e, * d, * dmp1, * dmq1, * iqmp;
@@ -67,33 +68,33 @@ int PrivateKey::export_private_to_PEM(std::string filename)
RSA_set0_key(rsa, n, e, d);
RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp);
- FILE* fp = nullptr;
- fopen_s(&fp, (filename + ".priv.pem").c_str(), "wb");
- if (!fp)
+ BIO* out = BIO_new_file((filename + ".priv.pem").c_str(), "wb");
+ if (out)
{
- return 1;
+ if (!PEM_write_bio_RSAPrivateKey(out, rsa, nullptr, nullptr, 0, nullptr, nullptr))
+ {
+ ret = 3;
+ }
+ else
+ {
+ ret = 0;
+ }
+ BIO_free(out);
}
else
{
- if (!PEM_write_RSAPrivateKey(fp, rsa, nullptr, nullptr, 0, nullptr, nullptr))
- {
- return 2;
- }
- fclose(fp);
+ ret = 2;
}
RSA_free(rsa);
}
- else
- {
- return 3;
- }
- return 0;
+ return ret;
}
int PrivateKey::export_public_to_PEM(std::string filename)
{
- RSA* rsa = RSA_new();
+ int ret = 1;
+ RSA* rsa = RSA_new();
if (rsa != nullptr)
{
BIGNUM* n, * e;
@@ -107,27 +108,27 @@ int PrivateKey::export_public_to_PEM(std::string filename)
RSA_set0_key(rsa, n, e, nullptr);
- FILE* fp = nullptr;
- fopen_s(&fp, (filename + ".pub.pem").c_str(), "wb");
- if (!fp)
+ BIO* out = BIO_new_file((filename + ".pub.pem").c_str(), "wb");
+ if (out)
{
- return 1;
+ if (!PEM_write_bio_RSA_PUBKEY(out, rsa))
+ {
+ ret = 3;
+ }
+ else
+ {
+ ret = 0;
+ }
+ BIO_free(out);
}
else
{
- if (!PEM_write_RSA_PUBKEY(fp, rsa))
- {
- return 2;
- }
- fclose(fp);
+ ret = 2;
}
RSA_free(rsa);
}
- else
- {
- return 3;
- }
- return 0;
+
+ return ret;
}
RSA* PrivateKey::export_private_to_RSA()
diff --git a/Sources/EFS/public_key.cpp b/Sources/EFS/public_key.cpp
index 74ee7c7..78e090f 100644
--- a/Sources/EFS/public_key.cpp
+++ b/Sources/EFS/public_key.cpp
@@ -13,6 +13,8 @@ PublicKey::PublicKey(PBYTE data, DWORD size)
int PublicKey::export_to_PEM(std::string filename)
{
+ int ret = 1;
+
RSA* rsa = RSA_new();
BIGNUM* n, * e;
@@ -27,25 +29,25 @@ int PublicKey::export_to_PEM(std::string filename)
RSA_set0_key(rsa, n, e, 0);
- FILE* fp = nullptr;
- fopen_s(&fp, (filename + ".pub.pem").c_str(), "wb");
- if (!fp)
+ BIO* out = BIO_new_file((filename + ".pub.pem").c_str(), "wb");
+ if (out)
{
- return 1;
+ if (!PEM_write_bio_RSA_PUBKEY(out, rsa))
+ {
+ ret = 3;
+ }
+ else
+ {
+ ret = 0;
+ }
+ BIO_free(out);
}
else
{
- if (!PEM_write_RSA_PUBKEY(fp, rsa))
- {
- return 2;
- }
- fclose(fp);
+ ret = 2;
}
RSA_free(rsa);
}
- else
- {
- return 3;
- }
- return 0;
+
+ return ret;
}
diff --git a/Sources/NTFS/ntfs.h b/Sources/NTFS/ntfs.h
index 968020a..7803238 100644
--- a/Sources/NTFS/ntfs.h
+++ b/Sources/NTFS/ntfs.h
@@ -541,7 +541,6 @@ typedef struct {
struct {
DWORD cert_thumbprint_header_size;
DWORD cert_thumbprint_header_offset;
-
};
};
} MFT_RECORD_ATTRIBUTE_EFS_DATA_DECRYPTION_ENTRY, * PMFT_RECORD_ATTRIBUTE_EFS_DATA_DECRYPTION_ENTRY;
diff --git a/Sources/NTFS/ntfs_mft.cpp b/Sources/NTFS/ntfs_mft.cpp
index 94ae697..edb3145 100644
--- a/Sources/NTFS/ntfs_mft.cpp
+++ b/Sources/NTFS/ntfs_mft.cpp
@@ -111,14 +111,14 @@ std::shared_ptr MFT::record_from_number(ULONG64 record_number)
}
if (offset == -1LL)
{
- wprintf(L"Err: Unable to find record offset for inode 0x%08llx", record_number);
+ wprintf(L"Failed to find record offset for inode 0x%08llx", record_number);
return nullptr;
}
_reader->seek(offset);
if (!_reader->read(buffer->address() + sector * _reader->boot_record()->bytePerSector, _reader->boot_record()->bytePerSector))
{
- wprintf(L"Err: Reading record at offset 0x%08llx failed", offset);
+ wprintf(L"Failed to read record at offset 0x%08llx", offset);
return nullptr;
}
}
diff --git a/Sources/NTFS/ntfs_mft_record.cpp b/Sources/NTFS/ntfs_mft_record.cpp
index 351bd84..ae78e5b 100644
--- a/Sources/NTFS/ntfs_mft_record.cpp
+++ b/Sources/NTFS/ntfs_mft_record.cpp
@@ -51,7 +51,7 @@ uint64_t MFTRecord::raw_address(PMFT_RECORD_ATTRIBUTE_HEADER pAttr, uint64_t off
return 0;
}
-ULONG64 MFTRecord::datasize(std::string stream_name)
+ULONG64 MFTRecord::datasize(std::string stream_name, bool real_size)
{
if (_record->data()->flag & FILE_RECORD_FLAG_DIR)
{
@@ -67,7 +67,8 @@ ULONG64 MFTRecord::datasize(std::string stream_name)
}
else
{
- return pAttribute->Form.Nonresident.FileSize;
+ if (real_size) return pAttribute->Form.Nonresident.FileSize;
+ else return pAttribute->Form.Nonresident.AllocatedLength;
}
}
else
@@ -93,7 +94,7 @@ ULONG64 MFTRecord::datasize(std::string stream_name)
std::shared_ptr extRecordHeader = _mft->record_from_number(pAttr->recordNumber & 0xffffffffffff);
if (extRecordHeader != nullptr)
{
- return extRecordHeader->datasize();
+ return extRecordHeader->datasize(stream_name, real_size);
}
else
{
@@ -283,68 +284,6 @@ std::vector> MFTRecord::index()
return ret;
}
-template
-std::shared_ptr> MFTRecord::attribute_data(PMFT_RECORD_ATTRIBUTE_HEADER pAttributeData)
-{
- std::shared_ptr> ret = nullptr;
-
- if (pAttributeData->FormCode == RESIDENT_FORM)
- {
- ret = std::make_shared>(pAttributeData->Form.Resident.ValueLength);
- memcpy_s(ret->data(), ret->size(), POINTER_ADD(LPBYTE, pAttributeData, pAttributeData->Form.Resident.ValueOffset), pAttributeData->Form.Resident.ValueLength);
- }
- else if (pAttributeData->FormCode == NON_RESIDENT_FORM)
- {
- ULONGLONG readSize = 0;
- ULONGLONG filesize = pAttributeData->Form.Nonresident.FileSize;
-
- ret = std::make_shared>(pAttributeData->Form.Nonresident.AllocatedLength);
-
- bool err = false;
-
- std::vector runList = read_dataruns(pAttributeData);
- for (const MFT_DATARUN& run : runList)
- {
- if (err) break; //-V547
-
- if (run.offset == 0)
- {
- for (ULONGLONG i = 0; i < run.length; i++)
- {
- readSize += min(filesize - readSize, _reader->sizes.cluster_size);
- }
- }
- else
- {
- _reader->seek(run.offset * _reader->sizes.cluster_size);
-
- if (!_reader->read(POINTER_ADD(PBYTE, ret->data(), DWORD(readSize)), static_cast(run.length) * _reader->sizes.cluster_size))
- {
- std::cout << "[!] ReadFile failed" << std::endl;
- err = true;
- break;
- }
- else
- {
- readSize += min(filesize - readSize, static_cast(run.length) * _reader->sizes.cluster_size);
- }
- }
- }
- if (readSize != filesize)
- {
-
- std::cout << "[!] Invalid read file size" << std::endl;
- ret = nullptr;
- }
- else
- {
- ret->shrink(static_cast(filesize));
- }
- }
-
- return ret;
-}
-
std::vector MFTRecord::read_dataruns(PMFT_RECORD_ATTRIBUTE_HEADER pAttribute)
{
std::vector result;
@@ -429,14 +368,14 @@ PMFT_RECORD_ATTRIBUTE_HEADER MFTRecord::attribute_header(DWORD type, std::string
return nullptr;
}
-ULONG64 MFTRecord::data_to_file(std::wstring dest_filename, std::string stream_name)
+ULONG64 MFTRecord::data_to_file(std::wstring dest_filename, std::string stream_name, bool real_size)
{
ULONG64 written_bytes = 0ULL;
HANDLE output = CreateFileW(dest_filename.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
if (output != INVALID_HANDLE_VALUE)
{
- for (auto data_block : process_data(stream_name))
+ for (auto data_block : process_data(stream_name, real_size))
{
DWORD written_block;
if (!WriteFile(output, data_block.first, data_block.second, &written_block, NULL))
@@ -458,7 +397,7 @@ ULONG64 MFTRecord::data_to_file(std::wstring dest_filename, std::string stream_n
return written_bytes;
}
-cppcoro::generator> MFTRecord::process_data(std::string stream_name, DWORD block_size)
+cppcoro::generator> MFTRecord::process_data(std::string stream_name, DWORD block_size, bool real_size)
{
PMFT_RECORD_ATTRIBUTE_HEADER pAttributeData = attribute_header($DATA, stream_name);
if (pAttributeData != NULL)
@@ -471,7 +410,10 @@ cppcoro::generator> MFTRecord::process_data(std::string
if (pAttributeData->Form.Resident.ValueOffset + pAttributeData->Form.Resident.ValueLength <= pAttributeData->RecordLength)
{
PBYTE data = POINTER_ADD(PBYTE, pAttributeData, pAttributeData->Form.Resident.ValueOffset);
- co_yield std::pair(data, pAttributeData->Form.Resident.ValueLength);
+ for (DWORD offset = 0; offset < pAttributeData->Form.Resident.ValueLength; offset += block_size)
+ {
+ co_yield std::pair(data + offset, min(block_size, pAttributeData->Form.Resident.ValueLength - offset));
+ }
}
else
{
@@ -567,7 +509,7 @@ cppcoro::generator> MFTRecord::process_data(std::string
}
}
}
- else if (pAttributeData->FormCode == NON_RESIDENT_FORM)
+ else
{
Buffer buffer(block_size);
@@ -599,7 +541,7 @@ cppcoro::generator> MFTRecord::process_data(std::string
break;
}
fixed_blocksize = DWORD(min(pAttributeData->Form.Nonresident.FileSize - writeSize, block_size));
- co_yield std::pair(buffer.data(), fixed_blocksize);
+ co_yield std::pair(buffer.data(), !real_size ? fixed_blocksize : block_size);
writeSize += fixed_blocksize;
}
}
@@ -643,7 +585,7 @@ cppcoro::generator> MFTRecord::process_data(std::string
for (std::pair b : extRecordHeader->process_data(stream_name, block_size))
{
- if (filesize_left < b.second)
+ if (filesize_left < b.second && !real_size)
{
b.second = static_cast(filesize_left);
}
@@ -669,21 +611,21 @@ cppcoro::generator> MFTRecord::process_data(std::string
}
}
-std::shared_ptr> MFTRecord::data(std::string stream_name)
+std::shared_ptr> MFTRecord::data(std::string stream_name, bool real_size)
{
std::shared_ptr> ret = nullptr;
PMFT_RECORD_ATTRIBUTE_HEADER pAttributeData = attribute_header($DATA, stream_name);
if (pAttributeData != NULL)
{
- return attribute_data(pAttributeData);
+ return attribute_data(pAttributeData, real_size);
}
else
{
PMFT_RECORD_ATTRIBUTE_HEADER pAttributeList = attribute_header($ATTRIBUTE_LIST);
if (pAttributeList != NULL)
{
- std::shared_ptr> attribute_list_data = attribute_data(pAttributeList);
+ std::shared_ptr> attribute_list_data = attribute_data(pAttributeList, real_size);
if (attribute_list_data != nullptr)
{
DWORD offset = 0;
diff --git a/Sources/NTFS/ntfs_mft_record.h b/Sources/NTFS/ntfs_mft_record.h
index 01ded7c..c915206 100644
--- a/Sources/NTFS/ntfs_mft_record.h
+++ b/Sources/NTFS/ntfs_mft_record.h
@@ -14,6 +14,7 @@
#include "ntfs_reader.h"
#include "Utils/buffer.h"
+#include "Utils/utils.h"
#include
@@ -50,17 +51,76 @@ class MFTRecord
PMFT_RECORD_ATTRIBUTE_HEADER attribute_header(DWORD type, std::string name = "", int index = 0);
template
- std::shared_ptr |