MFT 엔트리 구조에서 Attributes에 대한 내용을 다룹니다.
꽤 내용이 길수도 있습니다. 본 포스팅은 다음과 같은 내용을 다룹니다.
NTFS MFT Attributes
Resident, Non-resident
$STANDARD_INFORMATION, $FILE_NAME, $BITMAP
NTFS구조
속성을 알아보기 전에 이전에 배웠던 것을 간단하게 짚고 넘어갑시다. 기존 NTFS 구조는 아래 사진과 같이 구성되어 있습니다.
VBR에서는 Boot Sector와 NTLDF & Boot strap으로 구성되어 있었고, FAT와 마찬가지로 BPB라는 구조를 살펴보았습니다. 더 나아가 MFT를 살펴봤는데, $MFT도 NTFS에서 하나의 파일로 다뤄진다고 하였습니다. 0번 제일 처음을 사용하고 있으며 fixup array라는 구조도 살펴봤지요. 무엇보다, Signature, Sequene Number, Flags가 중요한 필드라고 설명했습니다. 이제 MFT Entry 구조에서 Attributes(속성)을 살펴볼 차례입니다.
MFT Entry 구조
MFT엔트리는 NTFS의 각 파일마다 하나씩 존재한다. 각 파일의 메타정보는 MFT 엔트리 내에 다양한 속성으로 표현된다. MFT 엔트리 크기는 1024바이트로 고정되어 있다.
MFT 엔트리 헤더, Fixup Array 다음에 속성은 End of marker가 나타날 때까지 연속적으로 이어진다. 속성은 크게 속성 헤더와 내용으로 나뉜다.
위 속성중 0x10, 0x30, 0x90, 0xA0은 폴더가 가지는 속성이고, 0x10, 0x30, 0x80은 파일이 가지는 속성이다.
위의 속성들은 각 파일의 특성에 따라 MFT 엔트리 헤더, Fixup 배열 이후에 연속적으로 온다고 했다. 일반적인 파일의 경우에는 아래 3개의 속성이 온다. Fixup 배열 이후 $STANDARD_INFORMATION, $FILE_NAME, $DATA가 순차적으로 오는 것을 볼 수 있다.
여기서 속성 크기에 따라 Resident와 Non-Resident로 나뉜다. 크기가 작은 Resident는 MFT안에 있으며, 크기가 큰 Non-Resident는 MFT밖에 있다. 별도로 클러스터를 할당해서 링크만 한다. 이것을 클러스터 런이라고 부른다. $Data 속성의 경우 파일크기가 600 바이트 미만이면 Resident, 600넘어가면 Non-Resident속성으로 된다.
Resident, Non-resident, 클러스터 런에 관한 글을 참고하자.
[파일 시스템]NTFS - 4편(Resident, Cluster Run) (tistory.com)
각 속성은 속성의 메타정보 표현을 위해 속성헤더를 가지게 되는데, 속성 헤더는 공용헤더와 속성 형식헤더로 구성되어 있습니다. 다음은 Common Header (공용헤더) 입니다.
- Attribute type identifier : 속성 타입 식별 값
- Length of attribute : 속성 헤더를 포함한 속성 전체 길이
- Non resident flag : Non resident 속성인지 여부(0x01값이면 Non-resident 속성이다)
- Lenght of name : 자신의 속성 이름 길이
- Offset to name : 속성 이름이 저장된 곳의 시작 위치
- Flags : 속성의 상태 표현
(0x0001 : 압축된 속성, 0x4000 : 암호화된 속성, 0x8000 : Sparse 속성)
- Attribute identifier : 고유한 식별자로 같은 속성이 여러 개일 경우 구별을 위해 사용
다음은 Resident Attribute 헤더입니다. 공용 속성 헤더(Common Attribute Header)는 바로 위에 있습니다.
- Size of content : 헤더 뒤에 오는 속성 내용의 크기
- Offset to content : 속성 내용이 시작하는 곳의 위치
- Indexed flag : 1값을 가진다면 인덱스된 속성($FILE_NAME 속성은 1로 설정)
- Attribute Name : 속성 이름이 존재할 경우. 없다면 속성 내용
다음은 Non-resident Attribute 헤더입니다.
Start VCN of the runlist : 속성 내용이 담긴 런리스트의 시작 VCN
- VCN : 특정 파일의 첫 번째 클러스터부터 순차적으로 부여한 번호
End VCN of the runlist : 속성 내용이 담긴 런리스트(runlist)의 끝 VCN
Offset to runlist : 속성 내부의 런리스트 시작 위치
Compression unit size : 압축 속성일 경우 압축 단위
Allocated size of attribute content : 속성 내용에 할당된 클러스터크기(클러스터 배수)
Real size of attribute content : 속성 내용의 실제 크기
Initialized size of attribute content : 속성 내용의 초기 크기
- NTFS에 존재하는 초기화된 크기의 의미는 파일이 할당될 때, 파일이 더 커질 것을 예상하고 추가적으로 공간을 더 할당하는 경우가 있다. 이 경우 순수한 파일 데이터의 크기는 초기화된 크기이고, 추가적인 공간까지 포함한 크기가 논리적인 크기이다. 대부분 초기화된 크기와 논리적 크기가 동일하다.
Attribute name : 속성 이름이 존재할 경우, 없다면 속성 내용
추가적인 것은 속성 다음에 온다.
$STANDARD_INFORMATION
각 속성을 Hex Editor로 열어서 분석을 해볼건데, 그 전에 속성을 들여다 볼 필요가 있습니다. 모든 파일에 존재하는 기본 속성으로 식별 값은 0x10이다. 속성 중 식별 값이 가장 낮기 때문에 속성 구조에서 가장 처음에 위치한다. 윈도우 NT에서는 48바이트 크기를 가지며 2000이상부터는 72바이트로 증가하였다.
- Windows 64-bit Timststamp : Created, Modified, MFT Modified, Last Accesed Time 총 4개
- Flag : 아래 표 참고
- Maximum number of version : 파일에서 최대로 허용하는 버전 값, 0일 경우 해당 기능이 비활성화
- Version number : 파일의 버전 번호, 버전 최대값이 0일 경우 이 값도 0
- Class ID : 인덱스된 클래스 ID
- Owner ID : 파일 소유자의 ID 값으로 $Quota 파일에서 인덱스로 사용
- Security ID : $Secure 파일의 인덱스로 사용되고 파일 접근 제어 적용시 사용
- Quota Charged : 사용자 할당량 중 해당 파일이 할당된 크기(보통 파일 크기와 동일)
- USN : 파일의 USN 값으로 $UsnJrnl에서 인덱스로 사용
$STANDARD_INFORMATION 속성의 많은 항목 중에서 보통 0으로 셋팅되는 경우는 비활성화되어 있음을 의미한다. 디지털 포렌식적으로 의미 있는 정보는 시간 정보 4가지와, Flag, Owner ID, Security ID, USN가 중요. $STANDARD_INFORMATION의 정보를 들여다 보도록 하자. 다음은 MFT 엔트리 구조입니다.
테스트 NTFS 파일 시스템을 Hex Editor로 열어보았다. Fixup array 이후에 첫 번째 빨간색 0x00000001 값을 가지는 $STANDAR_INFORMATION이 옵니다. 그 다음에 주황색 네모칸을 보면 같은 값이 4개가 반복이 됩니다. (0x01D6C6C5 F53B4F53) 이 값은 $STANDARD_INFORMATION 속성의 4가지 시간정보 입니다.
그리고 이후에 나오는 0x00000003 값을 가지는 $FILE_NAME 속성에도 동일하게 (0x01D6C65C F53B4F53) 값이 4번 반복됩니다. 그리고 나서 $MFT가 유니코드로 적혀 있는 것도 확인이 됩니다.
정확한 분석을 위해서 각 속성의 헤더와 내용의 포맷을 이해해야 합니다. 근데 속성의 4가지 시간정보인데 왜 시간정보가 다 같은 값을 가지고 있을까요? 시간 정보는 MFT수정, 생성, 수정, 접근 시간을 나타냅니다. 저번에도 다뤘던 것 같지만, $MFT는 매우 빈번하게 접근 및 수정이 이루어지기 때문에 시간 정보를 갱신하지 않는 것 같습니다. 속도 차원에서도 많이 느려지겠지요. 한 번 시간을 우리가 보기 편한 시간으로 바꿔보도록 합시다.
- 생성, 수정, MFT수정, 접근 시간 : 0x01D6C6C5F53B4F53(2020년 11월 29일 23시 36분 45초, UTC +9)- Flag : 0x0006(숨긴파일 + 시스템파일)- Maximum number of version : 0x00000000 (사용 X)- Version number : 0x00000000 (사용 X)- Class ID : 0x00000000 (사용 X)- Owner ID : 0x00000000 (사용 X)- Security ID : 0x00000100- Quota Charged : 0x00000000 00000000- USN : 0x00000000 00000000
자세히 보면 $STANDARD_INFORMATION, $FILR_NAME 각각 속성에 4개의 시간 총 8개 시간이 동일합니다. 이는 파일 시스템을 포맷한 시점이라고 보시면 됩니다.
$ATTRIBUTE_LIST
$ATTRIBUTE_LIST의 크기는 가변적이라 Resident, Non-resident 둘 다 될 수 있다. $ATTRIBUTE_LIST는 파일이나 디렉토리의 속성 크기가 너무 크거나 많아지면 MFT 엔트리에 담을 수 없다고 했었다. 다 담을 수 없는 경우 MFT 엔트리에 나눠 저장하게 된다. 이 때 $ATTRIBUTE_LIST속성의 내용을 통해 어떤 속성이 어느 MFT 엔트리에 담겨있는지 알 수 있다.
속성 식별 겂은 0x20(32)로 필수 속성은 아니다. 목적은 무엇일까? 속성의 빠른 접근을 위해 존재한다.
Attibute type : 속성타입
Lenght of entry : 엔트리 길이
Length of Name : 이름 길이
Offset to Name : 이름 시작 위치. 항상 0x1A값이 있음.
Start VCN of attribute : 속성 시작 VCN
File Reference Address : 속성 위치의 파일 참조 주소
Attribute ID : 속성 ID
Attribute name : 속성 이름이 존재할 경우 속성 이름
$FILE_NAME
$STANDARD_INFORMATION의 속성 값은 0x10(16)을 쓰고, $FILE_NAME은 0x30(48)을 사용합니다. 더불어 유니코드(UTF-16)로 인코딩되어 있으며, NTFS에서 빠른 탐색을 위해 만들어 둔 인덱스 구조에도 존재합니다. $STANDARD_INFORMATION과 함께 모든 파일에 기본적으로 존재하는 속성입니다. FILE_NAME=파일 이름이지만 이름외에 부가정보를 더 가지고 있습니다. $FILE_NAME 속성은 해당 MFT 엔트리 뿐만 아니라 인덱스 구조에도 생성이 되며, 이름이 변경될 때 두 속성이 모두 변경이 되지만, 단순히 파일의 속성이 변경될 때에는 인덱스 구조의 $FILE_NAME만 변경됩니다. 항상 Resident 형태도 존재하고 최소 68바이트의 크기를 가집니다.
$FILE_NAME 시간정보를 보면 알겠지만, $STANDARD_INFORMATION 4개의 시간정보 다음에 $FILE_NAME의 시간정보가 옵니다. 총 8개의 시간정보를 볼 수 있는데, 두 개의 차이점은 행위에 따라 차이가 있지만 보통은 이름 변경이면 $FILE_NAME 시간이 변경될 것이고, 나머지는 $STDINFO의 시간 정보가 갱신된다고 알고 있으면 됩니다.
- File Reference address parent directory(부모 디렉토리 파일 참조 주소) : 따로 포스팅 예정
- Allocated size of file : 해당 파일이 할당된 크기(클러스터 배수)
- Real size of file : 파일의 실제 크기
- Flags : $STANDARD_INFORMATION 속성중 Flag와 약간 차이가 있음. 거의 동일
- Reparse value : 해당 속성의 Reparse Point(해당 파일의 마운트, 심볼링 링크 정보 등을 저장)
- Lenght of Name ; 이름 길이
- Namespace : 이름 표현 형식(POSIX, DOS, Win32&Dos). 아래 표 참고
- File Name : 유니코드(UTF-16)로 인코딩된 파일 이름
NTFS는 파일 이름을 저장할 때 DOS형식에 맞지 않으면 $FILE_NAME 속성을 2개 저장하여 파일 이름을 2개로 표현한다. 즉, 원래 파일 이름과 DOS형식의 이름을 추가로 저장한다. 분석할 때 MFT 엔트리 내에 $FILE_NAME 속성이 하나 이상 존재한다면 파일 이름이 DOS형식에 맞지 않다는 것이다.
한 번 예시를 들어서 필드 값을 찾아보자. 파일 이름은 cluster_run.txt 라고 예시를 만들었다. 이 예시는 파일 이름을 변경하지 않고, 파일의 내용을 변경하였다. 파일 이름이 수정 되지 않고, 내용만 수정되었으니 $STANDARD_INFORMATION의 시간 정보만 바뀐 것을 알 수 있다.
File Reference address of parent directory :
- 순서번호 : 0x0005
- MFT 엔트리 주소 : 0x000000000006
Created Time : C5 D7 C3 CF E4 E1 D6 01 (2021년 1월 4일 월요일 00시 26분 30초 UTC+9)
Modified Time : 2A 81 EC D5 E4 E1 D6 01 (2021년 1월 4일 00시 26분 41초 UTC +9)
MFT modified Time : 2A 81 EC D5 E4 E1 D6 01 (2021년 1월 4일 00시 26분 41초 UTC +9)
Last Accessed Time : 2A 81 EC D5 E4 E1 D6 01 (2021년 1월 4일 00시 26분 41초 UTC +9)
Allocated size of file : 0x00 (0 바이트)
Real size of file : 0x00
Flags : 0x0x00000020 ( 일반 파일 )
Reparse value : 0x00000000
Lenght of name : 0x0F
Namespace : 0x00
File Name : cluster_run.txt
한 가지 예시를 더 보자. 지금은 파일만 바뀌어 $STANDARD_INFORMATION의 시간정보만 바뀌고 $FILE_NAME의 시간 정보는 그대로이다. 파일 이름을 바꾸면 정말 $FILE_NAME의 시간정보가 바뀌게 될까? 아래 사진을 보면 $FIME_NAME의 시간도 바뀐 것을 알 수 있다.
$BITMAP
$MFT 파일의 MFT 엔트리의 항목 중 $BITMAP은 $MFT 파일에 연속되어 있는 1024바이트의 MFT 엔트리 중 현재 사용중인 엔트리(1)와 사용하지 않는 엔트리(0)를 비트맵으로 표현한 것이다.
속성 식별 값 0xB0(176)을 가지는 속성으로 할당 정보를 표현해준다. 할당 정보를 가지는 데이터는 $MFT, $INDEX_ALLOCATION이다. 그러면 Non-resident 속성인 $BITMAP을 한 번 Hex Editor로 구경해보자.
공통된 헤더
속성 타입 식별자 : 0x000000B0(176) -> $BITMAP
속성 길이 : 0x00000005 (80) 현재 초록색 범위의 크기
Non-resident 플래그 : 0x01
속성 이름 길이 : 0x00
속성 이름 시작 위치 : 0x0040
상태 플래그 : 0x0x0000
속성 식별자 : 0x0005
Non-resident 헤더
런리스트 시작 VCN : 0x00000000 00000000
런리스트 끝 VCN : 0x00000000 00000001
런리스트 시작 위치 : 0x0004
압축 단위 크기 : 0x0000
속성 내용 할당 크기 : 0x00000000 00002000 (8192)
속성 내용 실제 크기 : 0x00000000 00001008 (4104)
속성 내용 초기화된 크기 : 0x00000000 00001008 (4104)
속성 이름 : 존재하지 않음
$MFT의 전체 MFT 엔트리를 비트맵으로 표현하기 위해서 4104바이트를 사용했다. 0으로 표기된 MFT엔트리를 모으면 현재 사용되지 않고 삭제된 MFT엔트리 이거나 할당 대기중인 엔트리이다.
그리고 런 리스트 끝 VCN이 "1"값을 가지는 것으로 보아 $BITMAP 속성을 표현하기 위해 2개의 클러스터를 사용하고 있다는 것을 확인할 수 있다. 또한 할당 크기가 8192바이트로 확인이 된다.
$DATA
처음에 설명했듯이 MFT엔트리에는 기본적으로 3개의 속성이 있다고 하였다. 그 중 하나인 $DATA는 파일의 데이터를 저장하는 속성으로 파일 데이터가 약 700바이트 보다 크다면 Non-resident 속성으로 저장된다. 그 외에는 MFT 엔트리 내에 존재하게 된다.
MFT 엔트리의 크기는 1024바이트 인 것을 알고 있다. MFT 엔트리 헤더, $STANDARD_INFORMATION, $FILE_NAME을 제외하면 약 700바이트가 남는다. 때문에 설명하는 사람들마다 600바이트, 680바이트라고 하는 분도 있으니 이 값은 가변적이라고 알아둬야 한다. 즉, 파일 데이터가 별도의 클러스터를 할당받아 저장되는 것이 아니라 MFT 엔트리 내부에 저장된 다는 것을 알아둬야 한다. 이는 만약 파일이 삭제될 경우 삭제된 파일의 데이터를 복구하기 어려운 문제도 있다. 데이터 영역은 할당 정책에 따라 데이터 쓰기 작업이 수행되는데, 방금 삭제된 파일이 덮어 쓰여질 가능성은 적지만 $MFT 내부는 순차적으로 MFT엔트리를 할당받기 때문에 연속적인 MFT 엔트리 공간에서 특정 MFT엔트리가 삭제되었을 경우 새로운 파일에 의해 해당 엔트리가 덮어써질 가능성이 적지 않다.
속성 식별값 0x80(180)을 가지는 속성으로 파일 데이터를 저장한다. 속성 헤더 이후에 바로 속성 내용인 파일 데이터 스트림이 위치하게 된다. 데이터 크기에 따라 Resident 또는 Non-resident로 존재한다. 대체 데이터 스트림(ADS, Alternate, Data Stream)을 통해 2개 이상의 데이터 스트림을 표현한다. 한 번 예시를 알아보자
$DATA가 Resident인 경우
공통된 헤더를 보면 0x80의 $DATA를 알림과 4바이트 뒤에 크기가 나오며, 8바이트 시작에서는 1이면 Non-resident, 0이면 Resident 속성인 것을 알 수 있다. 지금은 값이 0이므로 Resident속성이다.
$DATA가 Non-resident인 경우
$DATA인 0x80과 8번째 Non-resident flag가 1로 적혀있으므로 Non-resident임을 알 수 있다. Non-resident 경우에는 따로 클러스터로 할당 받는 것을 알 수 있다.
Resident, Non-resident 정보는 여기서 보자 [파일 시스템]NTFS - 4편(Resident, Cluster Run) (tistory.com)
한 번 직접 헤더를 보면서 값을 찾아보는 것도 좋을 것이다.
$DATA, LCN, VCN
NTFS에서 LCN(Logical Cluster Number)과 VCN(Virtual Cluster Number)라는 주소방식을 사용한다. LCN은 볼륨의 첫 번째 클러스터부터 순차적으로 지정되어있는 주소를 나타내고, 볼륨상 중복되는 주소가 존재하지 않는 고유 주소를 가진다. VCN은 파일의 첫 번째 클러스터부터 순차적으로 지정되어 있는 주소를 나타내며, 어떤 파일이든 첫 번째 클러스터 VCN값은 0이 되며, 순서대로 하나씩 VCN 값이 증가하게 된다. 또한, LCN처럼 고유번호가 아니라 동일 파일 내에서는 중복된 값을 가질 수 있다. 동일 파일 내에서만 다르면 된다.
즉, LCN은 볼륨의 첫 번째 클러스터를 순차적으로, 고유 주소를 가지는 것. VCN은 동일 파일 내에서만 고유하면 된다.
위 그림을 보면 파일의 0-2번 클러스터 정보를 가지며 VCN 0-2번과 LCN 1300-1302이 대응된다. 두 번째 클러스터 런을 보면 VCN은 3-6번 클러스터 정보를 가지고 있고 LCN은 2301-2304 클러스터와 대응된다.
$DATA ADS(Alternate Data Stream)
하나의 파일이나 디렉토리에 데이터 속성이 여러개 올 수 있으며 기본적으로 존재하는 $DATA 속성 외에 추가적으로 존재하는 속성이 ADS이다. ADS속성은 파일 크기에 포함되지 않는다.
ADS속성은 반드시 속성 이름이 있어야 하며 기본적으로 존재하는 $DATA 속성은 이름이 없어도 상관 없다. ADS는 영역식별자 및 Thumbs.dg:encryptable에 활용된다. 다음은 ADS 생성하는 방법이다. ADS는 용량에 포함되지 않는다. 즉 다른 볼륨에 저장이 되며 삭제하는 방법은 ADS삭제 도구를 이용해야 한다.
참고
NTFS – $DATA 속성 | FORENSIC-PROOF (forensic-proof.com)
NTFS – $ATTRIBUTE_LIST 속성 | FORENSIC-PROOF (forensic-proof.com)
'DFIR > DFIR' 카테고리의 다른 글
[파일 시스템]NTFS - 5편(Index) (0) | 2021.11.12 |
---|---|
[파일 시스템]NTFS - 4편(Resident, Cluster Run) (0) | 2021.11.12 |
[파일 시스템]NTFS - 2편(MFT, Fixup array) (0) | 2021.11.12 |
[파일 시스템]NTFS - 1편(VBR) (0) | 2021.11.12 |
[Digital Forensic] GPT란? (0) | 2021.11.12 |