pub struct ApModel { /* private fields */ }Expand description
AP deobfuscation model for a single SA17 page-store file.
Build one with ApModel::learn, then call ApModel::deobfuscate
to recover plaintext for any page.
The model is cheap to clone; it stores at most one u8 per 16-page block.
Implementations§
Source§impl ApModel
impl ApModel
Sourcepub fn learn(store: &PageStore) -> Self
pub fn learn(store: &PageStore) -> Self
Construct an ApModel by scanning every pure-AP page in store.
Pure-AP page types - '@', 'C', 'H', 'M' - have bodies
dominated by the AP fill (sectors 1..6 are almost entirely fill).
From those sectors we can back-calculate bv(block) precisely.
Pages of other types, whose plaintext is dense, contribute nothing to the calibration. At least one pure-AP page must exist in the store (SA17 files always have some).
Sourcepub fn bv_at(&self, bi: u64) -> u8
pub fn bv_at(&self, bi: u64) -> u8
Return the bv for block bi, falling back to bv0 for unknown blocks.
For files where every block has at least one pure-AP page, every block
will be in bv_map. For the rare blocks that lack one, bv0 is used
(an approximation that degrades gracefully).
Sourcepub fn deobfuscate(&self, raw: &[u8], pn: u64) -> Vec<u8> ⓘ
pub fn deobfuscate(&self, raw: &[u8], pn: u64) -> Vec<u8> ⓘ
Deobfuscate a full 4 KiB page.
pn is the zero-based page index within the store.
The page trailer (0xFF0..0xFFC) and CRC footer (0xFFC..0x1000) are
copied verbatim; they are stored in plaintext and must not be modified.
For blocks whose bv was not learned from a pure-AP page this falls
back to bv0. Use ApModel::deobfuscate_with_store to get the
correct bv for every block.
Sourcepub fn learned_block_count(&self) -> usize
pub fn learned_block_count(&self) -> usize
Number of blocks for which bv was directly learned from a pure-AP page.
Sourcepub fn recover_bv_for_block(&self, store: &PageStore, bi: u64) -> u8
pub fn recover_bv_for_block(&self, store: &PageStore, bi: u64) -> u8
Brute-force recover bv for a block that has no pure-AP page.
For each candidate bv (0..=255), score it by computing the peak of the
histogram of (stored[i] - (pn + si - bias) - i*step) mod 256 for each
candidate step, then summing the best-step peak across all sectors of up
to 3 sample pages in the block. The candidate with the highest total
score is returned.
The algorithm matches APModel._recover_bv_for_block in the Python
reference implementation. At ~2.7 M arithmetic ops per block it is fast
in release mode (< 2 ms on modern hardware).
This assumes bv is constant across the sampled pages, which does not
hold on every file (see Self::recover_bv_for_page); prefer that
method, via Self::deobfuscate_with_store, when per-page accuracy
matters.
Sourcepub fn recover_bv_for_page(&self, store: &PageStore, pn: u64) -> u8
pub fn recover_bv_for_page(&self, store: &PageStore, pn: u64) -> u8
Brute-force recover bv for a single page, independent of its block.
Same scoring technique as Self::recover_bv_for_block (histogram-peak
search over candidate (bv, step) pairs), scoped to exactly this page
rather than sampled across its 16-page block.
Use this when a block’s pages don’t share a single bv - observed on
some QuickBooks Enterprise 24.0 files, where bv varies per page
rather than per block (see opensqlany issue #8). This is what
Self::deobfuscate_with_store uses.
Sourcepub fn deobfuscate_with_store(
&self,
raw: &[u8],
pn: u64,
store: &PageStore,
) -> Vec<u8> ⓘ
pub fn deobfuscate_with_store( &self, raw: &[u8], pn: u64, store: &PageStore, ) -> Vec<u8> ⓘ
Deobfuscate a full 4 KiB page, recovering bv for this specific page
rather than trusting a value shared across its 16-page block.
bv is not reliably constant per block on every file - some
QuickBooks Enterprise 24.0 files show 6-8 distinct bv values inside
a single block (opensqlany issue #8). So this always resolves bv
per page: directly, if pn is itself a pure-AP page with a clean
signal, otherwise via Self::recover_bv_for_page’s brute-force
search. Use this variant whenever you have store access; it’s the
only variant that’s correct for dense data blocks (all-E-type)
on files with per-page bv.