본문 바로가기

Kitri_NCS3기 보안과정/디지털포렌식

170512 컴파운드 파일 분석

Compound File Binary Format (CFBF)


: 복합 파일, 복합 문서 형식, 여러 파일 및 스트림을 단일 파일에 저장하기 위한 복합문서 파일형식

 Compound 파일구조는 FAT와 유사함


파일 → 파일 할당 테이블과 함께 연결된 섹터로 분할됨 

디렉토리 → 섹터 ID가 있는 포함된 파일에 대한 정보





구조

512바이트 헤더 레코드와 헤더에 정의된 여러 섹터로 구성

섹터의 길이는 128*2^n (128, 256, 512, 1024 등....)의 크기를 지원

0 sector

1 sector  

Header

Header 에 정의된대로 섹터가 구성됨 



섹터의 길이 하한선이 128인 이유?

: 디렉토리 섹터에 단일 디렉토리 항목을 맞추기 위해 필요한 최소값.

▷ 섹터의 유형 

    • FAT : 섹터 인덱스 체인 정보
    • Mini FAT: MiniStream 내의 miniSector 체인 정보 
    • Double Indirect FAT(DIFAT) : FAT 섹터 위치
    • Directory Sector : 디렉토리 항목 포함
    • Stream Sector : 파일의 데이터 포함
    • Range Rock Sector : 큰 파일의 바이트 범위 잠금 영역 포함





<Header>


00

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

 File Header Signature

Header CISID 

 

 Minor Version

Major Version 

Byte order Identifier 

Sector Shift 

Size Mini Sector 

예약영역

Directory sectors 개수

FAT sectors 개수

SEC ID 

Transaction Signature Number 

Mini Stream Cutoff size 

Mini FAT 위치

Mini FAT 개수 

first DIFAT Sector Loaction

 DIFAT Sector의 개수 

FAT #1 위치 

FAT #2 위치

......

FAT #N 위치

0xFFFFFFFF




 

Offset

길이(byte) 

설명 

 File Header Signature

0x00 

8 

파일의 종류 시그니쳐  D0 CF 11 E0 A1 B1 1A E1 는 hwp, doc 등의 파일

파일 시그니쳐 종류 : http://forensic-proof.com/archives/300

 Header CISID

0x08 

8 

예약된 클래스 , 사용하지 않는다. 모두 0으로 기입되어있음 

Minor Version

0x18 

2

요약 변경을위한 버젼 번호

 major의 값이 0x0003, 0x0004일경우 0x003E 

Major Version 

0x1A 

2 

 변경사항에 관련된 버전정보 

0x0003(ver.3) 이나 0x0004(ver.4)로 됨 

Byte Order Identifier 

0x1C 

2 

바이트의 순서를 Little-Endian 이냐 Big-Endian이냐 정하는곳

LE: FE FF / BE : FF FE

Sector Shift  

0x1E 

2 

섹터의 크기를 정의함 

Major의 ver3 = 9 / ver4 = C 를 기재 하는데 

2^9  = 512

2^13 = 4096

을 의미함

Mini Sector Shift

0x20 

2 

Mini Sector의 크기를 정의함.  6으로 정의되야 한다.

2^6 = 64

 Reserved 영역

0x22

6

0으로 채워준다 

 Directory Sector 개수

0x28 

디렉토리 섹터의 개수 (Major = 3 이면  0 )

FAT Sector 개수

0x2C 

 FAT 섹터의 개수

SEC ID 

0x30 

 첫 번째 디렉토리 개수 (Root Directory, Directory Entry)

 Transaction Signature Number

0x34 

4 

파일이 특정 API에 의해 저장되면 숫자가 증가됨, 파일이 트랜잭션이 아닌경우 0으로 써주면됨 

 Mini Stream Cutoff size

0x38 

0x00001000 으로 설정되야함 

Mini FAT 와 FAT의 분기 기준 ?

Mini FAT location 

0x3B 

 Mini FAT 위치

Mini FAT 개수 

0x40 

Mini FAT 개수 

first DIFAT Sector loaction 

0x44 

 처음 DIFAT Sector의 위치 여기서는 현재위치를 말한다.

 DIFAT Sector 개수

0x48 

DIFAT의 개수 

FAT#N의 위치 

0x4B ~

4

FAT의 위치를 말해준다. 하나의 FAT당 4Byte 씩 할당되며 그 이후 나머지는 FF로 채워줌

(major Ver.4의 경우 헤더의 나머지부분은 0으로 채워준다) 




<Root Directory Entry>


00

01 

02 

03 

04 

05 

06 

07 

08 

09 

10 

