NTFS – MFT 엔트리 구조 (MFT Entry Structure)
파일시스템을 금방 마무리 하고 파일시스템에 기반한 여러 가지 이슈와 다른 포렌식 적인 이슈를 다룰려고 했는데 생각보다 일이 몰리는 바람에 이제서야 다시 쓰네요. 별로 중요한 글은 아니라고 생각했는데 생각보다 많이 찾아주시고, 또 요청이 있어서 앞으로 잠을 줄여서라고 써야겠네요.
바로 전에 MFT 엔트리에 대한 기본적인 내용에 대해서 살펴봤다. 다시 짚어보면 MFT 엔트리는 NTFS 파일시스템에서 하나의 파일마다(디렉터리도 파일로 간주) 하나(하나 이상이 될 수도 있음)의 MFT 엔트리가 할당된다. 하나의 MFT 엔트리 크기는 1024 바이트로 고정되어 있다. 그렇다면 MFT 엔트리는 어떤 모습을 하고 있을까?
MFT 엔트리 구조 (MFT Entry Structure)
MFT 엔트리는 다음 그림과 같은 구조를 가진다. 맨 앞부분에 42 바이트 크기의 엔트리 헤더가 오고, 이어서 Fixup 값이 온다. 그리고 해당하는 파일의 특성에 따라 여러 개의 속성들이 따라온다.

파일은 일반 파일, 심볼릭 파일, 보안 속성이 저장된 파일, 비트맵 파일 등에 따라 해당 MFT 엔트리에 존재하는 속성들이 다르다. 즉, 파일의 특성은 해당 MFT 엔트리에 존재하는 속성으로 표현되는 것이다. 속성도 세부적으로 보면 여러 개의 속성이 오는 만큼 속성 헤더와 속성 내용으로 구분된다. 속성에 대해서는 이후에 자세히 살펴보겠다.
속성의 마지막에는 속성의 끝을 나타내는 표시자(End Marker)가 온다. 표시자 이후의 값들은 MFT 엔트리에서 사용되지 않는 값이다. MFT 엔트리도 한번 어떤 파일에 할당된 이후에, 해당 파일이 삭제되면 다른 파일의 MFT 엔트리로 사용될 수 있는 프리(FREE) 리스트가 된다. 새로운 파일이 생성될 때, 만약 해당 MFT 엔트리를 사용하게 되고, 속성 내용이 이전 파일보다 적다면 해당 MFT 엔트리에는 이전 파일의 내용이 남아 있을 수 있다. 이전 파일의 속성 정보가 남아있는게 무슨 대수냐고 반문할 수도 있지만, 이후에 살펴볼 Resident 속성의 경우 파일 데이터가 남아 있을 수도 있다. 자세한 내용은 이후에 살펴보자.
이상으로 전체적인 MFT 엔트리 구조에 대해 살펴보았다. 먼저, 엔트리 헤더가 온 후, 파일의 특성에 따라 해당하는 속성들이 연속해서 온다고 생각하면 된다.
MFT 엔트리 헤더 (MFT Entry Header)
MFT 엔트리 헤더는 모든 MFT 엔트리의 앞 부분에 위치하는 48 바이트 정보이다. 다음 MFT 엔트리 헤더의 데이터 구조이다.
| Byte Range | Description | Essential |
| 0 – 3 | Signature ("FILE") | No |
| 4 – 5 | Offset to fixup array | Yes |
| 6 – 7 | Number of entries in fixup array | Yes |
| 8 – 15 | $LogFile Sequence Number (LSN) | No |
| 16 – 17 | Sequence Number | No |
| 18 – 19 | Link count | No |
| 20 – 21 | Offset to first attribute | Yes |
| 22 – 23 | Flags (in-use and directory) | Yes |
| 24 – 27 | Used size of MFT entry | Yes |
| 28 – 31 | Allocated size of MFT Entry | Yes |
| 32 – 39 | File reference to base record | No |
| 40 – 41 | Next attribute id | No |
| 42 – 43 | Align to 4B boundary | No |
| 44 – 47 | Number of this MFT Entry | No |
위의 데이터 구조와 같이 MFT 엔트리는 모두 "FILE"이라는 시그니처를 가진다. 중요한 값들의 내용을 살펴보면 다음과 같다.
- Offset to fixup array : fixup 배열(연속된 fixup 값)의 시작 위치
- Sequence Number : 해당 MFT 엔트리가 할당, 해제될 때마다 1씩 증가하는 값
- Offset to first attribute : 첫 번째 속성의 위치
- Flags : MFT 엔트리의 속성
- Used size of MFT Entry : 실제 사용되는 크기
- Allocated size of MFT Entry : MFT 엔트리 크기 (1024 바이트)
- File reference to base record : base record의 MFT 엔트리 주소 값
다음은 $MFT 파일의 MFT 엔트리 내용이다. 여기서 기억해야 할 것은 NTFS를 접하면서 다들 많이 헷갈리는 부분이다. $MFT는 MFT 엔트리를 모아둔 파일이라고 했다. 그런데 $MFT 역시 하나의 파일이므로 해당 파일에 대한 정보를 가지는 MFT 엔트리도 존재할 것이다. 여기서 말하는 MFT 엔트리는 $MFT 파일의 내용 중 하나가 아닌 $MFT 파일 자체의 MFT 엔트리이다.

