49 const std::vector<ScanResult>& seed_results,
50 std::vector<std::string>& logs) {
51 std::vector<ScanResult> out;
52 std::set<uint64_t> seen_offsets;
54 logs.push_back(
trs(
"NTFS probe: analysis started."));
56 for (
const auto& seed : seed_results) {
57 const bool interesting_seed =
61 if (!interesting_seed || seen_offsets.count(seed.offset_bytes) != 0) {
64 seen_offsets.insert(seed.offset_bytes);
66 std::array<unsigned char, 512> sector{};
67 if (!reader.
read_at(seed.offset_bytes, sector.data(), sector.size()) || !is_ntfs_boot_sector(sector)) {
71 const uint16_t bytes_per_sector = le16(sector.data() + 11);
72 const uint8_t sectors_per_cluster = sector[13];
73 const uint64_t total_sectors = le64(sector.data() + 40);
74 const uint64_t mft_lcn = le64(sector.data() + 48);
75 const uint64_t mftmirr_lcn = le64(sector.data() + 56);
76 const int8_t record_descriptor =
static_cast<int8_t
>(sector[64]);
78 if (bytes_per_sector == 0 || sectors_per_cluster == 0 || total_sectors == 0) {
82 const uint64_t cluster_size =
static_cast<uint64_t
>(bytes_per_sector) * sectors_per_cluster;
83 const uint64_t volume_size = total_sectors * bytes_per_sector;
84 const uint64_t record_size = record_size_from_descriptor(record_descriptor, cluster_size);
86 if (record_size == 0) {
89 const uint64_t mft_offset = seed.offset_bytes + (mft_lcn * cluster_size);
90 const uint64_t mftmirr_offset = seed.offset_bytes + (mftmirr_lcn * cluster_size);
92 std::array<char, 4> mft_sig{};
93 bool mft_ok = reader.
read_at(mft_offset, mft_sig.data(), mft_sig.size()) &&
94 std::string(mft_sig.data(), mft_sig.size()) ==
"FILE";
96 std::array<char, 4> mftmirr_sig{};
97 bool mftmirr_ok = reader.
read_at(mftmirr_offset, mftmirr_sig.data(), mftmirr_sig.size()) &&
98 std::string(mftmirr_sig.data(), mftmirr_sig.size()) ==
"FILE";
100 std::ostringstream detail;
101 detail <<
trs(
"Bytes/sector") <<
": " << bytes_per_sector
102 <<
", " <<
trs(
"Sectors/cluster") <<
": " <<
static_cast<unsigned>(sectors_per_cluster)
103 <<
", " <<
trs(
"MFT record size") <<
": " << record_size
104 <<
", " <<
trs(
"MFT") <<
": " << (mft_ok ?
"OK" :
"missing")
105 <<
", " <<
trs(
"MFTMirr") <<
": " << (mftmirr_ok ?
"OK" :
"missing");
107 double confidence = 0.85;
108 if (mft_ok) confidence += 0.10;
109 if (mftmirr_ok) confidence += 0.03;
110 if (confidence > 0.99) confidence = 0.99;
126 trs(
"Primary MFT record signature validated"),
135 trs(
"MFT mirror record signature validated"),
140 logs.push_back(
trs(
"NTFS probe: analysis completed."));