11 

12 

13 

14 

15 

Directory Entry Name 

Directory Entry Name Length

Object Type

Color Flag

Left Sibling ID

Right Sibling ID

Child ID

CLSID

State Bits

Creation Time

Modified Time

Modified Time

Starting Sector Location

Stream Size


 

Offset

길이(byte)

설명 

Directory Entry Name 

0x00

64 

 64Byte UNICODE

 Null 문자로 종료되야한다.

 '/','\',':','!' 의 문자를 사용할 수 없음

Directory Entry Name Length

0x40 

 Directory Entry Name 문자열의 길이와 일치해야함. 

 개수에 null도 포함해서 계산

 64초과해선 안됨

Object Type 

0x42 

 파일의 유형에 따라 값이 다르다.

 

Name

Value 

UnKnown or unallocated

0x00

Storage Object

0x01 

Stream Object

0x02 

Root Storage Object 

0x05 


Color Flag 

0x43 

 0x00과 0x01 밖에 올 수 없다. root의 경우 0x01


Name

Value 

 Red

0x00

 Black 

0x01 

Left Sibling ID 

0x44 

 왼쪽 스트림 아이디를 포함. 없으면 0xFFFFFFFF

Right Sibling ID 

0x48 

 오른쪽 스트림 아이디를 포함. 없으면 0xFFFFFFFF

Child ID 

0x4C 

 하위 스트림 아이디 포함. 없으면 0xFFFFFFFF

CLSID 

0x50 

16 

 저장소, 루트 저장소의 경우에 개채 클래스 GUID가 포함됨, 스트림에서는 모두 0 

State Bits 

0x60 

 사용자 정의 플래그

Creation Time 

0x64 

  생성 시간, Root에는 0

Modified Time 

0x6C 

  수정 시간, UTC 시간으로 저장

Starting Sector Location 

0x74 

 Root Storage : 미니스트림의 첫번째 섹터

 Mini FAT : 데이터가 존재하는 곳의 첫번째 섹터 

Stream Size 

0x78 

 >= 4096 → FAT

 < 4096 → Mini FAT







실습 


Compound 파일에서 데이터를 추출하기

 : 데이터를 추출하기위해서는 파일의 정보가명시되어있는 Directory Entry와 FAT 그리고 Data Stream영역을 알아내야 한다.

  compound file은 헤더정보를 토대로 파일의 몸통이 생성되기 때문에 헤더값을 살펴보고 분석하자.


<Header>


 D0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00

 00 00 00 00 00 00 00 00 3E 00 03 00 FE FF 09 00 

 06 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00

 01 00 00 00 00 00 00 00 00 10 00 00 02 00 00 00

 02 00 00 00 FE FF FF FF 00 00 00 00 00 00 00 00 


 

주의 

컴파운드 파일을 분석할때 헤더에서 위치등을 지정하는 경우 지정된 장소는 실제장소와 1의 차이가 난다.

헤더에서 지정할 경우 자신을 제외하기 때문이다. 아래의 그림으로 설명하겠다.

 

0

1

2

3 →Header에서 지정되는 주소값

0

1

2

3

4 →실제 주소값

 Header

 

 

  

예를들어 FAT Sector의 주소가 1 이라고 하면 우리가 찾아가야 할 주소는 2인 셈이다.



 

Offset

길이(byte)

설명 

 File Header Signature

0x00 

8 

D0 CF 11 E0 A1 B1 1A E1 hwp, doc, ppt 등의 종류의 파일이다.(파일 시그니쳐 확인)

 Header CISID

0x08 

8 

00 00 00 00 00 00 00 00으로 채워져 있다. 

Minor Version

0x18 

2

3E 00major가 03 이기 때문에 0x003E 

Major Version 

0x1A 

2 

03 00 major ver.3  

Byte Order Identifier 

0x1C 

2 

FE FF Little Endian 방식이다

Sector Shift  

0x1E 

2 

09 00  한 섹터의 크기는 2^9 = 512byte

Mini Sector Shift

0x20 

2 

06 00 한 mini Sector의 크기는 2^6 = 64byte

 Reserved 영역

0x22

6

 예약영역

 Directory Sector 개수

0x28 

00 00 00 00 major = 3 이기 때문에 0

FAT Sector 개수

0x2C 

01 00 00 00 1개 

SEC ID 

0x30 

01 00 00 00 Root Directory의 위치는 2Sector

 Transaction Signature Number

0x34 

4 

 00 00 00 00 

 Mini Stream Cutoff size

0x38 

00 10 00 00 Mini Stream 의 최대사이즈 4096Byte 고정 

Mini FAT location 