$MFT 파일의 MFT 엔트리를 위의 데이터 구조와 비교해보면 다음과 같다.
- Signature : "FILE"
- Offset to fixup array : 0×0030
- Number of entries in fixup array : 0×0003
- $LogFile Sequence Number (LSN) : 0×00000006 3B16F7D5
- Sequence Number : 0×0001
- Link count : 0×0001
- Offset to first attribute : 0×0038
- Flags : 0×0001
- Used size of MFT entry : 0x000001A8
- Allocated size of MFT Entry : 0×00000400 (1024 바이트)
- File reference to base record : 0×00000000 00000000
- Next attribute id : 0×0006
- Align to 4B boundary : 0×0000
- Number of this MFT Entry : 0×00000000
Fixup Array Values
Fixup이라는 것에 대해 살펴보자. Fixup은 해석하면 "수리(하다), 고치다" 등의 의미를 가진다. NTFS에서 Fixup이라는 구조를 둔 이유는 신뢰성을 높이기 위한 방안이다. MFT 엔트리는 기본적으로 1,024(1K) 바이트이므로 2개의 섹터를 사용한다. 이처럼 NTFS를 구성하는 데이터가 하나 이상의 섹터를 사용할 경우 섹터의 마지막 2 바이트 값을 별도로 저장하고, 해당 위치에는 Fixup 값 2바이트가 들어간다. 이로 인해 혹시나 섹터의 내용이 비정상적으로 변경될 경우, 해당 데이터를 해석하기 전, 오류를 사전에 찾아낼 수 있다. 다음은 Fixup 값의 활용을 그림으로 나타낸 것이다.

