Investigated decrypting a real Microsoft Store Kindle book (KFX). Found the content is a loose DRMION container with a sibling .voucher, and the account key material lives in .kinf2024 — a key store newer than and structurally different from the .kinf2018 that DeDRM supports (zero "/" record separators; not a version bump). No DeDRM/community support exists for .kinf2024. The blocker is the key, not KFX itself: without the account DSN/secret the voucher (and thus the book) cannot be decrypted or tested. Reverse-engineering .kinf2024 is novel work outside the "port DeDRM" premise, so per decision the findings, evidence, and a two-part follow-up plan (KFX engine port + .kinf2024 RE) are captured in docs/kfx2024-decryption-effort.md rather than implemented. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
9.3 KiB
KFX + .kinf2024 decryption — follow-up research notes
Status: parked (not implemented). This documents what we found while trying to test Phase 4 (KFX) on a real Microsoft Store Kindle book, why it's blocked, and what a future effort would need to do.
Date investigated: 2026-06-24. Machine: Windows 11, Kindle installed via Microsoft Store.
TL;DR
- The target book (The Chronicles of Narnia, ASIN
B008LUYSAE) is in KFX form: a DRMION-wrapped.azwplus a separate.voucherand.resresources. - Decrypting KFX requires a per-book content key that is itself encrypted in a voucher, unlockable only with the Kindle account's DSN + account secret.
- Those credentials live in
.kinf2024— a key store newer than and structurally different from the.kinf2018that DeDRM supports. There is no published reverse-engineering of.kinf2024(it is not in DeDRM_tools). - Therefore the blocker is the key, not the KFX format. Even a perfect KFX
decryptor cannot be tested on this book until
.kinf2024is cracked. That is novel reverse-engineering of a deliberately-obfuscated, rotating format — outside this project's original "port the DeDRM logic" premise.
A follow-up has two independent parts: (A) a KFX decryption engine (a
tractable port of DeDRM) and (B) .kinf2024 key extraction (a research
problem). (A) is useless on Store-Kindle books without (B).
Evidence we gathered
The Kindle install (Microsoft Store)
- Package:
AMZNKindle.AmazonKindleReadingApp_m1sc522ngdk36 - Content root:
%LOCALAPPDATA%\Packages\AMZNKindle.AmazonKindleReadingApp_m1sc522ngdk36\LocalState\Classic\Content\ - Key store:
…\LocalState\Classic\Data\storage\.kinf2024
The book folder (…\Content\B008LUYSAE_EBOK\)
| File | Size | Notes |
|---|---|---|
B008LUYSAE_EBOK.azw |
1,166,844 | DRMION container (see magic below) |
amzn1.drm-voucher.v1.77b9b3e1-…-db5a276a8d6c.voucher |
1,199 | Encrypted DRM voucher (holds the content key) |
CR!….azw.res (many) |
1–6 MB each | KFX resource containers (images/fonts/text) |
B008LUYSAE_EBOK.mbpV2 |
554 | annotations/sidecar |
B008LUYSAE_EBOK.phl |
1,129 | popular-highlights sidecar |
First 16 bytes of B008LUYSAE_EBOK.azw:
ea 44 52 4d 49 4f 4e ee e0 01 00 ea ee 9e 81 83 .DRMION.........
… "ProtectedData" … "amz…"
\xeaDRMION\xee is the KFX DRMION magic. Note: this is a loose DRMION
file, not a .kfx-zip. (Our current Format::detect only recognizes DRMION
inside a ZIP — see "DRMLibre changes needed" below.)
.kinf2024 facts
- Size: 86,477 bytes.
- Zero
/(0x2F) bytes..kinf2018/.kinf2011are/-delimited record streams; the absence of any/means.kinf2024uses a completely different serialization — this is not a renamed.kinf2018. - Content is char-map-style encoded (first 64 chars looked like
bAY8YkY8bkd8AfdYA69v08b799A1AC0YC0009SAAY0d8CM94Ytz992zhb6Yt9J0J). - No legacy
.kinf2018/.kinf2011exists anywhere on this machine (no old desktop "Kindle for PC" install to fall back on).
There is also a Google-Drive-synced ~\My Drive\Documents\My Kindle Content\
with many classic *_EBOK.azw files from an older install. Those are also
account-locked and would need the same Kindle key material to decrypt.
Background: how KFX decryption works (the tractable part — a port)
Reference: DeDRM_tools/DeDRM_plugin/kfxdedrm.py, ion.py, kfxtables.py.
- Identify the pieces. A KFX book is a DRMION content file (
…\xeaDRMION\xee) plus a*.voucher(theDrmIonVoucher). Both are Amazon Ion binary. - Parse the voucher (Ion) to read the encryption algorithm (AES), transform
(CBC), hash (SHA-256) and the lock parameters:
CLIENT_ID= DSN,ACCOUNT_SECRET= account token. - Derive the voucher key. Build
shared = "PIDv3" + algos + lockparams, run it through 13 obfuscation variants (ion.pyobfuscate*/process_V*, ~lines 1051–1610), thenkey = HMAC_SHA256(secret, b"PIDv3")[:32]. AES-256-CBC decrypt the voucher with its IV, PKCS#7-unpad → aKeySet→ theSecretKey(DrmIonVoucher.decryptvoucher, ~lines 1643–1699). - Decrypt the DRMION content with the
SecretKey(AES-CBC) and repackage a DRM-free KFX. (Output is decrypted KFX, not EPUB — same limitation DeDRM has; a separate KFX→EPUB converter would be needed for a readable EPUB.)
What a Rust port needs:
- A minimal Amazon-Ion binary reader (enough for the voucher + DRMION).
- The YJ shared symbol table (the 2 MB
kfxtables.py) embedded as a compressedinclude_bytes!blob, to resolve symbol IDs used in the voucher. - LZMA (
lzma-rs) for compressed Ion LOBs — verify it handles KFX's framing. - Crypto we already have: AES-256-CBC (add 256-bit path to
crypto.rs), HMAC-SHA256 (hmaccrate), SHA-256, PKCS#7 unpad.
Risk: the 13-variant key derivation and the symbol-table embedding are fiddly, and "Amazon changes KFX DRM frequently" (DeDRM's own warning).
Background: .kinf2018 (closest documented relative of .kinf2024)
Reference: kindlekey.py::getDBfromFile, ~lines 419–572, and getK4Pids
(kgenpids.py ~219–309). For version 6 / .kinf2018:
- File =
/-separated records; first record is a DPAPI-protected header (UnprotectHeaderData) decoded withtestMap1, containing[Version:6][Build:b][Cksum:…][Guid:g]. - Per-key derivation:
salt = str(0x6D8*build) + guid,sp = GetUserName() + "+@#$%+" + GetIDString(),passwd = encode(SHA256(sp), charMap5),key = PBKDF2(passwd, salt, 10000, 0x400)[:32]. - Each value: rearrange (prime-offset) →
decode(testMap8)→iv||ciphertext, withiv = iv[:12] + 00 00 00 02, then AES-CTR decrypt →decode(charMap5). GetIDString()= disk volume serial / MAC-derived machine id.
The useful outputs are kindle.account.tokens (account secret) and DSN
(or the inputs to derive it: MazamaRandomNumber + IDString + UsernameHash).
These feed both getK4Pids (for MOBI/AZW PIDs) and the KFX voucher lock
params (CLIENT_ID=DSN, ACCOUNT_SECRET=token).
What's unknown for .kinf2024: the serialization (no / records), the
header/version encoding, the per-value cipher and key derivation, and what
machine/account entropy it binds to. All of this must be reverse-engineered.
What a follow-up needs to do
Part A — KFX decryption engine (port; ~the original Phase 4)
- Extend
Format::detectto recognize a loose DRMION file (starts with\xeaDRMION\xee) as KFX, in addition to KFX-ZIP, and to recognize a Kindle content folder (.azwDRMION +*.voucher+*.res). - Minimal Ion binary reader (
kindle/kfx/ion.rs). - Embedded YJ symbol table (
kindle/kfx/symbols.rs, compressed blob). - Voucher key derivation + DRMION decrypt (
kindle/kfx/voucher.rs). - Add AES-256-CBC + HMAC-SHA256 helpers to
crypto.rs; addlzma-rs. - Repackage decrypted KFX; wire the
KfxZip/Kfxbranch indecrypt.rs.
Part B — .kinf2024 key extraction (research; the real blocker)
- Decode the container. Figure out
.kinf2024's framing (it is not/-delimited). Inspect for length-prefixes / a new separator / base-N blocks. - Header + version. Find how the
[Version:…][Build:…][Guid:…](or its successor) is stored; confirm whether the header is still DPAPI-protected. - Per-value crypto. Determine the v7+ key derivation and cipher (is it still PBKDF2 + AES-CTR? new salt/entropy? new char-maps?).
- Goal outputs:
kindle.account.tokensandDSN(orMazamaRandomNumberIDString+UsernameHash).
- Likely needs dynamic analysis of the Store Kindle app (the encoder is in the
app), or watching for any community RE of
.kinf2024.
Once Part B yields DSN + account secret, Part A can be validated on the Narnia
book, and getK4Pids (already ported in kindle/pid.rs: encode,
encode_hash, generate_device_pid) lets the existing MOBI path also
decrypt account-locked classic .azw files.
DRMLibre changes already implied
crates/drmlibre-core/src/format.rs: add loose-DRMION detection + aKfx(non-zip) variant; currently such a file returns "can't determine file type".crates/drmlibre-core/src/kindle/pid.rs:encode/encode_hash/generate_device_pidare ported and tested but#[allow(dead_code)]untilgetK4Pids(the Kindle-DB → PID path) is wired — that wiring is the natural companion to Part B.crates/drmlibre-core/src/extract/: akindleextractor would live here, alongside the working Windows Adobe extractor.
Open questions / risks
.kinf2024may bind to hardware/account in new ways; extraction might only work on the same machine where Kindle is activated (acceptable for our use).- KFX DRM is a moving target; a port valid today may break on future books.
- Output of Part A is decrypted KFX, not EPUB — readability needs a separate KFX→EPUB step (out of scope here).
References
- DeDRM_tools:
DeDRM_plugin/kfxdedrm.py,ion.py(DrmIonVoucher,obfuscate*/process_V*),kfxtables.py(symbol table),kindlekey.py(getDBfromFile,.kinf2018v5/v6),kgenpids.py(getK4Pids). - Our notes on the KFX crypto core are in the project plan
(
~/.claude/plans/fizzy-sparking-wadler.md, Phase 4 section).