0x3B 

 02 00 00 00 첫번째 Mini FAT의 위치, 3Sector

Mini FAT 개수 

0x40 

 02 00 00 00 Mini FAT의 개수는 2개

first DIFAT Sector loaction 

0x44 

 FE FF FF FF 첫번째 DIFAT는 FE FF FF FF = -2 + 1 = -1 (현재 위치)

 DIFAT Sector 개수

0x48 

 00 00 00 00 

FAT#N의 위치 

0x4B ~

4

 00 00 00 00 FAT위치는 0 + 1 = 1Sector


헤더를 분석해서 주요 정보를 나열해 보았다.


섹터의 크기 : 512 byte

mini sector의 크기 : 64byte

mini FAT의 개수 : 2개

FAT의 위치 : 1Sector

Root Directory의 위치 : 2 Sector

첫번째 mini FAT의 위치 : 3 Sector


먼저 FAT의 구조를 보고 파일이 어떻게 배치되어있는지 살펴보았다.


<FAT>


File 1 = 1번째

File 2 = 2, 19번째

File 3 = 3, 20번째

File 4 = 4~34번째(19,20번째 제외)

의 결과가 도출된다

 

같은색은 하나의 파일이다. 파일의 정체는 알수 없지만 이처럼 구성되 있음을 파악 할 수 있다. 회색영역의 첫 파일은 섹터1의 FAT를 가리킨다.

섹터 2번자리는 Root Directory라고 헤더에서 알아냈다. 그렇다면 0x12 = 18번째 영역에 있는부분 (19sector)에는 Root Directory의 내용이 이어질것이고, 같은 이유로 3번째 자리와 20번째는 mini FAT의 정보가 들어있다는걸 알 수 있다. 그렇다면 그 부분을 제외한 나머지는 파일의 데이터 스트림이 있을것이다.


File 1 = 1번째 = FAT

File 2 = 2, 19번째 = Root Directory

File 3 = 3, 20번째 = Mini FAT

File 4 = 4~34번째(19,20번째 제외) = File




2sector 와 19sector를 가져와서 root directory entry를 완성했다.

우리에게 필요한 시그니쳐는 Starting Sector Location과 Stream Size , 파일별 시작위치, 파일이 FAT인지 miniFAT인지 구분만 하면된다.

 Root Entry

 size = 14784(FAT) / 시작 위치 : 3

 1

 size = 3332 (mini FAT) / 시작 위치 = 0

 Catalog

 size = 158(mini FAT) / 시작 위치 = 53

 2

 size = 3865(mini FAT) / 시작 위치 = 54

 3

 size = 3546(mini FAT) / 시작 위치 = 116

 4

 size = 3690(mini FAT) / 시작 위치 =  172


Root Entry를 제외한 아래의 다른 파일들은 모두 mini FAT로 되어있다.


mini FAT의 부분을 확인해보자


 




Entry에서 확인한 시작 위치와 파일의 시작위치를 매칭시켜 파일의 정체를 알아보자.

처음 시작위치가 0인 1번파일이 빨간색 영역의 파일임을 알 수 있다. Catalog의 시작은 53으로 0x35이다 노란색 부분이 catalog임을 알 수 있다.

나머지도 매칭시켜보면


1

 0x00 ~ 0x34

Catalog

 0x35, 0x73, 0xE6

2

 0x37 ~ 0x72

3

 0x75 ~ 0xAB 

4

 0xAD ~ 0xE5 


데이터를 추출해보자 


Data stream 시작 = offset 2048


1번파일 = 0 ~ (52*64)+2048 = 0 ~ 5376 의 영역이 해당 파일을 구성하는 데이터의 영역이라 한다.

영역만큼 데이터를 긁어야 하는데 주의할점이 있다.

주 의 !

데이터스트림에서 처음 내용은 헤더정보를 나타낸다.  offset 0~3은 헤더의 길이. offset 8~11은 파일의 길이이다.

 00

01 

02 

03 

04 

05 

06 

07 

08 

09 

10 

11 

12 

13 

14 

15 

 헤더의 길이

 

 

 

 

파일의 길이 

파일의 내용 

파일의 내용 

 .....

<1파일의 header>


헤더의 길이는 0xC = 12 (0~11)

파일의 길이는 0xCF8 = 3320     


데이터를 추출하기위해서는 헤더를 제외하고 Offset 12부터 추출한다. 2048 + 12 = 2060


2060 ~ 5376 까지 추출해보겠다.



영역 복붙후 jpg로 저장하면!




1번 파일이 복구 되었다.


2,3,4 파일도 같은 방법으로 복구하면된다.