위의 그림은 Fixup이 사용되기 전의 모습이고, 밑에 모습은 Fixup이 적용된 모습이다.
MFT 엔트리 헤더에서 Fixup과 관련된 필드는 2개가 있다. 하나는 "Offset to fixup array"이고, 다른 하나는 "Number of entries in fixup array" 이다. 위의 $MFT 파일의 MFT 엔트리 헤더에서 이 값은 다음과 같다.
- Offset to fixup array : 0×0030
- Number of entries in fixup array : 0×0003
fixup 배열이 위치한 곳이 0×30(48) 이다. 데이터 구조는 2바이트를 사용하므로 Fixup 값을 살펴보면 "0xB76F" 값을 가진다. 즉, Fixup 값이 "B76F" 이다. 그리고 Number of entries in fixup array 값이 3이므로 Fixup 값 이후로 3*2바이트 (총 6바이트)가 Fixup 값에 의해 대체된 값을 저장하는 배열이 된다. 이 값은 기본 값이 3 이다. 3 이라는 의미는 전체 MFT 엔트리는 2개의 섹터를 사용하므로, MFT 엔트리 내에 존재하는 섹터의 마지막 2바이트와 추가적으로 하나를 더 준 셈이다.
하나의 파일이 MFT 엔트리를 2개 이상 쓴다면 물론 이 값도 거기에 맞게 증가할 것이다. 하지만, MFT 엔트리를 2개 이상 쓰는 파일은 매우 드믈다. 따라서, 기본적으로 3을 쓰는 것으로 판단된다. 1이 추가된 것은 그냥 여유롭게 하나 더 준게 아닐까? 그리고 3이 되어야만 위의 그림에서처럼 이어서 나오는 속성의 위치가 안정적으로 위치한다.
위의 Fixup 배열을 보면, 첫 번째 값이 "D585"이다. 즉, 해당 MFT 엔트리의 첫 섹터의 마지막 2바이트 실제 값이 "D585"이고, 거기에는 이 값 대신 "B76F"가 쓰여져 있을 것이다. 직접 확인해 보면 다음과 같이 "B76F"가 써 있는 것을 확인할 수 있다.

MFT 엔트리 플래그 (MFT Entry Flags)
MFT 엔트리 헤더를 보면 엔트리의 속성을 나타내는 Flags 값이 존재한다. 엔트리의 속성이라는 것은 무엇을 의미하는 것일까? 간단하게 사용되고 있는 MFT 엔트리인지, 해당 MFT 엔트리가 디렉터리 인지를 나타낸다.
- In-use : 0×01
- Directory : 0×02
주의 해야 할점은 사용되는 디렉터리는 값이 0×03을 가진다는 점이다. 사용 중이면서 디렉터리이기 때문에 두 값을 더한 값이 오게 된다.
파일 참조 주소 (File Reference Address)
NTFS에는 64비트로 이루어진 파일 참조 주소(File Reference Address)가 존재한다. 특정 MFT 엔트리를 찾고자 할 경우 MFT 엔트리의 주소만 있으면 되겠지만, NTFS는 파일 참조 주소를 사용해 해당 MFT 엔트리의 위치를 표현한다. 파일 참조 주소는 각 MFT 엔트리의 주소값과 MFT 엔트리의 순서 번호(Sequence Number)를 조합해서 만들어 진다. 우선 MFT 엔트리의 주소값을 살펴보자.
MFT 엔트리 주소값은 첫 번째 엔트리부터 마지막 엔트리 까지 순차적으로 매겨진 번호이다. 따라서, MFT 엔트리 0번인 $MFT의 주소값은 0이 된다. 마지막 MFT 엔트리 주소값은 $MFT 의 크기가 파일의 수에 따라 가변적이지만, MFT 엔트리 크기 (1,024 바이트)로 $MFT 파일 크기를 나누면 구할 수 있다. 그리고 MFT 엔트리 주소는 48비트로 표현된다.
파일 참조 주소는 48비트 MFT 엔트리 주소값 앞의 16바이트로 해당 MFT 엔트리의 순서 번호를 사용한다. 순서 번호는 위에서 살펴본 바와 같이, 해당 엔트리가 할당 또는 해제될 때마다 1씩 증가하는 값이다. 아래 그림에서 살펴보는 바와 같이 파일 참조 주소를 구성하는 64비트 중 앞의 16비트는 각 MFT 엔트리의 순서 번호를 사용하고, 나머지 48비트는 MFT 엔트리의 주소값을 사용한다.

