## What is MFT Attribute? NTFS 파일시스템에서는 모든 파일(디렉토리)을 하나의 엔트리의 형태로 메타데이터만 저장해 놓는다. 이와 비슷한 내용을 [[$MFT 1]] 에서 다루었었다. 잘 기억이 나지 않는다면 복습하고 오는 것을 추천한다. MFT Attribute를 한 문장으로 표현하자면 하나의 파일 안에 있는 다양한 속성값들에 대한 리스트다. 이때 말하는 속성은 파일의 시간값과 같은 메타데이터나, 실질적으로 파일의 내용을 담당하는 데이터를 포함하게 된다. 분량이 사실 방대한 편이기 때문에 2개의 게시글에 걸쳐 다룰 예정이다. 이번 글은 두번째 글이다. 각각 Attribute의 종류에 대해서 알아보도록 하겠다. ## Attribute Content 이번 단원에서는 각각의 Attribute 속성마다 어떤 정보를 저장하는지 알아볼 예정이다. 어떤 정보가 저장되는지, 또 어떤 포렌식 관점에서 이 정보를 활용할 수 있는지 알아보자. 정보가 좀 빈약하거나, 중요도가 낮다고 판단되는 영역은 공란으로 개제했으니 참고해서 보면 좋겠다. 추후에 추가할 수 있는 내용이 있다면 추가하도록 하겠다. ### $STANDARD_INFORMATION(0x10) 대부분의 MFT Entry는 공통적으로 가지는 Attribute가 있는데 바로 $STANDARD_INFORMATION 속성이다. 이 속성은 파일의 3대 시간값인 생성, 수정, 접근 시간값을 저장하고 있으며 이와 더불어 소유자와 같은 부가적인 정보를 저장하고 있는 속성이다. 직접 구조를 파악해 보며 어떤 정보가 저장되는지 알아보자. ![[%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2023-05-03_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_2.31.17.png]] ![[%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2023-05-03_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_2.33.43.png]] |Name|Offset|Size(Bytes)|Description| |---|---|---|---| |Created Time|0x00|8|파일 생성 시각| |Modified Time|0x08|8|파일 수정 시각| |MFT Modified Time|0x10|8|MFT Entry 수정 시각| |Last Accessed Time|0x18|8|파일 접근 시각| |Flags|0x20|4|[[MFT Attribute (2)]] 참조| |Maximum Number of Versions|0x24|4|파일 버전 최댓값 (Null 인 경우 비활성화)| |Version Number|0x28|4|파일 버전 번호| |Class ID|0x2C|4|인덱스된 Class ID| |Owner ID|0x30|4|파일 소유자의 ID <br>$Quota 파일에서 Index로 사용되는 값| |Security ID|0x34|4|파일 접근 및 제어시 사용 <br>$Secure 파일의 Index로 사용되는 값| |Quota Charged|0x38|8|사용자 할당량 중 파일이 할당된 크기| |Update Sequence Number|0x40|8|$UsnJrnl파일에서 인덱스로 사용되는 값| **Flag Table** |Flag Value|Description| |---|---| |0x0001|읽기 전용| |0x0002|숨김 파일| |0x0004|시스템 파일| |0x0020|아카이브 파일| |0x0040|장치 파일| |0x0080|일반 파일| |0x0100|임시 파일| |0x0200|Sparse 파일| |0x0400|Reparse Point 파일| |0x0800|압축 파일| |0x10000|오프라인| |0x2000|Index 되지 않은 파일| |0x4000|암호화된 파일| > [!NOTE] **Flag Value 패턴 > > **Flag 값들을 유심히 관찰해 보면 2의 배수로 패턴을 이루고 있는 것을 볼 수 있다. > 이는 Flag 값의 특성으로 비트 단위로 0/1을 표시하게 되었을 때 각 비트의 자릿수를 Flag로 사용하는 것이다. > > 예를 들어 4비트 Flag를 예시로 들었을 때 각 비트의 기능을 A,B,C,D라 하자. > 0000 → 기능 없음 > 0001 → A만 활성화 > 0011 → A,B만 활성화 > 0111 → A,B,C 활성화 > 1111 → 모든 기능 활성화 > > 다음과 같이 나타낼 수 있는 것이다. 즉 각 자릿수별로 비트를 나타내기 때문에 Flag Value가 이와 같이 나타나는 것이다. > ### $ATTRIBUTE_LIST(0x20) 속성들이 무작위로 저장되어 있다면 속성값에 접근하는데 어려움이 존재할 것이 자명하다. 이런 이유 때문에 속성들을 묶어 다루는 속성이 존재하게 된다. 이러한 이유 때문에 $ATTRIBUTE_LIST 속성은 반드시 첫번째 Entry인 Base-MFT Entry에 존재해야 한다. 필수적으로 사용되는 속성은 아니며 인덱싱 기능처럼 빠르게 접근하거나 MFT Entry 크기를 넘어 형성될 경우 포함되는 속성이다. 말 그대로 List 이므로 헤더 이후 반복적인 구조가 나타난다. 반복되는 구조에 대해서만 알아보도록 하겠다. ![[Untitled 1.png]] ![[Untitled 2.png]] |Name|Offset|Size|Description| |---|---|---|---| |Attribute Type|0x00|0x04|속성의 종류| |Length of Entry|0x04|2|Entry 길이| |Length of Name|0x06|1|이름 길이| |Name Offset|0x07|1|이름 시작 위치 / 0x1A| |Start VCN of Attribute|0x08|8|속성 시작 VCN| |File Reference Address|0x10|8|속성 위치의 파일 참조 주소| |Attribute ID|0x18|2|속성 ID| |File Name|0x1A|6|속성 이름이 존재할 경우 속성 이름| ### $FILE_NAME(0x30) 파일의 이름을 저장하는 속성이다. `$STANDARD_INFORMATION`과 동일하게 파일의 시간 정보 역시 저장하고 있다. 구조 역시 `$STANDARD_INFORMATION`이랑 비슷하니 잘 비교하며 보도록 하자. ![[%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2023-05-04_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_7.58.42.png]] ![[%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2023-05-04_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_8.00.09.png]] |Name|Offset|Size(Bytes)|Description| |---|---|---|---| |File Reference Address of Parent Directory|0x00|8|부모 디렉토리의 파일 참조 주소 <br>해당 값을 이용하여 $MFT 내의 폴더 구조 구성 가능.| |Created Time|0x08|8|파일 생성 시각| |Modified Time|0x10|8|파일 수정 시각| |MFT Modified Time|0x18|8|파일의 MFT Entry 수정 시각| |Last Accessed Time|0x20|8|파일 접근 시각| |Allocation size of File|0x28|8|해당 파일에 할당된 크기 (클러스터 단위)| |Real Size of File|0x30|8|해당 파일의 실제 크기| |Flags|0x38|4|[[MFT Attribute (2)]] 참조| |Reparse Value|0x3C|4|해당 속성의 Reparse Point 정보 <br>없는 경우 Null Bytes| |Name Length|0x40|1|파일 이름의 길이| |Name Space|0x41|1|파일 이름의 표현 형식 <br> <br>0 : POSIX (`/` 와 NULL문자를 제외한 모든 유니코드 사용 가능) <br>1 : WIN32 (`/`,`”`,`:`,`<`,`>`,`?`를 제외한 모든 유니코드 문자가 사용 가능) <br>2 : DOS (오직 대문자만 표현 가능, 파일명 최대 길이는 8자, 확장자의 경우 3자까지 가능) <br>3 : WIN32 & DOS (기존의 파일 이름이 DOS 형식일때 사용, 2개의 이름을 저장하지는 않음) <br> <br>**파일 이름이 DOS 형식이 아닌 경우 `$FILE_NAME` 속성을 2개 저장하여 파일 이름을 2개로 표현하게 된다.| |File Name|0x42|variable|UTF-16으로 인코딩된 파일 이름| **Flag Table** |Flag Value|Description| |---|---| |0x0001|읽기 전용| |0x0002|숨김 파일| |0x0004|시스템 파일| |0x0020|아카이브 파일| |0x0040|장치 파일| |0x0080|일반 파일| |0x0100|임시 파일| |0x0200|Sparse 파일| |0x0400|Reparse Point 파일| |0x0800|압축 파일| |0x10000|오프라인| |0x2000|Index 되지 않은 파일| |0x4000|암호화된 파일| |0x10000000|디렉토리| |0x20000000|Index View| > [!NOTE] **`$STANDARD_INFORMATION`****과 동일한 Flag Table 인가요??** > > 가장 상위 비트를 차지하는 “디렉토리”와 “Index View”를 제외한다면 나머지 인자들은 동일한 값을 가진다. > > [!Question] **하드링크? 소프트링크?** > 하드링크란 > 실제 파일에 직접적으로 연결된 파일이다. 실제 파일의 복제본이라고 생각하면 편리하다. > > 소프트 링크란 > 실제 파일을 가르키는 바로가기 파일이다. > > 자세한 내용은 [[#$SYMBOLIC_LINK($REPARSE_POINT)(0xC0)]]를 공부해 본다면 이해가 될 것이다. ### \$OBJECT_ID($VOLUME_VERSION)(0x40) $Volume Version 이라는 이름으로도 사용되었는데 이는 NT1.2 버전에서만 사용되었다. 따라서 $OBJECT_ID 만 알아보도록 하겠다. 먼저 GUID라는 용어에 대한 이해가 선행되어야 한다. 굳이 이 사이트에서 다룰 내용은 아니기에 따로 공부를 해오면 좋겠다. 좀 풀어서 설명하자면 파일/디렉토리가 이름이나 위치에 따라 가지는 고유한 값이라고 생각하면 된다. 4가지 값이 저장되는데, 그중 가장 주로 사용되는 GUID Object ID 항목을 제외한다면 생략되어 저장되는 경우도 빈번하다. 어떤 파일의 GUID 값이 궁금하다면 fsutil.exe 을 이용해 GUID값을 볼 수 있다. MFT Entry에 기재된 값과 비교해 보면 이해가 잘 될 것이다. ![[Untitled 3.png]] |Name|Offset|Size|Description| |---|---|---|---| |GUID Object ID|0x00|16 Byte|각각의 파일 또는 디렉터리 마다 가지는 고유한 ID 값| |GUID Birth Volume ID|0x10|16 Byte|파일이 생성된 볼륨의 ID 값| |GUID Birth Object ID|0x20|16 Byte|파일이 처음 생성될 때 받은 오브젝트 ID 값| |GUID Domain ID|0x30|16 Byte|네트워크 환경에서 쓰이는 PC 도메인 ID 값| ### $SECURITY_DESCRIPTOR(0x50) 파일에 대한 전반적인 보안 요소들을 다루는 속성이 $SECURITY_DESCRIPTOR이다. 윈도우 시스템에서는 파일에 대한 감사 로그 정책이나 소유자에 따른 작업 권한을 부여하기 때문에 존재하는 속성이다. 소유자 권한은 SID, 작업 권한은 DACL, 액세스 관련 레코드는 SACL에 저장된다. 원체 복잡한 구조를 가지고 있어 잘 이해가 안될수도 있으나 잘 따라와보면 이해가 될 것이다. 차근차근 이해해 보도록 하자. **SID (Security IDentifier)** 보안분야에 관심이 있어 Windows Exploit 영상을 본 적이 있다면 취약점 코드 실행 이후 메모장을 띄워 보이거나 현재 SID 값을 보여주는 것을 본 적이 있을 것이다. 이 때 등장하는 값에 대해 알아보자. SID는 사용자가 컴퓨터에 로그인 되어있는 동안 도메인 컨트롤러가 할당하는 고유한 값으로 사용자가 로그인 하는 순간 user SID, group SID, 접근 토큰을 생성하게 된다. SID 시그니처, SID 규격버전, Value, 식별자, 상대 ID(RID)로 구성되는 값인데 예시를 통해 빠르게 이해해 보자. ![[Untitled 4.png]] 이때 SID 값은 S-1-5-21-4123707617-2427176102-3762384596-1001이다. 각 구성 요소가 아래 표처럼 대응된다. |SID 시그니처|SID 규격버전|Value|식별자|상대 ID(RID)| |---|---|---|---|---| |S|1|5|21-4123707617-2427176102-3762384596|1001| 우리가 유심히 봐야할 것은 3번째 인자인 Value 인데, Value 값에 따른 의미는은 다음과 같다. |Value|Name|Description| |---|---|---| |S-1-0|NULL SID|아무 소속 없는 SID| |S-1-1|Everyone|All users and groups are included in this SID. <br>This SID is used to grant access to all resources on a system.| |S-1-2|Local group|This SID represents the built-in groups on a local system, such as Administrators, Users, and Guests.| |S-1-3|Creator owner|- This SID is used to grant permissions to the user who creates a resource, such as a file or folder.| |S-1-4|Creator group|- This SID is used to grant permissions to the group that the user who creates a resource belongs to.| |S-1-5|NT Authority|- This SID represents a built-in Windows system account, such as Local Service or Network Service.| |S-1-9|Mandatory Label|- This SID represents the security integrity level of a process, thread, or object.| |S-1-16|Cryptographic Operators|- Members of this group can perform cryptographic operations, such as encrypting and decrypting files.| |S-1-18|Local System|- This SID represents the built-in SYSTEM account on a local system.| |S-1-32|BUILTIN\BUILTIN|- This SID represents the local Built-in account on a system.| |S-1-113|Local account and member of Administrators group|- This SID represents a local account that is a member of the Administrators group.| ### $VOLUME_NAME(0x60) 디스크는 파티션 → 볼륨 → 파일시스템 구조로 세분화된다. 즉 우리가 원하는 파일시스템은 어떤 볼륨에 속해있다는 것이다. 이러한 볼륨에 대한 속성으로 저장할 양이 그리 방대하지는 않아 항상 Resident Attribute Header를 사용한다. Resident Header 다음에 곧바로 볼륨 이름이 위치한다. ![[Untitled 5.png]] 파일시스템의 볼륨 이름을 담고 있으며 이름은 유니코드 형식으로 저장된다. 2바이트에서 256바이트까지 저장할 수 있다. 만약 볼륨 이름이 너무 길면 어떻게 되는지 궁금한 사람들도 있을 것이다. 하지만 볼륨 레이블은 공식적으로 32글자로 제한하고 있다. label 명령어에서도 이를 확인할 수 있다. ![[Untitled 6.png]] ### $VOLUME_INFORMATION(0x70) 0x60값의 Volume Name 속성을 보면서 볼륨 안에 많은 메타데이터 정보가 있을텐데 이름만 저장하는것이 의아했을 수도 있다. 하지만 정보를 분리하여 저장하는 것이지, 볼륨 이름만 저장하는 것은 아니다. 기타 메타데이터는 Volume_Information 속성에 저장된다. ![[%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2023-05-16_%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB_10.45.22.png]] ![[Untitled 7.png]] 그렇다 하기에도 많은 정보가 저장되지는 않는다. 버전정보와 플래그 값만 간략하게 알아보고 넘어가자 **버전 정보** |OS|Major|Minor| |---|---|---| |Windows NT|0x01|0x02| |Windows 2000|0x03|0x00| |Windows XP 이후|0x03|0x01| **Flag 값** |Flag Value|Description| |---|---| |0x0001|Dirty <br>볼륨 내 오류, 부팅 시 chkdsk 실행| |0x0002|$Logfile Resize| |0x0004|Upgrade on Mount| |0x0008|Mounted on NT4| |0x0010|Delete USN ID| |0x0020|Repair Obeject ID| |0x8000|Modified by chkdsk| ### $DATA(0x80) 이번 장에서 가장 중요하다고 여길 수 있는 파일의 실질적인 내용물이 저장되는 부분이다. 실질적인 내용이 저장되는 만큼 그 크기가 다양하며, 특정 크기 이하에서는 Resident Attribute Header를 사용하지만 특정 크기가 넘어가게 된다면 Non-Resident Attribute Header를 사용하게 된다. > [!Question] **Non-Resident Attribute Header를 사용하는 정확한 기준은 몇 바이트인가요?? > > 실험을 통해 확인해 본 결과 파일 크기가 680바이트가 넘어가는 순간부터 Non-Resident Attribute 헤더를 사용하였다. > 가장 큰 차이는 어떤 헤더를 사용하는지에 따르지만 헤더 종류에 따라 Resident Attribute header는 header가 끝나는대로 파일 내 데이터를 확인해 볼 수 있지만 Non-Resident Attribute Header의 경우 header가 끝나면 Cluster Run 구조가 등장하여 데이터가 저장된 클러스터로 이동해야 파일 내 데이터를 확인해 볼 수 있다. > [!Question] > Cluster Run은 무엇이죠?? > [[MFT Attribute (1)#**Cluster Run(Run List)**]] 에서 자세히 다룬 바가 있으니 복습하고 오는 것을 추천한다! > **Resident Attribute** ![[%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2023-05-10_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_8.19.43.png]] $DATA는 Resident Attribute의 경우 Header 이후 파일 내용이 바로 저장되어 있다. 어떤 구조체로 이루어져 있는것이 아닌, 데이터가 곧바로 등장하기에 별다른 설명은 없다. 해당 예시에 0x08 오프셋이 Non-Resident Flag인데, 해당 값이 0이기 때문에 다음과 같이 저장되는 점만 짚고 넘어가자. **Non-Resident Attribute** ![[%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2023-05-10_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_8.45.18.png]] 역시 헤더→클러스터 런을 따라가면 데이터만 담고 있기 때문에 별다른 설명은 하지 않는다. [[MFT Attribute (1)#Non-Resident Header]] 의 구조를 잘 복습하자. 이번 샘플의 Cluster Run을 보면 0x640061000 위치에서 0x42개의 클러스터를 할당 받은 $Bad파일 이라는 것을 알 수 있다. 파일 내용은 해당 오프셋을 보면 된다. 파일을 따라가는 실습은 에서 한번 더 다루겠다. ### $INDEX_ROOT(0x90) 0x90과 0xA0은 수많은 파일의 탐색 속도를 빠르게 하기 위한 “인덱스”라는 개념을 다룬다. 특정 데이터를 찾기 위해 데이터들은 정렬된 순서로 저장되곤 하는데 이때 기준을 만드는 것을 인덱싱이라 한다. 이때 사용되는 개념은 Tree라는 자료구조인데 NTFS에서는 이 인덱싱을 표현할 때 B+ Tree라는 자료구조를 사용하고 있다. 인덱싱 하는 기준은 여러가지다. 대표적으로 몇가지만 알아보도록 하자. |Name|Index Data|Location| |---|---|---| |$I30|$FILE_NAME 속성|각 디렉토리의 MFT Entry| |$SDH|Security Descriptors|$Secure 메타 데이터 파일| |$SII|Security IDs|$Secure 메타 데이터 파일| |$O|Object IDs|$ObjId 메타 데이터 파일| |$O|Owner IDs|$Quota 메타 데이터 파일| |$Q|Quotas|$Quota 메타 데이터 파일| 인덱스 노드의 특성을 좀 알아보도록 하자. - 하나는 여러 인덱스 엔트리를 저장한다는 특성상 반드시 End of Node(EOD)가 존재해야 한다. - 트리 구조상 자식 노드는 부모 인덱스 내 Entry보다 1개 많을 수 있다. - 각 Index Node는 파일의 형태로 존재하기에, $FILE_NAME 속성을 가지고 있고, 이를 기준으로 정렬된다. ![[Untitled 8.png]] 이때 하나의 인덱스 노드는 독립적으로 존재하지 않으며, 반드시 $INDEX_ROOT나 $INDEX_ALLOCATION에 속하게 된다. 지금 다루는 내용은 $INDEX_ROOT로, 트리의 최상위 노드를 의미한다. 사실 별 큰 의미는 없고, $INDEX_ROOT인 경우 사용하는 헤더가 약간 다른 특징이 있다. 구조를 알아보도록 하자. 밑 예시의 첫 0x10 바이트와 0x08바이트, 그리고 그 다음 0x08 바이트는 각각 Common Header, Resident Header, Attribute Name에 해당하는 영역이다. 각 속성에서 중복적으로 다루는 내용이기 때문에 생략하고 INDEX_ROOT 영역만 다루겠다. ![[%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2023-05-31_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_5.40.24.png]] |Name|Offset|Size(Byte)|Description| |---|---|---|---| |Type of Attribute in Index|0x20|4|Index Entry가 담고 있는 속성에 대한 식별값 <br>ex) Index Entry 안의 내용이 속성이 아닌 경우, 0x00 <br>현재는 속성을 담고 있으니 속성의 Type 값인 0x30| |Collation Sorting Rule|0x24|4|Index Entry 간 정렬 형식 <br>- 0x00 : Collation Binary → 첫 바이트를 기준으로 이진 정렬 <br>- 0x01 : Collation File Name → 파일 이름을 유니코드 값 비교 정렬 (0x02와 특수문자처리 다름) <br>- 0x02 : Collation Unicode String → 파일 이름을 유니코드 값 비교 정렬 <br>- 0x10 : Unsigned Long → Little Endian 32bit에 대해서 오름차순 <br>- 0x11 : SID → SID 에 대해서 오름차순 <br>- 0x12 : Security Hash : 파일에 대한 Hash 값을 오름차순으로 정렬 후 SID 로 정렬 <br>- 0x13 : Multiple Unsigned Longs → 여러 바이트의 Little Endian 값의 오름차순| |Size of Index Entry - Bytes|0x28|4|Index Entry의 바이트 단위 크기 <br>대부분은 4096으로 고정값 가짐| |Size of Index Entry - Cluster|0x2C|1|Index Entry의 클러스터 단위 크기| |Padding|0x2D|3|| |Offset to First Index Entry|0x30|4|Index Node에서 첫번째 Entry의 시작 위치| |Total Size of the Index Entries|0x34|4|Index Entry 목록의 실제 크기 (헤더 포함)| |Allocated Size of the Index Entries|0x38|4|Index Entry 목록의 실제 할당된 크기 (헤더 포함)| |Flags|0x3C|1|Index Node 의 자식 노드 유무 <br>- 0x00 : 자식 없음 <br>- 0x01 : 자식 있음| |Padding|0x3D|3|| |File Reference Address of Filename|0x40|4|해당 파일이나 디렉토리의 File Reference 값| |Length of Index Entry|0x44|2|Index Entry의 총 크기| |Length of $FILE_NAME|0x48|2|Index Entry의 $FILE_NAME 속성 크기| |FLags|0x4C|4|마지막 노드 존재 여부 및 자식 노드 존재 여부 <br>- 0x01 : 자식 노드 존재 <br>- 0x02 : 마지막 노드| |Padding|0x4D|3|| |$FILE_NAME Attribute|0x50|-|$FILE_NAME t| |VCN of Child node in $INDEX_ALLOCATION|-0x08|8|$INDEX_ALLOCATION 속성에 위치한 자식 노드의 위치| > [!Question] Bytes vs Cluster? > > Size of Index Entry 항목을 보면 굳이 같은 내용을 두번 적어놓는다는 기분이 들 수 있다. > $INDEX_ROOT에서뿐만 아니라 다른 여러 항목들에서 실제 크기와 할당된 크기(클러스터 크기) 를 적어놓는 경우가 많다. > 이는 할당은 클러스터 단위로 하는데, 실제 파일 크기는 클러스터 단위가 아니기 때문이다. > 즉 남는 공간에는 미할당된 파일의 내용이 포함되어 있을 수 있다. > > 하지만 Index Entry 사이즈는 주로 4096 바이트가 할당되므로 별도로 남는 공간이 없다. > 그렇기에 1개 이상의 클러스터가 할당된다면 삭제된 엔트리 정보를 얻을 수 있게 된다. ### $INDEX_ALLOCATION(0xA0) INDEX 갯수가 많아짐에 따라 B+ 트리는 하위 노드를 생성한다. 즉 여러 노드가 존재함에 따라 모든 노드가 ROOT 노드에 존재할 수는 없다. 따라서 $INDEX_ALLOCATION 특성이 필요하게 되고, 루트 노드를 벗어나는 노드들을 다룬다. $INDEX_ALLOCATION 속성은 Non-Resident로 다루어지기 때문에 Cluster Run 구조를 참고해야 한다. 예시를 통해 알아보자. ![[%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2023-05-31_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_6.16.53.png]] 0x7D2000 경로에 가 보면 Index Record Header를 확인할 수 있다. 이 레코드 헤더 구조를 파악해 보도록 하자. 구조를 잘 살펴 본다면 Resident / Non-Resident 여부만 다를 뿐 구조 자체는 유사하다. ![[%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2023-05-31_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_6.39.40.png]] |Name|Offset|Size(Byte)|Description| |---|---|---|---| |Signature|0x00|4|`INDX` 라는 시그니처 값| |Offset to Fixup Array|0x04|2|Fixup Array 의 위치| |Number of Entries in Fixup Array|0x06|2|Fixup Array 내 Entry의 개수| |$Logfile Sequence Number|0x08|8|$LogFile에서 사용하는 트랙잭션 값| |VCN of Index Entry|0x10|8|$INDEX_ALLOCATION 안에서 Entry의 위치| |Offset to the First Index Entry|0x18|4|Index Node에서 첫번째 Index Entry의 시작 위치| |Total Size of Index Entries|0x1C|4|Index Entry의 실제 크기 (헤더 포함)| |Allocated Size of Index Entries|0x20|4|Index Entry의 할당 크기 (헤더 포함)| |Flag|0x24|1|Index 노드의 자식 노드 유무 <br>- 0x00 : 자식 노드 없음 <br>- 0x01 : 자식 노드 있음| |Padding|0x25|3|| 헤더와 마찬가지로 Index Entry 구조도 $INDEX_ROOT와 유사하다. 분리되어 있다는 점만 빼면 같다고 봐도 무방하다. | | | | | |---|---|---|---| |Name|Offset|Size(Byte)|Description| |File Reference Address of Filename|0x00|8|해당 파일이나 디렉토리의 File Reference 값| |Length of Entry|0x08|2|Index Entry의 총 크기| |Length of Content|0x0A|2|Index Entry의 $FILE_NAME 속성 크기| |Flags|0x0C|2|마지막 노드 존재 여부 및 자식 노드 존재 여부 <br>- 0x01 : 자식 노드 존재 <br>- 0x02 : 마지막 노드| |$FILE_NAME Attribute|0x10|-|$FILE_NAME 속성| |VCN of child node in $INDEX_ALLOCATION|-0x08|8|$INDEX_ALLOCATION 속성에 위치한 자식 노드의 위치| ### $BITMAP(0xB0) 하나의 파일시스템에서는 여러 파일의 존재를 다룬다. 이를 위해 $MFT 파일이 존재하고, 앞서 공부한 Index에 대한 정보 역시 존재했다. 이를 비롯하여 할당된 데이터들의 부가적인 정보를 저장하기 위해 사용되는 속성이 $BITMAP이다. 해석 그대로 비트에 대한(Bit) 지도(Map) 이므로 한눈에 파일이 할당된 건지(1) 미할당된 건지(0) 확인해 볼 수 있다. 지금까지는 실제 데이터를 예시로 설명했었지만, 비트맵은 그 수준이 쉽기 때문에 별도의 사진자료 없이 설명해 보려 한다. 어느 속성값과 동일하게 Attribute Header 영역 뒤에 등장하는 것이 비트맵이다. 비트맵은 그 크기만큼을 그대로 보면 된다. 만약 전체 파일시스템에 단 하나의 파일이 존재한다면 이때 비트맵은 `0000 0000 0000 0001` 일 것이다. 하나의 파일이 존재하기 때문에 쉽게 볼 수 있는데, 부가적인 설명을 통해 완벽하게 이해하고 가자. 첫번째 파일이 할당될 때 이 파일을 0번째 인덱스를 부여받게 될 것이다. 즉 비트맵 영역의 0번째 비트가 1로 설정된다. 같은 논리로 823498번째 인덱스를 부여받은 파일은 823498번째 비트의 값을 통해 그 할당 여부를 확인할 수 있게 된다. ### \$SYMBOLIC_LINK($REPARSE_POINT)(0xC0) 이번 절에서 다루는 내용은 $Reparse Point중에서도 가장 친근하게 접해볼 수 있는 $SYMBOLIC_LINK 에 대한 내용이다. 친근하다는 이유를 제외하고도, NTFS 3.0 이전에는 해당 속성이 온전히 $SYMBOLIC_LINK를 위해 사용되었다. NTFS 3.0 버전 다음부터는 여러 특징을 가지는 $REPARSE_POINT 속성으로 통합되었다. $REPARSE_POINT는 다음과 같은 내용들을 다룬다. - Mount - Junction - Symbolic Link - Deduplication - etc 심볼링 링크는 컴퓨터를 공부했다거나 관심이 있다면 한번쯤 접해보았을 내용이다. 주로 하드링크와 소프트링크를 더불어 심볼릭 링크라 하는데 이는 여기서 자세히 다룰 내용은 아니므로 다음에 다룰 기회가 있다면 다뤄보도록 하겠다. 그리고 이번 절에서는 Resident 헤더를 사용하는 $REPARSE_POINT 에 대해서 다루지만, 모든 $REPARSE_POINT 속성이 Resident로 구성된 것은 아니다. ![[%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2023-05-31_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_7.21.53.png]] | | | | | |---|---|---|---| |Name|Offset|Size|Description| |Common Header|0x00|16|| |Resident Header|0x10|8|| |Reparse Point Tag|0x18|4|Tag 값. <br>ex) 0xA000000C → 0xA000*(Type) + 0x000(Reserved) + 0xC(Flag) : IO_REPARSE_TAG_SYMLINK <br> <br>여러 태그 값에 대해서는 다음 링크를 참고하자. <br>[Reparse Point Tags](https://github.com/libyal/libfsntfs/blob/main/documentation/New%20Technologies%20File%20System%20(NTFS).asciidoc\#10-the-reparse-point)| |Reparse Data Size|0x1C|2|해당 속성 영역 크기| |Reserved|0x1E|2|예약된 영역 <br>보통 0으로 채워짐| |Substitute Name Offset|0x20|2|대체 이름의 오프셋| |Substitue Name Length|0x22|2|대체 이름의 길이| |Print Name Offset|0x24|4|보여지는 이름의 오프셋| |Print Name Length|0x26|2|보여지는 이름의 길이| |Symbolic Link Flags|0x28|4|Flag 값 <br>-0x01 : Symlink Flag Relative → 대체 이름은 Symbolic Link를 포함하는 위치에서의 상대 경로 이름| |Print Name|*0x24|*0x26|보여지는 이름 <br>* 는 포인터 형식을 의미하며 *0x24는 0x24주소에 쓰인 값이 오프셋임을 의미.| |Substitute Name|*0x20|*0x22|대체 이름| ### $EA_INFORMATION(0xD0) ### $EA(0xE0) ### $LOGGED_UTILITY_STREAM(0xF0) ## Analysis Tool > [!info] WinHex: Hex Editor & Disk Editor, Computer Forensics & Data Recovery Software > WinHex hex editor, disk editor, RAM editor. Binary editor for files, disks, and RAM. Download HEX EDITOR. Sector editor. Drive editor. > [https://www.x-ways.net/winhex/](https://www.x-ways.net/winhex/) > [!info] 010 Editor - Pro Text/Hex Editor | Edit 220+ Formats | Fast & Powerful | Reverse Engineering > 010 Editor | Pro Text/Hex Editor | Edit 200+ Formats | Reverse Engineering | Data Analysis > [https://www.sweetscape.com/010editor/](https://www.sweetscape.com/010editor/) ## Conclusion 속성 종류가 여러개 있다 보니 텍스트 양이 좀 많다. 끊어서 포스팅 하려 했으나 모두 같은 내용을 다루고 있기 때문에 다같이 다루었다. 거의 몇주가 걸린 작업이지만 그만큼 얻어갈 수 있는 정보가 많고, NTFS 구성의 대부분을 이해했다고 해도 좋다. 사실 모든 내용을 외울수는 없다. 외우면 좋겠지만, 그걸 외워야 하는 환경에 놓인 것이 아니라면 빠르게 참조할 수 있는 능력을 기르는 것이 중요하다고 생각한다. 그런 관점에서 Forensic-cheatsheet는 참조 능력을 돕는 사이트이다. 많은 관심과 이용 바란다.