🗄️.xls – BIFF8 im Compound File
Die klassische Excel-Datei (Excel 97–2003) ist ein kleines Dateisystem – das Compound File (OLE2). Darin liegt der Stream „Workbook“: eine Folge von Records im Binary Interchange File Format Version 8.
📂Compound File: Dateisystem in der Datei
Gezeigt: Byte 0–95 von 512; ab 0x4C folgt das DIFAT-Feld (109 Einträge, hier nur Sektor 0, Rest FF FF FF FF).
Workbook: der BIFF8-Record-Strom (bei BIFF5: „Book“). Start-Sektor 2, Größe 4700 Byte → Kette über die FAT.
Datei-Offset von Sektor n = (n + 1) · 512, weil der Header selbst den ersten 512-Byte-Block belegt. Die Beispieldatei ist erfunden, aber in sich stimmig; der Workbook-Stream ist bewusst fragmentiert (Sektoren 2–9, dann 12–13).
📚 Quelle: [MS-CFB] 2.2 Compound File Header, 2.3 Compound File FAT Sectors, 2.5 Mini FAT, 2.6 Directory Entry; gegengeprüft an einer von LibreOffice erzeugten .xls (Sektoren 512 Byte, Mini 64 Byte, Cutoff 4096).
🧱Aufbau eines Records
Offset 0 1 2 3 4 … 4+Länge
┌──────┴──────┬──────┴──────┬─────────────────────────┐
│ Typ (u16 LE)│ Länge (u16) │ Daten (0 … 8224 Byte) │ ─► nächster Record
└─────────────┴─────────────┴─────────────────────────┘
Beispiel: 09 08 10 00 │ 00 06 05 00 BB 0D CC 07 00 00 00 00 06 00 00 00
└ BOF 0x0809, 16 Byte └ vers 0x0600 = BIFF8, dt 0x0005 = Globals …Stream "Workbook" ├─ Globals-Substream BOF(dt=0x0005) · CODEPAGE · DATEMODE · FONT/FORMAT/XF · BOUNDSHEET… · SST · EXTSST · EOF ├─ Blatt 1 BOF(dt=0x0010) · DIMENSIONS · ROW… · Zellen (LABELSST/RK/NUMBER/FORMULA…) · EOF └─ Blatt 2 … (BOUNDSHEET.lbPlyPos zeigt jeweils auf das BOF des Blatts)
09 08 in der Datei.CONTINUE-Records (0x003C) fortgesetzt.📚 Quelle: [MS-XLS] Abschnitt „Record“; OpenOffice.org „Excel File Format“.
🐞Record-Stream-Debugger
Beginn der Workbook-Globals (BIFF8)
| Feld | Bytes | Bedeutung |
|---|---|---|
| Record-Typ | 09 08 | 0x0809 = BOF |
| Länge | 10 00 | 16 Byte |
| vers | 00 06 | 0x0600 = BIFF8 |
| dt (Substream-Typ) | 05 00 | 0x0005 = Workbook-Globals |
| rupBuild | BB 0D | 3515 |
| rupYear | CC 07 | 1996 |
| bfh (Datei-Historie) | 00 00 00 00 | 0x00000000 |
| sfo (niedrigste BIFF-Version) | 06 00 00 00 | 0x00000006 |
| A | B | C | D | |
|---|---|---|---|---|
| 1 | ||||
| 2 | ||||
| 3 | ||||
| 4 | ||||
| 5 |
Noch nicht gelesen – kommt im Globals-Substream.
Synthetischer Stream (465 Byte), gekürzt um FONT/XF/FORMAT-Records. In eine CFB-Hülle verpackt öffnet LibreOffice ihn mit genau diesen Werten.
📚 Quelle: [MS-XLS] Records BOF, BoundSheet8, SST, LabelSst, Number, RK, Formula sowie Struktur PtgRef; Stream zur Probe in LibreOffice geöffnet.
🔢RK-Zahlen: 8 Byte in 4 quetschen
Variante int×100 · RK = 0x000007CF · im Record (little endian): CF 07 00 00
Wert · 100 = 499 ist ganzzahlig: (Wert·100) · 4 + 3 (fInt + fX100).
RK-Record: 4 Byte statt 8 für NUMBER – der Record ist 10 statt 14 Byte lang.
- Bit 0 fX100 = 0 nicht teilen
- Bit 1 fInt = 1 obere 30 Bit = Ganzzahl mit Vorzeichen
- Bits 2–31 = 45292
= 45292
Beispiel 0002C3B2 stammt aus einer echten .xls: die Zahl 45292 (= 01.01.2024 als Datum).
MULRK (0x00BD) zusammen.📚 Quelle: [MS-XLS] Strukturen RkNumber und RkRec; Werte 0x0002C3B2, 0x0000025B aus einer realen .xls.
📋Wichtige Record-Typen
| Typ | Name | Wo | Bedeutung |
|---|---|---|---|
| 0x0809 | BOF | beide | Beginn eines Substreams: Version 0x0600 (BIFF8), Typ 0x0005 Globals oder 0x0010 Arbeitsblatt |
| 0x000A | EOF | beide | Ende des Substreams, Länge 0 |
| 0x0042 | CODEPAGE | Globals | Zeichensatz; in BIFF8 immer 1200 (UTF-16) |
| 0x0022 | DATEMODE | Globals | 0 = 1900-Datumssystem, 1 = 1904-System |
| 0x0031 | FONT | Globals | Schriftart (Höhe in 1/20 pt, Name als Unicode-String) |
| 0x041E | FORMAT | Globals | Zahlenformat-String, z. B. „yyyy\-mm\-dd“ mit Nummer ab 164 |
| 0x00E0 | XF | Globals | Zellformat: verweist auf FONT und FORMAT – Zellen tragen einen XF-Index (ixfe) |
| 0x0085 | BOUNDSHEET | Globals | Blattname + Stream-Offset (lbPlyPos) des Blatt-BOF |
| 0x00FC | SST | Globals | Shared String Table: alle Texte der Mappe, einmalig gespeichert |
| 0x00FF | EXTSST | Globals | Sprungtabelle in die SST (schneller Zugriff) |
| 0x003C | CONTINUE | beide | Fortsetzung, wenn Daten > 8224 Byte sind |
| 0x0200 | DIMENSIONS | Blatt | Benutzter Bereich: erste/letzte+1 Zeile und Spalte |
| 0x0208 | ROW | Blatt | Zeileneigenschaften (Höhe, Format) |
| 0x00FD | LABELSST | Blatt | Textzelle: Zeile, Spalte, XF, Index in die SST |
| 0x0203 | NUMBER | Blatt | Zahlzelle mit 8-Byte-IEEE-754-Double |
| 0x027E | RK | Blatt | Zahlzelle kompakt in 4 Byte (RK-Kodierung) |
| 0x00BD | MULRK | Blatt | Mehrere RK-Zellen nebeneinander in einer Zeile |
| 0x0006 | FORMULA | Blatt | Formelzelle: zwischengespeichertes Ergebnis + Formel als Token (Ptg) in UPN |
| 0x0207 | STRING | Blatt | Text-Ergebnis der vorangehenden Formel |
| 0x0201 | BLANK | Blatt | Leere, aber formatierte Zelle |
| 0x0205 | BOOLERR | Blatt | Wahrheitswert oder Fehlerwert (#DIV/0! …) |
📚 Quelle: [MS-XLS] Record Enumeration; Nummern mit einer echten .xls gegengeprüft.
🧓BIFF-Versionen und Grenzen
| Version | Excel | BOF | Container | Besonderheit |
|---|---|---|---|---|
| BIFF2 | Excel 2.x | 0x0009 | loser Record-Strom | 1 Blatt pro Datei |
| BIFF3 | Excel 3.0 | 0x0209 | loser Record-Strom | 1 Blatt pro Datei |
| BIFF4 | Excel 4.0 | 0x0409 | loser Record-Strom (Arbeitsmappen-Variante BIFF4W) | XLM-Makroblätter |
| BIFF5 | Excel 5.0 / 95 | 0x0809, vers 0x0500 | Compound File, Stream „Book“ | Arbeitsmappen, VBA, Texte in Codepage |
| BIFF8 | Excel 97–2003 | 0x0809, vers 0x0600 | Compound File, Stream „Workbook“ | UTF-16, SST, 65 536 Zeilen |
fHighByte: 0 = jedes Zeichen als 1 Byte (Low-Byte von UTF-16, reicht für „Käse“), 1 = echtes UTF-16LE (nötig für „€“ = 0x20AC). Im Debugger siehst du beide Fälle in der SST.📚 Quelle: OpenOffice.org „Excel File Format“ (BIFF-Versionen, BOF); [MS-XLS] Struktur XLUnicodeRichExtendedString.