MFT 엔트리 주소만으로도 충분히 원하는 엔트리에 접근이 가능한데 왜 궂이 앞에 16바이트를 순서 번호로 사용했을까? 그 이유는 주소값만으로 해당 엔트리가 찾고자 하는 엔트리인지는 보장할 수 없기 때문이다. 순서 번호는 해당 엔트리의 고유한 값이므로, 만약 파일 참조 주소를 통해 찾은 엔트리의 순서 번호가 틀리다면, 파일시스템이 손상되었다고 판단할 수 있다. 따라서, 이 경우에는 적절한 오류를 발생시키거나 해당 파일을 참조할 수 없도록 해야 할 것이다.
그리고 할당, 해제될 때마다 1씩 증가한다는 것을 이용하면 한 가지 중요한 것을 생각해 낼 수도 있다. MFT 엔트리가 할당 되었다는 것은 특정 파일이 생성되고, 해당 MFT 엔트리를 사용한다는 것이고, 해제 되었다는 의미는 그 파일이 삭제되었다는 것을 의미한다. 그렇다면 순서 번호가 0보자 큰 짝수인 MFT 엔트리는 현재 사용되는 엔트리가 아닌 삭제된 파일로 간주 할 수 있을 것이다.
실제로는 파일이 삭제되면 MFT 엔트리의 많은 속성 중 $STANDARD_INFORMATION 속성에 Flag가 삭제되었다고 표시된다. 그렇다면, Flag를 이용해 찾은 삭제된 파일의 목록과 순서 번호를 이용해 찾은 삭제된 파일의 목록과 일치한다고 보는가? 이것은 문제로 남겨 두어야 겠다. 궁금한 사람은 확인해 보기 바란다.
이 외에도 파일이 하나 이상의 MFT를 사용할 경우 생성되는 Base MFT 엔트리, Non-based MFT 엔트리, MFT 헤더의 나머지 필드들의 내용은 포렌식적으로 크게 중요하지 않을 것 같아 생략한다. 궁금한 사람은 파일시스템 관련 도서를 찾아보기 바란다.
Categories
- 0×01 News (16)
- 0×02 Fundamentals (11)
- 0×03 Data Forensics (12)
- 0×04 Storage Forensics (14)
- 0×05 File System Forensics (31)
- 0×06 Windows Forensics (19)
- 0×07 *nix Forensics (2)
- 0×09 Web Forensics (5)
- 0x0A Virtual Forensics (5)
- 0x0B Forensic Challenges (15)
- 0x0C Forensic Education (8)
- 0x0D EnCase (12)
- 0x0E Forensic Tools (8)
- 0x0F Slides (24)
- 0×10 Articles (2)
addressing artifacts BIOS boot code boot process challenge Cluster Codegate cookie Data Carving Data recovery DC3 DCO defcon ENCASE EnCE encoding EnScript exFAT FAT File System firmware Forensic Challenge hardware imaging Live Forensics live response mbr network ntfs padocon process RAID Recycle Bin SCSI signature Slack slide SSD steganography timeline timestamp virtual forensics WDFS writeup
WP Cumulus Flash tag cloud by Roy Tanck requires Flash Player 9 or better.
What I'm Doing...
- Old Servers never die – unfortunately, http://t.co/9x9WoU5L 3 days ago
- Windows Live Messenger, MessengerCache folder - http://t.co/ynsdu7fe 3 days ago
- DFIR Slides and Video scripts - http://t.co/XmMYTpg1 3 days ago
- More updates...
Recent Comments
- Jinkook Kim on 리눅스 메모리 포렌식 개요 (An Introduction to Linux Memory Forensics)
- blesslaw on 리눅스 메모리 포렌식 개요 (An Introduction to Linux Memory Forensics)
- MaJ3stY on 리눅스 메모리 포렌식 개요 (An Introduction to Linux Memory Forensics)
- Jinkook Kim on 리눅스 메모리 포렌식 개요 (An Introduction to Linux Memory Forensics)
- MaJ3stY on 리눅스 메모리 포렌식 개요 (An Introduction to Linux Memory Forensics)



Pingback: CODEGATE 2011 YUT Quals – Forensics 400 Writeup | FORENSIC-PROOF (Digital Forensics Community)
Pingback: NTFS – 파일 참조 주소 (File Reference Address) | FORENSIC-PROOF (Digital Forensics Community)