Skip to content
API Documentation
BastionGuard™
NtfsProbe Class Reference

#include <ntfs_probe.hpp>

Static Public Member Functions

static std::vector< ScanResult > analyze (DiskReader &reader, const std::vector< ScanResult > &seed_results, std::vector< std::string > &logs)

Detailed Description

Definition at line 8 of file ntfs_probe.hpp.

Member Function Documentation

◆ analyze()

std::vector< ScanResult > NtfsProbe::analyze ( DiskReader & reader,
const std::vector< ScanResult > & seed_results,
std::vector< std::string > & logs )
static

Definition at line 48 of file ntfs_probe.cpp.

50 {
51 std::vector<ScanResult> out;
52 std::set<uint64_t> seen_offsets;
53
54 logs.push_back(trs("NTFS probe: analysis started."));
55
56 for (const auto& seed : seed_results) {
57 const bool interesting_seed =
58 seed.kind == ResultKind::Partition ||
61 if (!interesting_seed || seen_offsets.count(seed.offset_bytes) != 0) {
62 continue;
63 }
64 seen_offsets.insert(seed.offset_bytes);
65
66 std::array<unsigned char, 512> sector{};
67 if (!reader.read_at(seed.offset_bytes, sector.data(), sector.size()) || !is_ntfs_boot_sector(sector)) {
68 continue;
69 }
70
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]);
77
78 if (bytes_per_sector == 0 || sectors_per_cluster == 0 || total_sectors == 0) {
79 continue;
80 }
81
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);
85 // Bug #3/#4 fix: record_size==0 means invalid, skip volume
86 if (record_size == 0) {
87 continue;
88 }
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);
91
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";
95
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";
99
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");
106
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;
111
112 out.push_back({ResultKind::NtfsVolume,
113 seed.offset_bytes,
114 volume_size,
115 "NTFS volume",
116 "NTFS probe",
117 detail.str(),
118 confidence});
119
120 if (mft_ok) {
121 out.push_back({ResultKind::NtfsMetadata,
122 mft_offset,
123 record_size,
124 "NTFS $MFT",
125 "NTFS probe",
126 trs("Primary MFT record signature validated"),
127 0.96});
128 }
129 if (mftmirr_ok) {
130 out.push_back({ResultKind::NtfsMetadata,
131 mftmirr_offset,
132 record_size,
133 "NTFS $MFTMirr",
134 "NTFS probe",
135 trs("MFT mirror record signature validated"),
136 0.93});
137 }
138 }
139
140 logs.push_back(trs("NTFS probe: analysis completed."));
141 return out;
142}
bool read_at(uint64_t offset, void *buffer, size_t len)
std::string trs(const char *msgid)
Definition i18n.cpp:22
@ Partition
Definition models.hpp:8
@ LostPartitionCandidate
Definition models.hpp:9
@ NtfsMetadata
Definition models.hpp:13
@ FilesystemCandidate
Definition models.hpp:10
uint64_t le64(const unsigned char *p)
uint16_t le16(const unsigned char *p)
uint64_t record_size_from_descriptor(int8_t descriptor, uint64_t cluster_size)
bool is_ntfs_boot_sector(const std::array< unsigned char, 512 > &sector)

References FilesystemCandidate, LostPartitionCandidate, NtfsMetadata, NtfsVolume, Partition, DiskReader::read_at(), and trs().

Referenced by ScannerEngine::run_scan().


The documentation for this class was generated from the following files:
  • BastionGuard/thirdparty/bastionguard-recovery-data/src/ntfs_probe.hpp
  • BastionGuard/thirdparty/bastionguard-recovery-data/src/ntfs_probe.cpp