Réponse courte : utilisez analyzeMFT pour une analyse pur Python quand vous pouvez l'installer, libmft quand vous voulez un modèle d'objets typé, ou appelez omerbenamram/mft quand la vitesse compte. L'analyse pur Python est ~10 à 50× plus lente que le crate Rust mais convient pour des scripts ponctuels.
Ce que vous lisez
La Master File Table NTFS est une séquence d'enregistrements de taille fixe de 1 024 octets. Pour l'analyser depuis Python, il vous suffit de :
- Ouvrir le fichier
$MFT(ou le lire depuis une image disque). - La parcourir par tranches de 1 024 octets.
- Appliquer le tableau fixup à chaque enregistrement. Voir l'anatomie d'un enregistrement pour la mise en forme à l'octet près.
- Parcourir le flux d'attributs dans chaque enregistrement.
Les bibliothèques ci-dessous gèrent les quatre étapes. La plupart des analystes ne retombent dans le struct.unpack brut que lorsqu'une bibliothèque n'expose pas un champ qu'ils cherchent.
Option 1 : analyzeMFT
analyzeMFT est le classique parseur MFT en pur Python, à l'origine de David Kovar et toujours maintenu. CLI d'abord, mais importable.
# pip install analyzeMFT
from analyzeMFT.mft_analyzer import MFTAnalyzer
analyzer = MFTAnalyzer(mft_file="path/to/$MFT", output_file="out.csv")
analyzer.analyze()
Le CSV produit a une ligne par enregistrement avec les horodatages venant à la fois de $STANDARD_INFORMATION et $FILE_NAME. Suffisant pour du triage tableur.
À utiliser quand : petits fichiers $MFT, scripts ad-hoc, dépendances natives interdites.
Limites : lent sur les entrées de plusieurs gigaoctets (pur Python mono-thread), et le modèle d'objets est orienté vers l'émission de CSV plutôt que vers des parcours programmatiques.
Option 2 : libmft (modèle d'objets typé)
Si vous voulez interroger les enregistrements comme des objets Python, libmft expose un modèle typé proche de la structure sur disque.
# pip install libmft
from libmft.api import MFT
with open("path/to/$MFT", "rb") as f:
mft = MFT(f)
for entry in mft:
if not entry.is_deleted():
continue
name = entry.get_full_path()
si = entry.get_attributes(0x10)[0] # $STANDARD_INFORMATION
print(name, si.created, si.modified)
libmft résout les références parentes pour que vous puissiez demander à chaque entrée son chemin complet sans écrire la traversée vous-même. Il gère aussi les enregistrements d'extension $ATTRIBUTE_LIST de manière transparente — chose que la couche CSV d'analyzeMFT vous masque.
À utiliser quand : vous voulez écrire une logique qui parcourt les enregistrements, filtre par attribut et émet une forme personnalisée.
Option 3 : appeler un parseur Rust
Quand la $MFT est grosse (1 Go+) ou que vous traitez beaucoup de disques en lot, l'option pratique la plus rapide est d'appeler depuis Python un parseur natif et de lire son JSON.
import json
import subprocess
# omerbenamram/mft — `cargo install mft` ou téléchargez un binaire release
proc = subprocess.run(
["mft_dump", "-o", "json", "path/to/$MFT"],
capture_output=True, check=True,
)
for line in proc.stdout.splitlines():
record = json.loads(line)
if record["header"]["flags"] & 0x1 == 0: # IN_USE à zéro → supprimé
print(record["entry"], record["file_name"]["name"])
mft_dump émet du JSON Lines — un enregistrement par ligne — qui streame proprement dans Python sans charger toute la sortie en mémoire. Comparé à analyzeMFT sur la même entrée, le parseur Rust est typiquement 10 à 50× plus rapide et utilise un dixième de la mémoire.
À utiliser quand : pipelines de production, grosses entrées, ou partout où le temps d'analyse compte.
Lire $MFT directement depuis une image disque
Si vous avez une image brute .dd ou .E01 plutôt qu'une $MFT extraite, utilisez pytsk3 (bindings Python pour The Sleuth Kit) pour vous positionner sur $MFT du volume et en streamer les octets :
import pytsk3
img = pytsk3.Img_Info("disk.dd")
fs = pytsk3.FS_Info(img, offset=0) # utilisez le décalage de la partition NTFS
mft_file = fs.open_meta(inode=0) # $MFT est toujours inode 0
size = mft_file.info.meta.size
data = mft_file.read_random(0, size)
# data contient maintenant $MFT ; passez-le à libmft ou écrivez-le sur disque
C'est l'approche la plus propre quand le volume est chiffré au niveau partition mais monté via un déchiffreur qui vous donne une image brute.
Pièges courants
- Oublier le tableau fixup. Lire des blocs bruts de 1 024 octets sans appliquer l'USA donne des données aberrantes aux décalages 510 et 1022 de chaque enregistrement. Chaque bibliothèque ci-dessus le fait pour vous — n'écrivez votre propre parseur que si vous comprenez le mécanisme de fixup (voir l'anatomie d'un enregistrement).
- Traiter le numéro d'enregistrement comme une identité. Les numéros d'enregistrement sont réutilisés. La référence de fichier 64 bits (numéro d'enregistrement plus numéro de séquence) est l'identifiant qui n'entre pas en collision.
- Confondre les deux jeux d'horodatages. Chaque enregistrement porte des horodatages dans
$STANDARD_INFORMATION(souvent mis à jour) et$FILE_NAME(le plus souvent stable). Pour la détection de timestomping, vous avez besoin des deux — voir les quatre horodatages MFT.
Quand sauter Python entièrement
Pour une analyse interactive ponctuelle sans aucune installation, déposez votre $MFT sur le parseur navigateur de ce site. Il exécute le même crate omerbenamram/mft compilé en WebAssembly, filtre et recherche côté client, et exporte du CSV — aucun Python requis.