Microsoft specifies BIFF8 in full as [MS-XLS], Excel Binary File Format (.xls) Structure (revision 12.2, 19 August 2025, used for this page). Section numbers below refer to it. All numbers are little-endian.
The compound file
An .xls file is an OLE compound file ([MS-CFB]), which starts with
D0 CF 11 E0 A1 B1 1A E1 and holds a small file system of storages and
streams (section 2.1.1). The compound file itself is described on the
Word 97 container page.
Section 2.1.7 lists the streams an Excel file may contain:
| Stream or storage | Contents |
|---|---|
Workbook | Required. The workbook data as records (below). |
\005SummaryInformation, \005DocumentSummaryInformation | Document properties (title, author and so on). |
\001CompObj | The OLE class of the document. |
_VBA_PROJECT_CUR | Storage holding the VBA macro project. |
Ctls | ActiveX control data. |
MBD… storages, LNK… storages, \001Ole | Embedded and linked OLE objects. |
_SX_DB_CUR | PivotTable caches. |
Revision Log, User Names | Shared-workbook change history and users. |
List Data | Data of lists (tables) in a shared workbook. |
XML, MsoDataStore, XCB | XML maps, custom data and toolbars. |
_signatures, _xmlsignatures | Digital signatures. |
\006DataSpaces, \009DRMContent, \009DRMViewerContent, encryption | Rights-managed and encrypted content. |
(\005 and similar stand for the control character at the start of the
stream name.)
Records
| Offset | Size | Field | Meaning |
|---|---|---|---|
0 | 2 | type | Record type, from the record list. |
2 | 2 | size | Length of the data, 0 to 8,224 bytes. |
4 | size | data | Fields of that record type. |
Data longer than 8,224 bytes is split: the first 8,224 bytes stay in the record and
the rest follows in Continue records (type 0x003C) of up to
8,224 bytes each, or ContinueFrt, ContinueFrt11,
ContinueFrt12, ContinueBigName and
CrtMlFrtContinue for particular records (sections 2.1.4 and 2.4.58).
Some records use Continue even when short; for example a text box’s
TxO keeps its text and formatting runs in following Continue records.
Strings split across a Continue record start the continuation with a fresh option
byte (see Strings).
Records with type 2048 to 2303 (0x0800–0x08FF) in chart
sheets, and records carrying an FrtHeader, are future records:
a program that does not understand them is expected to keep them unchanged when it
saves (section 2.1.6).
Substreams
The Workbook stream is a series of substreams, each from a BOF record
to an EOF record (type 0x000A, no data). The first is the
globals substream; then come one or more sheet substreams, in the order of the
BoundSheet8 records (section 2.1.7.20).
0GlobalsBOF(dt 5), file protection,CodePage,Window1,Font,Format,XF,Style,BoundSheet8per sheet, names,SST,ExtSST,EOFrecords…WorksheetBOF(dt 16), settings,Index,Dimensions, rows and cells in blocks withDBCell, drawing and objects,Window2,EOFrecords…Chart sheet (dt 32), macro sheet (dt 64) or dialog sheet (dt 16 withWsBool.fDialog)records
BOF (0x0809)
| Offset | Size | Field | Meaning |
|---|---|---|---|
0 | 2 | vers | BIFF version: 0x0600. |
2 | 2 | dt | Substream type: 0x0005 globals, 0x0010 worksheet or dialog sheet, 0x0020 chart, 0x0040 macro sheet. |
4 | 2 | rupBuild | Build number of the application. |
6 | 2 | rupYear | 0x07CC (1996, written by Excel 97) or 0x07CD (1997). |
8 | 4 | flags | Bit 0 fWin (1), 1 fRisc, 2 fBeta, 3 fWinAny, 4 fMacAny, 5 fBetaAny, 8 fRiscAny, 9 fOOM (ran out of memory), 10 fGlJmp (ran out of memory while drawing), 13 fFontLimit (hit 255 fonts, Excel 97), bits 14–17 verXLHigh, the newest Excel that ever saved the file. |
12 | 1 | verLowestBiff | 6. |
13 | 1 | verLastXLSaved | Low 4 bits: the Excel that saved it last. |
14 | 2 | reserved | 0. |
Application versions in verXLHigh and verLastXLSaved:
0 Excel 97, 1 Excel 2000, 2 Excel 2002, 3 Excel 2003, 4 Excel 2007, 6 Excel 2010,
7 Excel 2013 (section 2.4.21 and its notes).
BoundSheet8 (0x0085)
| Offset | Size | Field | Meaning |
|---|---|---|---|
0 | 4 | lbPlyPos | Stream offset of the sheet’s BOF record. |
4 | 1 | hsState (bits 0–1) | 0 visible, 1 hidden, 2 very hidden (cannot be unhidden from the interface). |
5 | 1 | dt | 0 worksheet or dialog sheet, 1 macro sheet, 2 chart sheet, 6 VBA module. |
6 | varies | stName | Sheet name as a ShortXLUnicodeString, 1 to 31 characters, unique ignoring case. |
Finding cells quickly: Index and DBCell
A worksheet’s rows are stored in blocks of up to 32: the Row records of
the block, then their cell records, then a DBCell. The
Index record near the start of the sheet points to every DBCell.
| Record | Fields |
|---|---|
Index (0x020B) | 4 reserved bytes; rwMic (4), the first row with data; rwMac (4), one more than the last; ibXF (4), stream offset of the DefColWidth record; then one 4-byte stream offset per DBCell. |
DBCell (0x00D7) | dbRtrw (4): from this record back to the block’s first Row record; then up to 32 two-byte offsets: the first from the end of the first Row record to that row’s first cell, each later one from the previous row’s first cell. |
Readers may ignore both and simply read records in order.
Encryption: FilePass (0x002F)
If the globals substream contains FilePass, the workbook is
encrypted (section 2.4.117). Its first two bytes, wEncryptionType, are
0 for XOR obfuscation or 1 for RC4. For RC4 the next two bytes choose the header: 1
the original RC4 header ([MS-OFFCRYPTO] 2.3.6.1); 2, 3 or 4 the RC4 CryptoAPI header
([MS-OFFCRYPTO] 2.3.5.1). Record types and sizes stay readable, and so do the
records BOF, FilePass, UsrExcl,
FileLock, InterfaceHdr, RRDInfo and
RRDHead and the lbPlyPos field of
BoundSheet8; all other record data is encrypted (section 2.2.10). RC4
works in 1,024-byte blocks counted from the start of the stream, with the skipped
bytes still fed through the cipher as zeros so the key stream stays in step. With
RC4 CryptoAPI some other streams move into the encryption stream.