OLE란 Object Linking and Embedding 약자로서 객체 연결 및 삽입을 뜻하며
복합 이진 파일 형식(Compound File Binary Format)이라고도 한다.
Microsoft에서 제작한 OLE File Format은 마치 하나의 작은 파일 시스템과 같은 구조를 지니고 있어 상/하위 파일 버전에 대한 뛰어난 호환성을 가지고 있다. 그렇기에 MS Office 외에 다른 워드 프로세서들도 OLE 파일 형식을 사용하고 있다.
Storage and Stream
OLE 파일 구조는 마치 하나의 작은 파일 시스템과 같은 구조를 가지고 있다. 스트림은 문서 내용을 담고 있는 파일, 스토리지는 파일을 담는 폴더와 같다. 스토리지와 스트림의 내용은 문서 종류(doc, hwp, xls 등)에 따라 다를 수 있다.
Header and Data Section
OLE 파일 구조는 크게 헤더 영역과 데이터 영역으로 나뉜다.
헤더 영역에는 File Signature, Sector Count, Sector Size, Start Sector ID 등 OLE 파일을 구성하고 있는 주요 정보들이 저장되어 있고, 데이터 영역에는 앞서 설명한 스트림과 스토리지 그리고 그것들을 구성하고 있는 테이블 정보(BBAT, SBAT)가 저장된다. 데이터 영역 대부분은 스트림이 차지한다
File Sector
OLE 파일은 섹터 단위로 구성된다. 1섹터 크기는 512바이트이다. 예를 들어 만약 파일 크기가 2560바이트일 경우 헤더 영역은 고정 512바이트, 데이터 영역은 파일 크기에서 헤더 크기만큼 뺀 2560-512=2048바이트로 구성된 것이다. 여기서 주의해야할 점은 나중에 데이터 영역에 Sector ID로 접근을 할 때 헤더 크기는 빼고 계산해야 한다는 것이다. 이 부분은 나중에 다시 설명하도록 하겠다.
Header Information
OLE 파일에서 가장 먼저 읽어야 할 것은 헤더이다. 헤더에는 OLE 파일에 대한 다양한 정보를 저장하고 있다. 헤더 영역은 파일 시작 위치부터 1섹터(512바이트) 만큼이다. Hex Viewer 또는 Microsoft에서 제공하는 OffVis를 통해 직접 확인해 볼 수 있다.
이름
Magic ID
위치
0x00 ~ 0x07
크기
8바이트
일반적인 값
D0 CF 11 E0 A1 B1 1A E1
설명
OLE 파일임을 나타내는 Signature. 정상적인 OLE 파일의 경우 이 값은 반드시 0xE11AB1A1E011CFD0 이어야 한다.
이름
CLSID
위치
0x08 ~ 0x17
크기
16바이트
일반적인 값
0x00 …
설명
OLE CLSID 값
이름
Minor Version
위치
0x18 ~ 0x19
크기
2바이트
일반적인 값
설명
파일의 Minor Version 값
이름
Major Version
위치
0x1A ~ 0x1B
크기
2바이트
일반적인 값
설명
파일의 Major Version 값
이름
Byte Order
위치
0x1C ~ 0x1D
크기
2바이트
일반적인 값
FE FF(Little Endian), FF FE(Big Endian)
설명
값 저장 방식
이름
Sector Shift (BBAT)
위치
0x1E ~ 0x1F
크기
2바이트
일반적인 값
09 00
설명
1 섹터 크기 (2 승수로 나타내며 9인 경우 2^9 = 512)
이름
Small Sector Shift (SBAT)
위치
0x20 ~ 0x21
크기
2바이트
일반적인 값
06 00
설명
SBAT 섹터 1개 크기 (2 승수로 나타내며 6인 경우 2^6 = 64)
이름
Reserved1
위치
0x22 ~ 0x23
크기
2바이트
일반적인 값
0x00 …
설명
사용하고 있지 않음
이름
Reserved2
위치
0x24 ~ 0x27
크기
4바이트
일반적인 값
0x00 …
설명
사용하고 있지 않음
이름
Reserved3
위치
0x28 ~ 0x2B
크기
4바이트
일반적인 값
0x00 …
설명
사용하고 있지 않음
이름
Number of Big Block Allocation Table Depot
위치
0x2C ~ 0x2F
크기
4바이트
일반적인 값
설명
BBAT Depot 개수를 나타낸다. 이 개수가 109개 이상일 경우엔 Extra BBAT를 참조해야 한다.
이름
Root Storage Sector ID
위치
0x30 ~ 0x33
크기
4바이트
일반적인 값
설명
Root Entry(Root Storage) 시작 섹터 번호. 헤더 다음으로 가장 먼저 읽어야할 부분이다. 이 위치가 0x27인 경우 다음과 같이 계산할 수 있다. 이전에 앞서 설명한대로 헤더 다음 섹터부터 0번이기 때문에 헤더 크기만큼 추가로 더해야한다.
0x27 * 0x200(Sector Size) + 0x200(Header Size) = 0x5000
이름
Reserved4
위치
0x34 ~ 0x37
크기
4바이트
일반적인 값
0x00 …
설명
사용하고 있지 않음
이름
Max Small Stream Size
위치
0x38 ~ 0x3B
크기
4바이트
일반적인 값
00 10 00 00
설명
이 사이즈 미만인 스트림을 읽을 때는 SBAT를 참조해야 한다. 이 사이즈 미만인 스트림은 Small Stream이다.
이름
SBAT Depot Start Sector ID
위치
0x3C ~ 0x3F
크기
4바이트
일반적인 값
설명
Small Block Allocation Table Depot 시작 섹터 번호이다. 이 위치를 따라가면 SBAT Depot를 만날 수 있다.
이름
SBAT Sector Count
위치
0x40 ~ 0x43
크기
4바이트
일반적인 값
설명
Small Block Allocation Table 크기 값이며, 몇 개의 섹터를 차지하는지에 대한 값이다. 1이면 SBAT 크기는 다음과 같이 결정된다.
1 * 512(Sector Size) = 512
이름
Start Block of Extra Big Block Allocation Table
위치
0x44 ~ 0x47
크기
4바이트
일반적인 값
FE FF FF FF (BBAT 개수가 109개 이하일 경우)
설명
확장된 BBAT 시작 섹터 번호. Number of Big Block Allocation Table 값이 109개가 넘어서면 여기를 참조해야 한다. 이 값을 따라가면 확장된 BBAT가 나오게 된다.
이름
Number of Extra Big Block Allocation Table
위치
0x48 ~ 0x4B
크기
4바이트
일반적인 값
00 00 00 00 (BBAT 개수가 109개 이하일 경우)
설명
앞서 나온 확장된 BBAT 개수. 예를 들어 만약 BBAT가 120개여서 확장된 경우 이 값은 확장된 크기인 11이다.
이름
BBAT Depot
위치
0x4C ~ 0x01FF
크기
436바이트
일반적인 값
설명
여기서부터 헤더 끝인 0x01FF까지 109개의 BBAT 엔트리들이 저장된다. 4바이트씩 Sector ID를 가지고 있으며, BBAT 개수가 109개 이상일 경우 Start Block of Extra Big Block Allocation Table를 참조해야 한다.
BBAT (Big Block Allocation Table)
OLE 파일은 섹터 단위로 이루어져 있다. 마찬가지로 OLE 파일을 구성하고 있는 데이터들도 전부 섹터 단위로 구성되어 있다. 1섹터 크기는 512바이트이다. 512바이트를 초과하면 한 개 섹터에 데이터를 모두 저장할 수가 없기 때문에 나눠서 저장을 해야한다. 예를 들어 4480바이트 크기 데이터는 9섹터에 각각 512바이트씩 나눠서 저장한다.
BBAT는 나눠서 저장한 데이터들을 연결하는 연결고리 저장소이다. 데이터들은 항상 순차적으로 섹터에 저장하지 않기 때문에 반드시 BBAT를 참조하여 직접 연결을 해줘야만 한다. BBAT에는 참조하는 섹터에 연결된 다음 섹터 번호가 저장되어 있다. 데이터를 이루는 섹터는 단일 연결 구조로 구성되어 있다.
Small Block Allocation Table (SBAT)
파일 헤더에 나와있는 Max Small Stream Size보다 크기가 작은 스트림을 읽을 땐 BBAT가 아닌 SBAT를 참조해야 한다. SBAT는 BBAT와 똑같은 메커니즘이다. Small Sector 한 개 크기는 64바이트이다. 만약 256바이트 스트림을 저장할 경우 4개의 Small Sector에 각각 64바이트씩 저장해야 한다. Small Stream (Small Sector)는 Root Storage에 저장되어 있다. 따라서 Small Stream을 읽기 위해서는 Root Storage를 BBAT를 통해 먼저 읽어야 한다.
Root Storage (Root Entry)
헤더 다음으로 가장 먼저 읽어야 할 항목이다. 파일 내에 존재하는 모든 스트림과 스토리지를 포함하고 있는 최상위 폴더이고 Small Stream (Small Sector)을 저장하고 있다. BBAT를 참조하여 헤더의 Root Storage Sector ID와 연결된 섹터들을 전부 합친다면 파일 전체적인 구조를 파악할 수 있다.
결론
이번 글에서는 OLE 파일 구조 전체적인 정보에 대해 기술하였다. 다음에는 Root Storage 구조에 대한 자세히 알아보기로 한다.