[Digital Forensic] NTFS 파일 시스템 (3)

 

NTFS 파일 시스템


(14) 사용자 편의 기능

14-1. 디스크 할당

  • 이 기능은 사용자별로 사용할 수 있는 공간을 할당하는 기능으로, 할당 정보의 일부는 파일 시스템 메타데이터 파일로 저장

  • NTFS 3.0 버전을 전후로 3.0 이전 버전에서는 MFT 열 번째 엔트리인 \$Quota에 저장

  • 이후 버전에서는 \$Extend 디렉토리에 존재하였으며, MFT 엔트리는 어떠한 것도 할당 가능

  • 3.0 이전 버전에서 할당 정보 저장을 위해 사용되는 \$Quota 파일은 할당 정보 관리를 위해 두 개의 인덱스를 사용

  • $O라는 인덱스가 첫 번째 인덱스인데, 해당 인덱스는 $SID와 소유자 ID를 연관시키는데 사용

  • 여기서 SID는 앞에서 알아보았던 Security ID가 아님

 

또 $Q라는 인덱스가 있는데 이 인덱스 소유자 ID와 사용자에게 할당된 바이트 크기, 할당 허용 용량 등의 내용을 관리하는데 사용된다.

 

할당 정보는 포렌식적으로 의미가 크며, 할당 정보를 통해 어떤 사용자가 어떤 큰 데이터를 가지고 있었는지 판별 가능하기 때문이다.

 

하지만 할당 정보의 업데이트는 운영체제 입장에서 부가적인 사항이라 업데이트가 주기적으로 되지 않는다.

 

그리고 이러한 정보들은 꼭 할당 정보를 통해서만 얻을 수 있는 것은 아니며, $STANDARD_INFORMATION 속성을 통해서도 이러한 정보를 얻을 수 있다.

 

디스크 할당 기능은 기본적으로 비활성화 상태이다.

 

 

14-2. 저널링

  • 해당 기능은 NTFS만의 고유한 기능이 아닌 다른 파일 시스템에도 존재하는 기능

  • 저널링의 목적은 신뢰성으로, 파일 시스템을 원래 상태로 되돌리기 위해 사용

  • MS에서는 NTFS의 저널링 기술을 로깅이라고 함

  • NTFS 저널링 로그는 MFT 세 번째 엔트리인 $LogFile이라는 파일에 저장

  • 로그 파일의 크기는 파일 시스템 전체 크기의 1~2%

  • 이 파일에는 별다른 속성은 존재하지 않으며, 로그 내용은 $DATA 속성에 저장

 

윈도우는 저널에 할당할 수 있는 최대 크기가 있는데 해당 크기를 저널이 모두 사용하면 저널 파일은 sparse 파일로 변경되고 변경된 파일 마지막에 계속해서 데이터를 추가한다.

 

파일 마지막에 새로운 클러스터를 추가할 때는 첫 번째 클러스터는 제거하고 sparse 파일로 변경한다.

 

 

$LogFile $DATA에 대한 속성 내용은 다음 그림과 같다.

 

[그림 1] $LogFile $DATA 속성 내용

 

[그림 1] 을 보면 재시작 영역과 로깅 영역 두 영역으로 $DATA 속성이 나누어져 있다.

 

 

재시작 영역

  • 운영체제가 어떠한 파일 시스템의 정리를 수행할 경우 어떠한 트랜잭션을 참고해야 하는지 판단하는데 도움을 주는 구조체

  • 성공적인 마지막 트랜잭션을 위한 어떤 로깅 영역을 가리키는 포인터를 포함

 

로깅 영역

  • 연속적인 레코드의 집합

  • 각 레코드는 LSN(Logical Sequence Number)이라는 64bit의 값을 가짐

  • 레코드에는 두 가지 유형이 있으며, 업데이트 레코드와 검사 지점 레코드가 있음

 

업데이트 레코드는 가장 흔히 볼 수 있는 레코드로 기본적으로 모든 레코드가 가지고 있는 LSN 값 외에 추가적인 주요 필드 두 가지를 갖는다.

 

주요 필드 두 가지는 다음과 같다.

 

  • redo 필드 : 어떤 동작이었는지에 대한 정보 저장

  • undo 필드 : 어떤 동작을 어떻게 원래대로 되돌리는지를 설명하는 정보 저장

 

위 필드들은 파일 시스템 트랜잭션이 수행되기 전에 생성되며, 파일 시스템 트랜잭션이 수행된 후 다른 업데이트 레코드를 생성하면 그 트랜잭션이 수행되었다는 것을 보여준다.

 

두 번째 유형인 검사 지점 레코드는 운영체제가 파일 시스템을 검증하려고 할 때 운영체제가 로그 파일의 여러 레코드들 중 어느 레코드에서 시작을 해야 하는지 알려준다.


(15) 변경 저널

  • NTFS 버전 3.0 이상에서만 존재하는 기능

  • 파일과 디렉토리들의 변경이 수행되는 것을 기록하는 기능이며, 그 기록은 파일로 저장

  • 해당 기능은 변경 사항을 목록화 해두어 기존에 변경 여부를 판단하려고 하였을 때 오래 걸리던 시간을 단축시켜 줌

  • 해당 기능은 응용 프로그램 수준에서 활성 상태를 변경할 수 있음

  • 기본적으로 해당 기능은 비활성화 상태

  • 해당 기능의 파일에는 64bit 값이 포함되어 있으며 저널이 활성화되거나 비활성화 되었던 시간을 해당 값으로 표현

 

해당 기능은 \Extend\UsrJrnl 파일을 사용하며, 이 파일은 $DATA 속성 두 가지를 가지고 있다.

 

하나는 $Max라는 이름의 $DATA 속성이며, 또 하나는 $J라는 이름의 $DATA 속성이다.

 

두 $DATA 속성은 레코드를 포함하고 있으며 각 레코드에는 파일 이름 변경 시간, 변경 타입이 저장된다.

 

각 레코드는 USN(Update Sequence Number)라는 이름의 64bit 값을 가지고 있다.

 

USN은 저널 내 바이트 오프셋에 해당하며, $STANDARD_INFORMATION 속성에 저장된다.

 

레코드의 크기는 파일 이름의 길이에 따라 다르다.


(16) 파일 생성 / 삭제

16-1. 파일 생성

NTFS의 기본 레이아웃은 파일이 할당될 dir 1 디렉토리가 이미 존재하며, 클러스터가 2048byte 크기이며, 할당할 파일(File.txt)의 크기는 4000byte이다.

 

  • 먼저 파일 시스템이 첫 번째 섹터를 읽고 부트 섹터의 클러스터 크기, MFT 시작 주소, MFT 엔트리들의 크기를 정함

  • 그 후 MFT 첫 번째 엔트리($MFT)를 참조하고 $MFT 파일의 $DATA 속성을 읽어 나머지 MFT 엔트리 레이아웃을 결정함

[그림 2] 파일 생성 과정 1번 과정

 

  • 파일 할당을 위하여 MFT 엔트리를 할당해야 하는데 파일 시스템은 이때 비할당 엔트리를 찾기 위해 $MFT 파일의 $BITMAP 속성을 참조하여 해석을 시도함

  • 해석이 끝나면 비할당 엔트리를 찾게 되는데 찾은 엔트리를 새로운 파일에 할당하고 $MFT 파일 해당 엔트리 비트맵을 1로 설정

[그림 3] 파일 생성 과정 2번 과정

 

  • 파일에 할당된 엔트리의 MFT 내부에서의 위치를 구한 후 파일에 할당한 엔트리가 예전에 다른 파일에 할당되었던 엔트리일 수 있으므로 엔트리를 초기화함

  • 초기화 후 속성들을 엔트리 내에 생성하고 시간 값은 현재 시간으로 업데이트함

[그림 4] 파일 생성 과정 3번 과정

 

  • 이번에는 파일에 클러스터를 할당하기 위해 MFT 일곱 번째 엔트리($BITMAP)을 해석하여 클러스터를 할당

  • 해당 시나리오에서 할당하려는 파일의 크기가 클러스터보다 크므로 2개의 클러스터가 필요하며, 연속적인 2개의 클러스터를 찾아 $DATA 속성에 할당

  • 그 후 $BITMAP 파일에서 해당 클러스터의 비트맵 값을 1로 설정하고, MFT 엔트리가 수정되어 파일 수정 시간이 업데이트 됨

[그림 5] 파일 생성 과정 4번 과정

 

  • 파일 이름 엔트리를 디렉토리 인덱스에 추가하기 위해 파일이 할당될 디렉토리를 MFT 여섯 번째 엔트리(.)를 참조하여 찾음

  • 그 후 파일 이름 엔트리를 디렉토리 인덱스에 추가하고 디렉토리에 접근하였으므로 마지막 접근 시간이 업데이트 됨

[그림 6] 파일 생성 과정 5번 과정

 

  • 찾은 dir 1의 엔트리인 MFT 엔트리 180에 새로운 인덱스 엔트리를 생성하여 File.txt에 할당

  • 이때 트리의 노드들은 재정렬 될 수 있음

  • 그 후 File.txt의 시간 값들이 업데이트 되고, 디렉토리의 타임스탬프들 또한 업데이트 됨

[그림 7] 파일 생성 과정 6번 과정

 

만약 NTFS 시스템에 디스크 할당이나, 저널링 기능이 활성화 되어 있다면 6번 과정이 끝나고 $Quota 파일이나 $UsrJrnl 파일 인덱스에 엔트리들이 생성 되었을 것이다.

 

 

16-2. 파일 삭제

 

삭제 시나리오의 NTFS 레이아웃은 생성 기본 레이아웃과 동일하다.

  • 생성 과정의 1번과 동일

  • dir1 디렉토리를 찾기 위해 MFT 여섯 번째 엔트리(.)를 참조하여 인덱스 조사 (이때 dir 디렉토리의 마지막 접근 시간이 업데이트)

  • dir 1 디렉토리를 찾은 후 dir1 디렉토리의 인덱스를 조사하여 File.txt를 찾음

  • dir1 디렉토리 인덱스에서 File.txt 엔트리를 제거하며, 이때 노드들은 재정렬 될 수도 있으며, 디렉토리의 시간 값은 업데이트 됨

 

파일 삭제 4번 과정의 그림은 다음과 같으며, 그림에는 표시되어 있지 않지만, dir1 디렉토리 $BITMAP 속성에 지워진 엔트리에 해당하는 비트가 1에서 0으로 변환된다.

 

[그림 8] 파일 삭제 4번 과정

 

  • $BITMAP 파일의 $DATA 속성에 File.txt에 해당하는 엔트리 비트를 1에서 0으로 설정하여 MFT 엔트리를 비할당 상태로 변경

[그림 9] 파일 삭제 5번 과정

 

  • 이제 마지막으로 File.txt 파일의 MFT 엔트리 $DATA 속성에 할당된 클러스터를 할당 해제하기 위하여 $BITMAP 파일의 해당 클러스터 비트를 1에서 0으로 변경

[그림 10] 파일 삭제 6번 과정

 

위 그림 6번에서 파일 이름이 지워지지 않은 것은 MFT 엔트리가 비 할당 상태일 뿐 속성 내용은 보존되어 있기 때문이고, 화살표들이 지워져 포인터까지 삭제되어 있는 것처럼 보이지만, 윈도우는 포인터를 삭제하지 않는다.

 

이미지는 할당 상태를 나타내기 위해 화살표를 지운 것뿐이다.


# Reference 

 

http://www.yes24.com/Product/Goods/8511539

[Digital Forensic] NTFS 파일 시스템 (2)

 

NTFS 파일 시스템


(7) B-tree

  • NTFS에서는 앞에서 언급했듯이 b-tree를 사용

  • NTFS는 많은 상황에서 인덱스 구조체를 사용

  • NTFS 인덱스는 정렬된 순서로 저장된 속성들의 모음을 일컫음

  • 인덱스가 제일 흔하게 사용되는 것이 디렉토리인데, $FILE_NAME 속성을 포함하기 때문

  • NTFS에서 인덱스는 이진 트리, b-tree로 정렬

 

이진 트리는 자료구조론에서 자주 언급되는 개념 중 하나지만, 여기서 언급은 생략하고 b-tree에 대해서만 설명한다.

 

b-tree는 이진 트리와 유사한 형태이지만, 노드 별로 자식 노드가 2개 이상이다.

 

b-tree에는 여러 종류와 규칙이 있지만 여기서는 b-tree에 대해서만 설명할 것이며 노드 삽입, 삭제에 대해서 이야기 해보자.

 

 

b-tree는 기본적으로 다음과 같은 구조이다.

 

[그림 1] b-tree 기본 구조

 

가칭으로 각 노드에 알파벳 이름을 붙여 놨다.

 

 

이제 위 기본 구조를 이용해 삽입, 삭제를 알아보도록 하겠다.

 

 

7-1. 삽입

 

먼저 위 기본 구조에 90이라는 값을 삽입해보자.

 

90이라는 값을 삽입하려고 시도할 경우 순서는 다음과 같다.

 

  • 값과 가장 가까운 값이 들어있는 노드를 찾음 (위 기본 구조에서 C 노드가 가장 적합)

  • 빈 공간이 있다면 빈 공간에서 삽입하고자 하는 값(90)을 삽입

  • 만약 삽입하려 하는 노드에서 원래 있던 값(80)과 삽입하려는 값(90) 중 원래 있던 값이 크다면 삽입하려는 값이 원래 있던 값 앞으로 옴

  • 현재 삽입하려는 값이 원래 있던 값보다 크므로 자리 이동 없이 원래 있던 값 뒤에 위치함 

 

위 과정을 거치면 다음과 같다.

 

[그림 2] 90 값을 삽입한 경우

 

이번에는 30이란 값을 삽입해보자.

 

이번의 경우는 노드가 값으로 꽉 차있을 경우 어떻게 삽입이 되는 지를 알아 보는 것이다.

 

  • 값과 가장 가까운 값이 들어있는 노드를 찾음 (위 구조에서 B 노드가 가장 적합)

  • 노드에 빈 공간이 없을 경우 해당 노드를 분열하여 새로운 노드 구성

  • 노드를 분열한 후 노드에 들어갈 후보 값(10, 20, 30) 중 제일 큰 값을 새로운 노드로 삽입하고, 남은 두 값(10, 20) 중 큰 값을 부모 노드로 삽입

  • 마지막으로 남은 값(10)은 원래 노드에 남겨 둠

  • 노드 분열로 인해 다른 노드가 변경되어 값들이 꽉 차 있다면 해당 값들을 비교하여 정렬

 

[그림 3] 30 값을 삽입한 경우

 

이제 [그림 3] 구조에 마지막으로 70이라는 값을 삽입해보자.

 

이 경우는 부모 노드 분열에 대해 알아보는 것이다.

 

  • 값과 가장 가까운 값이 들어있는 노드를 찾음 (위 구조에서 C 노드가 가장 적합)

  • 노드가 꽉 차 있다면 노드를 분열하여 새로운 노드를 구성 (이 과정은 30 값을 삽입할 때 과정과 같음)

  • 만약 새로운 노드를 구성하는 도중 부모 노드가 꽉 차 있다면 부모 노드도 분열하여 새로운 노드를 구성

  • 노드 분열로 인해 다른 노드가 변경되어 값들이 꽉 차 있다면 해당 값들을 비교하여 정렬

 

2번 과정에서 노드 분열 도중 80 값이 부모 노드에 삽입되지 못하는 상황이다.

 

이 때도 노드 분열을 하면 되는데, 위 구조에서 보면 새로운 노드를 하나 구성하고 새로운 노드에 20, 50, 80 값 중 제일 큰 값인 80을 삽입하고 나머지 값인 20, 50 값 중 제일 큰 값을 부모 노드로 삽입한다.

 

그리고 마지막으로 남은 값은 그대로 남겨둔다.

 

 

70값을 삽입한 경우는 다음과 같다.

 

[그림 4] 70 값을 삽입한 경우

 

삽입은 위와 같은 규칙으로 계속 노드를 생성해 나가면 된다.

 

 

7-2. 삭제

 

다음과 같은 구조에 b-tree가 있다고 가정하여 하나씩 살펴보자.

 

[그림 5] b-tree

 

[그림 5] 구조에서 50 값을 삭제하면 다음과 같은 구조가 된다.

 

[그림 6] 50 값을 삭제한 경우

 

이번에는 [그림 6] 구조에서 40 값을 삭제해보자.

 

  • 삭제하려는 값을 삭제 (위 구조의 경우 노드가 비어 버림)

  • 노드에 아무런 값도 없다면 부모 노드에서 큰 값이 빈 노드로 내려와 노드를 채우고, 오른쪽 노드에서 작은 값이 부모 노드로 올라감

  • 위 구조의 경우 A 노드에서 70 값이 C 노드로 오게 되며, D 노드에서 작은 값인 80이 부모 노드로 가게 됨

 

[그림 7] 40 값을 삭제한 경우

 

이번에는 90 값을 삭제해 보자.

 

  • 삭제하려는 값을 삭제 (위 구조의 경우 노드가 비어 버림)

  • 노드에 아무런 값도 없다면 부모 노드에서 큰 값이 빈 노드로 내려와 노드를 채우고, 오른쪽 노드에서 작은 값이 부모 노드로 올라감 (하지만 오른쪽 노드가 없음)

  • 오른쪽 노드가 없다면 빈 노드를 삭제하고, 빈 노드가 삭제된 구조에서 오른쪽 노드로 부모 노드 값 중 제일 큰 값이 내려옴

  • D 노드가 삭제되고 삭제된 구조에서 오른쪽 노드인 C 노드로 부모 노드 값 중 제일 큰 80 값이 내려오게 됨

 

[그림 8] 90 값을 삭제한 경우

 

삭제의 경우 노드 생성이 없기 때문에 계속 위와 같은 규칙으로 노드를 삭제해 나가면 된다.


(8) 인덱스 엔트리

 

NTFS에서 b-tree를 사용한다고 위에서 언급 하였는데, 해당 트리에서는 노드에 값을 저장하기 위해서 '인덱스 엔트리(Index Entry)'라는 데이터 구조체를 사용한다.

 

  • 인덱스 엔트리는 많은 타입들을 가질 수 있으며, 모두 표준 헤더 필드를 사용

  • 인덱스 엔트리는 노드의 구성원이며, 비어 있는 인덱스 엔트리는 노드의 마지막을 뜻함

 

인덱스 엔트리의 구조는 다음 그림과 같이 매우 단순하다.

 

[그림 9] 인덱스 엔트리 구조

 

인덱스 엔트리를 구성원으로 가지고 있는 노드들은 MFT 엔트리 속성 두 개에 따라 저장 방식이 달라진다.

 

만약 속성이 $INDEX_ROOT 속성이라면 항상 거주 속성을 가져 노드는 한 개만 MFT 엔트리에 저장된다.

 

만약 노드가 여러 개라면 $INDEX_ALLOCATION 속성이 할당되는 데 이 속성은 비거주 속성이다.

 

이 속성의 내용은 하나 또는 그 이상의 인덱스 레코드를 포함하는 버퍼(클러스터)인데, 인덱스 레코드는 인덱스 엔트리의 집합이다.

 

인덱스 레코드의 크기는 4096byte이며, 또 인덱스 레코드는 인덱스 엔트리들의 목록을 포함하고 있다.

 

인덱스 레코드의 주소는 0으로 시작한다.

 

[그림 10] 속성별 저장 방식

 

[그림 10]을 보면 인덱스 레코드에 할당 되지 않은 영역들이 있는데 이 영역들은 할당이 가능한 상태이다.

 

인덱스 레코드 할당 상태는 $BITMAP 속성에서 관리하는데, 새로운 노드를 트리에 할당하려고 할 때 $BITMAP 속성은 사용 가능한 인덱스 레코드를 찾게 된다.

 

인덱스 엔트리에는 자식 노드가 있는지를 판별하게 도와주는 플래그 값이 포함되어 있다.

 

자식 노드가 있다면 자식 노드의 인덱스 레코드 주소가 부모 인덱스 엔트리에 포함된다.


(9) 메타데이터

  • NTFS에서 파일 시스템을 전반적으로 설명하는 데이터를 포함하는 파일을 메타데이터 파일이라고 함

  • NTFS에서 모든 것이 파일로 할당되므로 메타데이터 파일은 파일 시스템 전체를 데이터 영역으로 보고 어디든지 위치할 수 있음 (부트코드는 예외이며, 정해진 곳에만 위치)

  • 메타데이터 파일들의 흥미로운 점을 일반 파일들과 비슷한 구조의 타임 스탬프를 가짐

  • 메타데이터 파일이 가지고 있는 타임 스탬프는 파일이 생성될 때 설정되기 때문에 분석 시에 유용하게 사용할 수 있음

 

9-1. $MFT

  • 메타데이터 파일 중에서도 가장 중요한 파일

  • 모든 파일과 디렉토리의 엔트리를 가짐

  • MFT의 레이아웃은 $MFT 파일을 분석함으로써 파악 가능

  • MFT의 첫 번째 엔트리이며, 해당 파일의 $DATA 속성의 내용은 MFT에 의해 사용되는 클러스터들을 포함

  • 파일 시스템이 시작할 때 되도록 크기가 작은 상태에서 시작되며, 파일들이나 디렉토리가 생성되면 그 크기가 커짐

  • 하지만 한 번 생성된 엔트리는 지워지지 않아 크기가 줄어들지 않음

 

9-2. $MFTMirr

  • 해당 파일은 MFT 엔트리들 중 중요한 엔트리들을 복사해 놓은 백업본

  • 일반 파일을 찾으려면 부트 섹터와 $MFT를 참조해야 하는데 부트 섹터나 $MFT가 손상되게 되면 일반 파일을 찾을 수 없게 되므로 이럴 때 백업본이 필요함

  • MFT의 두 번째 엔트리이며, 해당 파일의 $DATA 속성은 파일 시스템 중간에 있는 클러스터를 할당 받아, 적어도 아래의 엔트리들을 복사하여 저장

 

복사하여 저장하는 엔트리들은 다음과 같다.

  • $MFT

  • $MFTMirr

  • $LogFile

  • $Volume

 

9-3. $Boot

  • 파일 시스템의 부트 섹터를 포함하는 파일

  • MFT의 여덟 번째 엔트리

  • 해당 파일은 고정된 위치를 갖는 파일로, 이유는 해당 파일의 $DATA 속성 내용이 시스템 부팅에 필요하기 때문

  • $DATA 속성은 항상 파일 시스템 첫 번째 섹터에 위치

  • 부트 섹터는 각 클러스터의 크기, 파일 시스템의 섹터 수, MFT 시작 클러스터의 주소 등을 저장

  • $DATA 속성에서 부트 섹터를 위해 할당된 섹터를 제외한 나머지 섹터들은 부트 코드를 위해 할당 됨

 

$DATA 속성에는 기본적으로 16개의 섹터가 할당되지만, 실제로 부트 섹터를 8개의 섹터에만 할당 된다.

 

부트 코드는 간단하게 파일 시스템 부팅을 위해 사용되며, 운영체제를 적재하기 위해 사용되는 파일들의 위치를 찾아준다.

 

부트 섹터도 백업본이 존재하는데, 백업본은 볼륨 마지막 섹터나 중간 섹터에 존재한다.

 

 

9-4. $Volume

  • 해당 파일은 볼륨 레이블과는 다른 버전 정보를 포함하며, MFT의 네 번째 엔트리

  • 해당 파일에는 다른 메타데이터 파일에는 없는 고유 속성 2개가 존재

  • 해당 파일에는 $DATA 속성이 존재하지만, 크기는 0

 

고유 속성 2개는 다음과 같다.

  • $VOLUME_NAME : 볼륨의 유니코드 이름 저장

  • $VOLUME_INFORMATION : NTFS 버전과 오류 상태 저장

 

9-5. $AttrDef

  • 각 속성 타입을 위해 이름과 타입의 식별자 정보를 포함

  • MFT 다섯 번째 엔트리

 

 

9-6. $Bitmap

  • 해당 파일은 클러스터의 할당 상태를 결정하는 메타데이터 파일

  • MFT 일곱 번째 엔트리

  • 해당 파일 $DATA 속성은 파일 시스템 내 모든 클러스터와 매칭되는 1개의 비트를 가지고 있음

  • 비트가 1로 설정되면 해당 클러스터는 할당 상태인 것을 의미

  • 비트가 0으로 설정되면 해당 클러스터넌 비할당 상태인 것을 의미

 

 

9-7. $BadClus

  • 해당 파일은 불량 클러스터를 관리하는 메타데이터 파일

  • MFT 아홉 번째 엔트리

  • 해당 파일에는 $DATA 속성이 2개 존재

  • 하나는 기본적인 $DATA 속성으로 크기가 0

  • 나머지 하나는 $Bad라고 불리는데 sparse 파일이며, 클러스터가 손상되었다고 보고 될 시 클러스터 주소가 해당 속성에 포함 됨

  • 처음에 $Bad 라고 불리는 이 $DATA 속성에는 아무것도 포함 되어 있지 않음

 

 

9-8. $Secure

  • 해당 파일은 $SECURITY_DESCRIPTOR 속성에서 사용하는 파일

  • 보안 식별자를 저장하는 용도로 사용

  • 보안 식별자는 파일이나 디렉토리에 접근 제어 정책을 정의할 때 사용

  • 해당 파일은 MFT 엔트리 열 번째에 해당

  • NTFS 버전 3.0 이상에서만 사용

 

NTFS의 모든 파일이나 디렉토리에 할당 되는 $STANDARD_INFORMATION 속성에는 SID(Security ID)라는 하나의 식별자를 포함하는데, 이 ID가 $Secure 파일에 인덱스로 사용된다. (SID와 윈도우에서 사용자에게 할당하는 SID는 다름)

 

해당 파일은 $SDH, $SII 인덱스와 이름이 $SDS인 $DATA 속성을 포함한다.

 

$DATA는 실제 SID(Security ID)를 포함하고, 두 인덱스는 SID를 참조하기 위해 사용된다.

 

$SII 인덱스는 $STANDARD_INFORMATION 속성에 포함되는 SID(Security ID)로 정렬되는데 $Secure 파일의 SID를 확인할 때 $Secure 파일의 SID의 위치를 확인하기 위해 사용된다.

 

$SDH 인덱스는 SID(Security ID)의 해쉬에 의해 정렬된다.

 

만약 해쉬가 없다면 두 인덱스에 의해 SID가 생성된다.


(10) 속성

10-1. STANDARD_INFORMATION

  • 모든 파일과 디렉토리에 존재하는 속성

  • 포함하는 데이터로는 타임스탬프 세트 및 소유권, 보안, 할당 정책이 있음

  • 해당 속성 타입 ID는 16이며 윈도우 별로 고정된 크기를 가짐

  • 해당 속성이 가지고 있는 타임스탬프는 총 4개의 시간 값을 가지고 있음

 

4개의 시간 값은 다음과 같다.

  • 생성 시간 : 파일이 생성된 시간

  • 수정 시간 : $DATA 또는 $INDEX 속성 내용이 마지막으로 수정된 시간

  • MFT 수정 시간 : 파일 메타데이터가 마지막으로 수정된 시간

  • 접근 시간 : 파일의 내용에 마지막으로 접근한 시간

 

또한 이 속성은 읽기 전용, 시스템, 아카이브 등의 일반적인 속성을 위해 플래그 값을 하나 가진다.

 

이 플래그 값은 읽기 전용 등의 속성 뿐만 아니라 압축, sparse, 암호화 등의 속성 또한 설명해준다.

 

하지만 이 플래그는 해당 엔트리가 파일을 위한 것인지, 디렉토리를 위한 것인지에 대한 구분은 해주지 않는다.

 

NTFS에서의 타임스탬프는 1970년 1월 1일 UTC를 기준으로 현재 시간과의 차이를 100나노로 표현한 64bit 값이다.

 

 

10-2. $FILE_NAME

  • 모든 파일과 디렉토리는 해당 속성을 필히 가짐

  • 해당 속성의 타입 ID는 48이고, 크기는 기본적으로 66byte이지만, 파일 이름의 길이에 따라 유동적

  • 해당 속성은 UTF-16 유니코드로 인코딩 된 파일 이름을 포함

  • 해당 속성은 부모 엔트리의 주소를 포함하며, 이 정보는 MFT 엔트리 전체의 경로를 파악하는데 유용하게 쓰임

 

이 속성은 $STANDARD_INFORMATION 속성처럼 타임스탬프 값을 포함하고 있다.

 

하지만 윈도우는 $FILE_NAME 속성의 타임스탬프 값을 $STANDARD_INFORMATION 속성처럼 자주 업데이트하지 않고 아래와 같은 경우에만 $FILE_NAME 속성의 타임스탬프 값을 업데이트한다.

 

  • 파일 생성

  • 파일 이동

  • 파일 이름 변경

 

해당 속성은 $STANDARD_INFORMATION 속성과 같이 읽기 전용, 시스템, 아카이브, 압축, 암호화 등을 구분하기 위한 플래그 값을 포함하고 있다.

 

 

10-3. $DATA

  • 해당 속성은 데이터의 내용을 저장하기 위해 사용

  • 특별히 정의된 값이나 레이아웃을 가지고 있지 않음

  • 속성 타입 ID는 128이며, 크기는 내용에 따라 유동적

  • 해당 속성은 파일이나 디렉토리의 MFT 엔트리에 기본적으로 할당되기는 하지만, 직접적인 이름은 할당되지 않음

  • 이렇게 기본적으로 MFT 엔트리에 할당되는 $DATA 속성은 이름이 존재하지 않아도 되지만, 추가적으로 할당되는 $DATA 속성은 반드시 이름이 있어야 함

 

이러한 추가 $DATA는 어떤 데이터를 숨길 수도 있으며, 디렉토리의 목록을 확인할 때 보이지 않는다.

 

대부분의 포렌식 도구들은 ADS(Alternate Data Streams)라고 불리는 추가적인 $DATA 속성들을 보여준다.

 

$DATA 속성은 비인가된 접근을 막기 위해 암호화하거나, 공간 절약을 위하여 압축할 수 있다.

 

이러한 선택 사항은 속성 헤더의 플래그를 설정함으로써 사용할 수 있다.

 

 

10-4. $ATTRIBUTE_LIST

  • 해당 속성은 파일이나 디렉토리의 모든 속성들을 저장하기 위해 MFT 엔트리가 하나 이상일 때 사용되는 속성

  • 하나의 파일이나 디렉토리에는 65536개 속성이 올 수가 있지만 MFT 엔트리 하나에 이 속성들을 모두 저장한다는 것은 불가능

  • 그렇기 때문에 비기준 MFT 엔트리를 생성한 후 기준 MFT 엔트리에 해당 속성을 할당함

  • 해당 속성의 내용은 기준 MFT 엔트리에 저장하지 못한 속성 타입 ID와 저장하지 못한 속성이 포함된 비기준 엔트리의 주소로 이루어짐


(11) 타임스탬프

 

기본적으로 시간 정보는 파일의 속성 창에서 확인할 수 있고, 시간 값들은 $STANDARD_INFORMATION에 포함되어 있는 값들이다.

 

NTFS에서 시간 값이 업데이트 되는 조건은 FAT와 유사한데 그 조건은 다음과 같다.

  • 파일을 생성하거나 복사하면 생성 시간은 현재 시간으로 업데이트 됨

  • 마지막 수정 시간은 $DATA, $INDEX_ROOT, $INDEX_ALLOCATION 속성 값이 수정될 때 업데이트 됨

  • MFT 수정 시간은 어떤 속성이 수정되어도 업데이트 되며, 어떠한 파일을 Open한 것만으로도 업데이트 됨

  • 마지막 접근 시간은 메타데이터 또는 내용을 확인했을 때 업데이트 됨

 

참고로 우리가 파일이나 디렉토리의 속성 정보에서 보는 타임스탬프 값은 $STANDART_INFORMATION 속성의 값이다.


(12) 디렉토리 인덱스

  • NTFS에서는 앞에서 언급한 인덱스를 이용하여 디렉토리 내용을 구성

  • 인덱스 엔트리는 노드 값을 포함하며, $INDEX_ROOT, $INDEX_ALLOCATION 속성에 저장 됨

  • $INDEX_ROOT 속성에 저장된 값은 항상 트리 구조에서 루트 노드 값에 해당

  • $INDEX_ALLOCATION 속성에 저장된 인덱스 엔트리들은 트리 구조에서 리프 노드에 해당

 

그리고 $BITMAP 속성은 인덱스 레코드들의 할당 상태를 관리하는데 사용된다.

 

NTFS의 디렉토리들은 기본적으로 헤더, $STANDART_INFORMATION, $FILE_NAME 속성을 가진 MFT 엔트리를 가지고 있다.

 

또 디렉토리 인덱스의 엔트리들은 $FILE_NAME과 파일 참조 주소를 포함하고 있다.

 

$FILE_NAME 속성은 파일 이름, 비주류 정보, 크기 등의 정보를 포함하는데 윈도우에서는 이 값들 중 비주류 정보와 크기 정보를 업데이트한다.

 

이러한 이유로 이 정보들은 정확성을 가지고 있다.

 

 

NTFS 디렉토리 기본 계층 구조는 다음과 같다.

 

[그림 11] NTFS 디렉토리 기본 계층 구조

 

12-1. 루트 디렉토리

  • 파일 시스템 전체 경로에서 어떠한 파일을 찾으려고 할 때 가장 먼저 파악해야 할 것이 루트 디렉토리

  • NTFS에서는 루트 디렉토리가 항상 MFT에서 여섯 번째 엔트리에 위치

  • 해당 엔트리는 기본적으로 $INDEX_ROOT, $INDEX_ALLOCATION, $BITMAP 속성을 가짐

  • 모든 메타데이터 파일이 루트 디렉토리에 위치하며, 메타데이터 파일은 숨김 속성으로 인해 사용자에게는 보이지 않음

 

 

12-2. 파일과 디렉토리의 연결

  • NTFS에서는 하드 링크를 이용해 파일이 하나 이상의 이름을 가지도록 함

  • 해당 하드 링크 부모 디렉토리 인덱스에 할당되며 원본과 동일한 MFT 엔트리를 가리킴

  • MFT 헤더에는 링크 카운트라는 플래그가 있는데 해당 플래그는 하드 링크가 생성될 때마다 값이 하나씩 증가

  • 하드 링크는 사용자가 파일을 삭제하여도 파일이 디스크 상에 남아 있다면 계속 그 파일을 가리키고 있어 파일 복구 가능 여부를 판단하게 도와줌

  • MFT 엔트리에는 하드 링크를 위한 $FILE_NAME 속성이 존재

  • NTFS 3.0 이싱 버전에서는 재파싱 기능을 지원

 

재파싱 기능은 파일, 디렉토리, 볼륨들을 서로 연결해주는 기능으로, 이 기능은 디렉토리나 파일로 존재한다.

 

그 내용으로는 어떠한 것들을 연결하고 있는지에 대한 정보이다.

 

 

재파싱 기능에는 여러 종류가 있는데 그 종류는 다음과 같다.

  • 심볼릭 링크 : 파일과 파일 간의 연결

  • Junction : 디렉토리와 디렉토리 간의 연결

  • 마운트 : 디렉토리와 볼륨 간의 연결

 

재파싱 기능은 파일이나 디렉토리로서 존재한다고 위에서 언급하였는데, 재파싱 기능은 $STANDARD_INFORMATION과 $FILE_NAME, $REPARSE_POINT 속성을 가진다.

 

$REPARSE_POINT 속성은 연결 대상 파일이나 디렉토리 위치 정보를 포함하는 속성이다.

 

NTFS는 재파싱 기능의 경로를 기록으로 남기기도 하는데 이 기록은 \$Extend\$Reparse 파일 시스템 메타데이터 파일의 인덱스를 이용한다.

 

또 루트 디렉토리의 $DATA 속성에 마운트 경로를 기록하기도 하는데 이 속성은 $MountMgrRemoteDatabase라는 이름을 가진 $DATA 속성으로 마운트 대상 볼륨 목록을 포함한다.


(13) 오브젝트 식별자

  • NTFS 3.0 이상 버전에서는 지금까지 설명한 디렉토리/파일 이름, MFT 엔트리 주소를 제외한 다른 주소 지정 방법을 제공

  • 운영체제는 각 파일이나 디렉토리에 있는 128bit 고유한 오브젝트 식별자를 할당하여 파일의 이동이나 이름 변경 시에 해당 오브젝트 식별자를 이용하여 파일을 참조

  • 오브젝트 식별자가 할당되면 해당 MFT 엔트리에는 $OBJECT_ID 속성이 할당

  • 해당 속성에는 원본 도메인과 해당 파일이나 디렉토리가 생성되었던 볼륨 정보를 저장


# Reference

 

http://www.yes24.com/Product/Goods/8511539

[Digital Forensic] NTFS 파일 시스템 분석 (1)

 

NTFS 파일 시스템


(1) NTFS란 ?

  • Microsoft 사에서 설계한 파일 시스템 으로 윈도우 NT, 2000, XP, 2003, 2008, 7, 10 등 많은 버전에서 사용하는 파일 시스템

  • FAT는 이동형 디스크에 많이 사용되며 고정식 디스크에는 대부분 NTFS를 사용한다고 봐도 무리가 없음

  • 많은 특징들을 제공하는데, 많은 특징만큼 확장성도 뛰어남

  • 뛰어난 만큼의 복잡성을 가지고 있는 파일 시스템이기에 분석이 FAT처럼 쉽지만은 않음

  • 신뢰성, 보안, 대용량 장치를 지원하기 위해 설계

  • 특정 내용으로 데이터 구조체를 감싸는 포괄적 데이터 구조체(Wrapper)를 사용해서 확장성 제공

NTFS 명세는 MS에서 모두 공개하지 않아 부정확한 면도 없지 않아 있다.

 

NTFS는 많은 윈도우의 표준이며, 거의 모든 공개 유닉스에서도 지원할 만큼 범용적이다.

 

하지만 비 공식적 명세와 출시된 응용 프로그램들이 만나 파일 시스템을 생성하기 때문에 응용 프로그램 종속 속성과 파일 시스템의 일반적 속성을 구분하기가 힘들어졌다.

 

 

중요한 NTFS 기능은 다음과 같다.

  • b-tree 개념 (파일 클러스터 추적할 때 사용)

  • 클러스터의 대한 정보를 클러스터에 같이 저장

  • 대략 160억 바이트 용량 파일 지원

  • 접근 제어 (ACL 사용 가능)

  • 파일 압축

  • 유니코드 기반 파일 이름 지원, 긴 파일 이름 지원

  • 이동식 디스크, 고정식 디스크 모두 보안 기능 지원

 

NTFS의 레이아웃은 다음 그림과 같다.

 

[그림 1] NTFS 레이아웃

 

VBR

  • 도스 파티션의 MBR 영역과 비슷하게 부트 섹터와 부트 코드가 위치하고 있는 영역

  • 해당 영역 크기는 섹터 단위가 아닌 클러스터 크기에 따라 변동 됨

 

MFT

  • NTFS 시스템에서 가장 핵심적인 요소

 

Data

  • 여러 가지 데이터가 위치하는 영역

 

위와 같이 보면 레이아웃이 매우 간단해 보이지만 의외로 복잡하게 구성 되어 있어 분석이 까다로운 파일 시스템이다.

 

NTFS는 시스템 내에서 중요한 데이터가 파일로 취급된다.

 

다른 말로 하면 NTFS 시스템 내 관리 데이터 들이 파일로 취급 받는다.

 

이러한 이유로 관리 데이터들이 일반 파일처럼 파일 시스템 어떤 위치에도 위치할 수 있게 된다.

 

그래서 NTFS는 다른 파일 시스템들과 달리 특정 레이아웃을 갖고 있지 않다.

 

다만, NTFS 볼륨 첫 섹터에는 부트 섹터가 있고, 부트 섹터에는 부트 코드가 포함되어 있을 뿐이다.


(2) 클러스터

  • NTFS에서 파일은 속성의 집합이라고 할 수 있음

  • 일부 속성은 거주 속성으로 MFT 엔트리에 존재

  • 나머지 속성들은 비거주 속성으로 클러스터에 그 내용이 존재

 

NTFS에서 클러스터는 다른 파일 시스템과 마찬가지로 연속적인 섹터의 그룹을 의미한다.

 

클러스터 수는 2^2이어야 하며, FAT 파일 시스템과는 다르게 NTFS에서는 클러스터 주소가 0으로 시작한다.

 

클러스터 0은 파일 시스템의 첫 번째 섹터를 포함하며, 클러스터 주소를 섹터 주소로 변환하기 위해 다음과 같은 계산식을 적용한다.

 

클러스터 X 클러스터 별 섹터 수 = 섹터


(3) MFT

  • 파일 시스템의 모든 파일들과 디렉토리에 대한 정보를 포함하고 있는 것으로 NTFS의 핵심

  • 모든 파일과 디렉토리는 MFT에 꼭 하나의 엔트리를 가지고 있으며, 매우 간단

  • NTFS를 설계한 MS사에서는 MFT 엔트리를 파일 레코드(File Record)라고 부름

 

다음은 MFT 엔트리 구조이다.

 

[그림 2] MFT 엔트리 구조

 

엔트리 크기는 1KB이며, 헤더는 미리 정의된 목적을 갖는다.

 

속성 영역은 특정 목적을 갖는 작은 데이터로 이루어져 있다.

 

각 MFT 엔트리는 테이블 내 주소를 갖고, 해당 주소는 0부터 시작한다.

 

보통 엔트리 크기는 1KB이지만, 정확한 크기는 부트 섹터에서 정의한다.

 

MFT도 시스템 내에서는 하나의 파일로 취급되어 MFT를 설명하는 MFT 엔트리가 MFT 안에 포함되어 있다.

 

MFT를 설명하는 엔트리 이름은 $MFT이며, 해당 엔트리는 MFT의 디스크 위치를 설명한다.

 

MFT의 전반적인 레이아웃과 크기를 파악하려면 $MFT 엔트리를 참조해야 하며, MFT 시작 위치는 부트 섹터에서 정의한다.

 

$MFT 엔트리는 MFT 첫 번째 엔트리이므로 쉽게 $MFT 엔트리를 찾을 수 있다. 

 

MS는 MFT를 가능한 작게 시작하고, 필요할 때 크기를 확장할 수 있도록 NTFS를 설계하여 운영체제에 의해 파일 시스템이 생성될 때에는 MFT에 고정 엔트리 수의 엔트리를 생성한다.

 

볼륨 스패닝 등으로 저장 공간이 늘어날 시에는 MFT를 동적으로 늘려 파일 시스템을 크게 만들 수 있게 하였다.

 

그리고 한 번 생성된 MFT 엔트리는 지워지지 않는다.

 

엔트리 크기는 원래 부트 섹터에서 정의하지만, MS 모든 윈도우 버전들은 보통 1KB 크기를 갖는다.

 

MFT 헤더는 42바이트 크기이며, 12개 필드를 포함하고 있고, 나머지 982바이트는 비구조적으로 속성 값들을 포함하고 있다.

 

MFT 엔트리 첫 번째 필드는 시그니처인데, 보통 시그니처로는 'FILE' 문자열이 사용된다.

 

하지만, 엔트리 오류 등이 생길 시에 시그니처 필드는 'BAAD'라는 문자열을 갖도록 되어 있다.

 

또 MFT 엔트리는 엔트리 할당 상태, 타입 구분 필드 등이 있으며 파일이 하나의 엔트리만으로 설명되지 않을 경우 여러 엔트리를 사용할 수도 있다.

 

MFT 엔트리는 48bit 주소(파일 번호) 값을 가지며, 순차적으로 주소가 할당되고, 주소 시작은 0부터이다.

 

첫 번째 엔트리가 주소 0을 가지며, MFT 최대 주소는 MFT 크기가 증가할 때마다 변경된다.

 

또 MFT는 주소 외에 다른 순서 번호를 가지며, 해당 순서 번호는 16비트이고, 48bit의 주소와 조합되어 64bit의 파일 참조 번호를 생성하는데 사용된다.


(4) 메타데이터 파일

  • 볼륨의 모든 바이트가 파일로 할당되어 이를 관리하는 데이터를 저장할 파일이 필요

  • 위와 같은 다른 데이터의 관리 데이터를 저장한 파일을 메타데이터라 부름

  • MFT의 첫 16개 엔트리들로 예약되어 있으며, 사용하지 않는 엔트리들은 비할당 상태가 아닌 할당 상태

  • 오직 기본적이고 일반적인 정보만을 포함

  • 사용자에게는 보이지 않지만, 루트 디렉토리로 존재

  • 각 파일들은 '$'로 파일명이 시작되고, 첫 번째 문자는 대문자로 시작

 

다음은 MFT 메타데이터에 대한 목록이다.

엔트리 번호

파일 이름

설명

0

$MFT

MFT의 전반적인 레이아웃과 크기 설명

1

$MFTMirr

MFT 엔트리 복사본

2

$LogFile

메타데이터 트랜젝션 기록

3

$Volume

볼륨 레이블 / 식별자 / 버전 등 정보 저장

4

$AttrDef

식별자 값 / 이름 / 크기 등 속성 정보 저장

5

.

파일 시스템 루트 디렉토리 저장

6

$Bitmap

파일 시스템에 있는 각 클러스터 할당 상태 저장

7

$Boot

파일 시스템 부트 섹터와 부트 코드 저장

8

$BadClus

불량 섹터가 있는 클러스터 저장

9

$Secure

파일 보안과 접근 제어 정보 저장 

10

$Upcase

유니코드 문자의 대문자 저장

11

$Extend

파일 추가 정보 저장

12 ~ 15

이름 없음

만약을 위한 예약 파일

번호 없음

$ObjId

파일의 고유 ID 저장

번호 없음

$Quota

사용자별 할당량 정보 저장

번호 없음

$Reparse

Reparse point 정보 저장

번호 없음

$UsnJrnl

Usn 저널 정보 저장


(5) MFT 엔트리 속성

  • 속성은 많은 타입들이 있으며, 각각 속성들은 자신의 내부 구조체를 가짐

  • NTFS는 다른 파일 시스템과 달리 파일 내용에 대한 속성이 있음

  • 속성은 3개로 나누어져 있는데 한 개의 속성마다 헤더가 존재

[그림 3] MFT 엔트리 구조

 

속성 헤더는 속성 타입, 크기, 이름을 구분지으며, 해당 값들이 압축, 암호화가 되었는지를 식별하는 플래그 값도 포함하고 있다.

 

속성 내용은 형식과 크기가 정해져 있지 않다.

 

이로 인해 속성 내용의 크기가 엔트리 크기보다 커지는 경우가 발생하여 NTFS에서는 두 가지 속성을 통해 속성 내용의 저장 장소를 판단한다.

 

MFT 엔트리 속성은 대부분 거주 속성이지만, $DATA, $ATTRIBUTE_LIST와 같이 크기가 유동적인 것들은 비거주 속성이 될 수 있다.

 

  • 거주(Resident) 속성 : 속성 내용이 엔트리 크기보다 작은 경우 엔트리 내 속성 내용을 저장

  • 비거주(Non-Resident) 속성 : 속성 내용이 엔트리 크기보다 클 경우 외부에 별도 클러스터를 할당받아 해당 클러스터에 속성 내용 저장

 

두 속성의 결정은 속성 헤더에서 결정하며, 비거주 속성이 될 경우 MFT 엔트리 속성 헤더에는 할당 받은 클러스터 주소가 포함되게 된다.

 

[그림 4] 비거주 속성 

 

만약 속성이 비거주 속성으로 판명되어 클러스터를 할당 받아 속성 내용을 저장한다고 하더라도, 할당 받은 클러스터 크기를 초과하면 또 다른 클러스터를 할당 받아 저장하게 된다.

 

하지만 새롭게 할당 받은 클러스터는 연속된 클러스터일 수도 있지만, 대부분 비연속적 클러스터일 가능성이 더 높다.

 

이럴 때 NTFS에서는 클러스터 런(Cluster Runs)이라는 것을 활용하여 비연속적으로 할당된 클러스터를 효과적으로 관리한다.

 

그리고 Run이라고 하는 것을 이용하여 각 클러스터를 문서화한다.

 

이러한 run을 목록화 해둔 것을 runlist라고 하며, run의 구조는 run의 길이(클러스터 개수)와 클러스터 시작 오프셋(파일 시스템 처음 오프셋부터)으로 이루어져 있다.

 

속성에는 표준적인 유형들이 있는데 속성 타입들은 번호로 정의되어 있으며, MS에서는 해당 번호들은 식별자로 사용한다.

 

각 속성 타입은 이름을 가지고, 모두 대문자로 구성되어 있다.

 

그리고 MFT 메타데이터와 동일하게 '$'로 시작한다.

 

 

다음은 표준 속성에 대한 목록이다.

식별자

속성 이름

설명

16

$STANDARD_INFORMATION

플래그, 접근 / 수정 / 생성 시간, 소유자와 보안 ID 등 정보 저장

32

$ATTRIBUTE_LIST

다른 속성의 위치 정보 저장

48

$FILE_NAME

파일 이름(Unicode), 접근 / 수정 / 생성 시간 저장

64

$VOLUME_VERSION

볼륨 정보 저장(Windows NT만 존재)

80

$OBJECT_ID

파일 또는 디렉토리의 16비트 고유 식별자 저장(Windows 2000 이상 존재)

96

$VOLUME_NAME

볼륨 이름 저장

112

$VOLUME_INFORMATION

파일 시스템 버전과 다른 플래그들 정보 저장

128

$DATA

파일 내용 저장

144

$INDEX_ROOT

인덱스 트리의 루트 노드 저장

160

$INDEX_ALLOCATION

$INDEX_ROOT 속성에 연결되어 있는 인덱스 노드 정보 저장

176

$BITMAP

$MFT 비트맵 정보 저장

192

$SYMBOLIC_LINK

소프트 링크 정보(Windows NT만 존재)

208

$EA_INFORMATION

OS/2 응용 프로그램과의 호환성을 위해 사용(HPFS)

224

$EA

OS/2 응용 프로그램과의 호환성을 위해 사용(HPFS)

256

$LOGGED_UTILITY_STREAM

암호화된 속성에 대한 키와 정보 저장(Windows 2000 이상 존재)

 

위 표에서 목록화된 속성들이 모두 파일에 존재하는 것은 아니다.

 

대부분 기본 파일에 할당된 MFT 엔트리는 $STANDARD_INFORMATION, $FILE_NAME, $DATA 속성만 갖는다.

 

$STANDARD_INFORMATION 속성의 경우 보안, 임시 정보, 소유권 등을 나타내기 때문에 모든 파일과 디렉토리에 있어 강제적 속성이다.

 

$FILE_NAME 속성의 경우 파일 이름, 크기, 임시 정보 등을 나타내기 때문에 이 속성 또한 모든 파일과 디렉토리에 있어서 강제적 속성이다.

 

$DATA 속성은 파일 내용을 저장하는 속성으로 파일 내용이 엔트리 크기를 초과한다면 비거주 속성으로 판단되어 별도의 클러스터에 파일 내용을 저장하게 된다.

 

기본적인 $DATA 속성은 이름을 갖지 않지만, 비거주 속성으로 인해 추가적인 $DATA 속성이 생긴다면 해당 속성은 이름을 반드시 가져야 한다.

 

하지만, 해당 이름은 따로 정해진 것이 없으며, 디렉토리에 $DATA 속성에는 어떠한 내용도 저장될 수 있다.

 

모든 디렉토리는 $INDEX_ROOT 속성을 가지며, $INDEX_ROOT 속성은 해당 디렉토리 내에 위치한 파일들과 하위 디렉토리 정보를 포함한다. ($INDEX_ROOT, $INDEX_ALLOCATION 속성 이름은 일반적으로 $I30)

 

디렉토리가 커지면 $INDEX_ALLOCATION 속성과 $BITMAP 속성을 사용하게 된다.

 

또 디렉토리에도 $DATA 속성이 있을 수 있으며, 디렉토리에 있는 $DATA 속성에는 해당 디렉토리의 하위 디렉토리 목록과 파일 내용 등이 저장된다.

 

[그림 5] 기본 MFT 엔트리 속성

 

다른 여러 가지 속성들을 알아보기 전에 참고로 알아두어야 할 것이다.

 

바로 '기준 MFT 엔트리'와 '비기준 MFT 엔트리'라는 개념이다.

 

기준 MFT 엔트리는 MFT 엔트리에 속성이 65536개가 올 수 있는데 이 모든 속성의 헤더를 저장하려면 하나 이상의 MFT 엔트리가 필요하게 된다.

 

이런 경우 추가적인 MFT 엔트리가 필요한데 추가적으로 MFT 엔트리가 파일이나 디렉토리에 할당될 시 기존에 할당되어 있던 MFT 엔트리가 기준 MFT 엔트리가 된다.

 

쉽게 말하자면, 원본 MFT 엔트리가 아닌 추가적으로 할당된 MFT 엔트리가 비기준 MFT 엔트리가 되는 것이다.

 

기준 MFT 엔트리에는 하나의 $ATTRIBUTE_LIST 속성이 있고, 해당 속성은 파일 속성과 MFT 주소가 있는 목록을 포함한다.

 

그리고 비기준 MFT 엔트리에는 $FILE_NAME과 $STANDARD_INFORMATION 속성이 없다.


(6)스파스 속성(Sparse Attribute)

  • 압축 기능 중 하나이며, 파일에 0으로 채워진 클러스터를 제외하고 디스크에 기록하는 기능

  • NTFS에서도 이 기능을 속성으로 지원하는데 NTFS에서는 $DATA 속성 값을 이 속성으로 정의하여 하나의 파일을 압축

  • FAT 파일 시스템과는 다르게 제외된 0으로 채워진 클러스터를 위해 runlist에 0으로 채워진 클러스터에 대한 run을 하나 생성

 

기본적으로 run은 시작 클러스터 위치와 크기를 포함하지만, 0으로 채워진 클러스터를 위해 생성된 run은 데이터로 크기만 가질 뿐 시작 위치는 포함하지 않는다.

 

0으로 채워진 클러스터를 위한 run이라는 것을 표시하기 위한 플래그 값도 포함하며, 이러한 run은 'sparse run'이라고 한다.

 

[그림 6] Sparse run

 

 

RunList는 스파스 속성 클러스터의 RunList이다.

클러스터 번호

정보

종류

1

시작 위치 : 100, 길이 : 5

Run

2

시작 위치 : x, 길이 : 2

Sparse Run

3

시작 위치 : 160, 길이 : 5

Run

 

속성의 압축

  • NTFS에서 지원하는 속성 압축은 파일 시스템 수준의 압축으로 $DATA 속성이 비거주 속성일 때만 압축 가능

  • 속성이 압축되었는지 판단하는 것은 속성 헤더

  • $STANDARD_INFORMATION, $FILE_NAME 속성 플래그는 해당 파일이 압축된 속성을 포함하였는지 판단하도록 정보 제공

  • 속성 내용이 압축되기 전에 속성 내용은 유닛이라는 같은 크기의 단위로 나뉘게 됨 (압축 유닛 크기는 속성 헤더에서 결정)

 

압축 유닛이 생성될 때 발생할 수 있는 경우가 3가지 정도 있는데 이는 다음과 같다.

 

  • Sparse run이 압축 유닛 크기로 만들어지는 경우, 모든 클러스터는 0을 포함하게 되고 디스크 공간에 할당되지 않음

  • 압축될 때 압축 결과는 저장을 위한 같은 수의 클러스터가 필요한데, 이 경우 압축 유닛은 압축되지 않고 하나의 run이 원본 데이터로 만들어짐

  • 압축될 때 압축 결과는 적은 양의 클러스터를 사용하며, 이 경우 압축 결과를 디스크에 run으로 압축 후에 저장하고, sparse run은 전체 run 길이와 압축 유닛에 클러스터 수를 같도록 하기 위해 압축된 run 뒤에 위치하게 됨

 

속성의 암호화

  • NTFS는 속성을 압축하는 기능 뿐만 아니라 암호화하는 기능도 있음

  • OS별로 보았을 때 윈도우를 제외한 OS는 여러 가지의 속성을 암호화할 수 있고 윈도우는 $DATA의 속성만을 암호화

  • 암호화 시 속성 헤더를 제외한 속성 내용만 암호화

  • $LOGGED_UTILITY_STREAM 속성이 암호화 된 파일을 복호화하기 위해서 사용하는 복호화 키를 포함

  • NTFS에서는 암호화 알고리즘으로 3DES 알고리즘을 사용

  • 3DES 알고리즘은 대칭 알고리즘인 DES를 연속으로 3번 적용한 알고리즘

 

복호화할 때 사용되는 난수 키는 암호화 된 각 MFT 엔트리를 위해 생성되며, NTFS에서는 'FEK(File Encryption Key)'라고 한다.

 

만약 MFT 엔트리에 여러 개의 $DATA가 있다면, 그것들은 모두 같은 FEK로 암호화 되는 것을 뜻한다.

 

FEK는 $LOGGED_UTILITY_STREAM 속성에 암호화 된 상태로 저장되는데, 해당 속성은 DDF(Data Decryption Fields)와 DRF(Data Recovery Filelds)의 목록을 포함한다.

 

DDF는 해당 파일에 접근하려는 모든 사용자를 위해 생성되는 것이며, 포함하는 데이터로는 사용자 SID, 암호화 정보, 사용자 공개 키로 암호화 된 FEK를 포함한다.

 

DRF는 데이터 복구를 위해 생성되는 것이며, 데이터 복구 공개 키로 암호화 된 FEK를 포함한다.

 

[그림 7] 암호화 과정

 

사용자 공개 키는 레지스트리 저장되며, 해당 키는 로그인 패스워드를 키로 하는 대칭 알고리즘으로 암호화되어 있다.

 

암호화가 되었다면 해당 내용을 사용자에게 보여주기 위해서는 복호화가 이루어져야 한다.

 

복호화 과정은 암호화된 FEK가 포함되어 있는 $LOGGED_UTILITY_STREAM을 참조하고, 참조하여 얻은 FEK를 사용자 공개 키로 복호화하여, 복호화된 FEK를 $DATA 속성 내용 복호화하는 것이다.

 

[그림 8] 복호화 과정

 

대부분 보안 도구들이 이러한 암호화를 풀기 위해 무작위 대입 공격 등을 시도하는 기능들이 들어있다.

 

하지만 성공률은 시간에 따라 달라 오래 걸릴 수 있고 짧게 걸릴 수도 있어 무조건적인 신뢰는 하지 않는 것이 좋다.

 

일부 디렉토리들과 파일들이 암호화 되어 있다면 암호화 되지 않은 파일 내용이 복사본이 불특정 비할당 영역 어딘가에 존재할 수도 있다.

 

이는 NTFS 설계 상의 취약점이며, 이러한 문제로 인해 평문 파일 내용이 저장된 EFS0, TMP 임시 파일이란 것이 생성되고, 이 파일은 MFT 엔트리가 재할당되지 않았다면 충분히 복구가 가능하다.

 

또 Swap 공간이나 페이지 파일 또한 암호화 되지 않은 평문 내용의 복사본을 포함하기도 한다.

 

하지만 이런 수고를 할 필요 없이 관리자나 도메인 컨트롤러, 해당 사용자 계정을 알고 있다면 바로 접근하고자 하는 암호화 파일에 접근하여 내용 확인이 가능하다.

 


# Reference

 

http://www.yes24.com/Product/Goods/8511539

Digital Forensic - FAT 파일 시스템 분석 (2)

 

FAT 파일 시스템


(9) 데이터 구조

 

부트 섹터

  • 파일 시스템 첫 섹터에 존재하며 FAT 파일 시스템 종류에 따라 조금씩 다름

  • 하지만 첫 36byte는 동일

 

다음은 부트 섹터의 36byte 오프셋 구조이다.

범위(Byte)

설명

범위(Byte)

설명

0 ~ 2

부트 코드 점프 명령

19 ~ 20

파일 시스템 섹터 개수

3 ~ 10

OEM 이름 (ASCII)

21 ~ 21

장치 타입

11 ~ 12

섹터 별 바이트(512, 1024, 2048, 4096)

22 ~ 23

FAT 영역 섹터 수

13 ~ 13

클러스터 별 섹터 수

24 ~ 25

저장 장치 트랙별 섹터 수

14 ~ 15

예약 영역의 섹터 크기

26 ~ 27

저장 장치 헤드 수

16 ~ 16

FAT 영역 개수

28 ~ 31

파티션 시작 전 섹터 수

17 ~ 18

루트 디렉토리가 포함하는 최대 파일 개수

32 ~ 35

파일 시스템 섹터 수

 

1) 부트 코드 점프 명령

  • 해당 부분은 부팅 파일 시스템이 아니면 설정되지 않아도 되는 부분

 

2) 섹터 별 바이트

  • 주로 512, 1024, 2048, 4096 바이트로 할당

 

3) 클러스터 별 섹터 수

  • 클러스터 당 섹터 수는 2제곱의 숫자만이 할당

 

4) FAT 영역 개수

  • 보통 2로 할당되지만 일부 작은 저장 장치에서는 1로 할당 되기도 함

 

5) 루트 디렉토리 최대 파일 개수

  • FAT 12 : 224

  • FAT 16 : 512

  • FAT 32 : 0

 

6) 파일 시스템 섹터 수

  • 2바이트로 표현되는 값보다 섹터 수가 많다면 0으로 설정 됨

 

7) 장치 타입

  • 디스크 유형에 따라 다른 값이 할당되는 부분

  • 고정식 디스크 경우 '0xF8', 이동식 디스크 경우 '0xF0'이 할당

 

8) FAT 영역 섹터 수

  • FAT 12 / 16의 FAT 영역 섹터 수를 나타내는 부분

  • FAT 32의 경우는 0이 할당

 

9) 파일 시스템 섹터 수

  • 위 2바이트로 표현되는 부분과 동일하나 차이점이 있다면 4바이트로 표현된다는 것

  • 2바이트로 표현이 안될 시 2바이트 부분은 0으로 설정되고 이 부분에 섹터 수가 설정 됨

  • 두 부분 중 한 부분은 무조건 0이 되어야 함

 

위에서 설명한 부트 섹터 영역 다음부터는 FAT 12 / 16과 FAT 32가 다르다.

 

 

다음 표는 FAT 12 / 16의 부트 섹터 구조를 정리한 것이다.

범위(Byte)

설명

범위(Byte)

설명

0 ~ 35

부트 섹터

43 ~ 53

볼륨 레이블

36 ~ 36

BIOS INT13h 드라이브 번호

54 ~ 61

파일 시스템 타입 레이블

37 ~ 37

사용 x

62 ~ 509

사용 x

38 ~ 38

확장 부트 시그니처

510 ~ 511

시그니처 (0xAA55)

39 ~ 42

볼륨 시리얼 번호

   

 

1) 확장 부트 시그니처

  • 고정 값으로 0x29를 가짐

 

2) 볼륨 레이블

  • 파일 시스템 생성 날짜 등을 확인할 수 있는 값

 

다음 표는 FAT 32의 부트 섹터 구조를 정리한 것이다.

범위(Byte)

설명

범위(Byte)

설명

0 ~ 35

부트 섹터

64 ~ 64

BIOS INT13h 드라이브 번호

36 ~ 39

FAT 영역 섹터 수

65 ~ 65

사용 x

40 ~ 41

FAT 구조체 저장 결정 비트

66 ~ 66

확장 부트 시그니처

42 ~ 43

주 / 부 버전 번호

67 ~ 70

볼륨 시리얼 번호

44 ~ 47

루트 디렉토리 클러스터 위치

71 ~ 81

볼륨 레이블

48 ~ 49

FSINFO 구조체 섹터 위치

82 ~ 89

파일 시스템 타입 레이블

50 ~ 51

부트 섹터 복사본 섹터 위치

90 ~ 509

사용 x

52 ~ 63

예약 영역

510 ~ 511

시그니처 (0xAA55)

 

1) FAT 구조체 저장 결정 비트

  • 만약 7번째 비트 자리가 1이라면 여러 FAT 구조체들 중 하나만 활성화된 것을 의미

  • 활성화 FAT 구조체 번호는 비트 0 ~ 3자리를 이용해 나타냄

 

2) 확장 부트 시그니처

  • 고정 값으로 0x29를 가짐

3) 볼륨 레이블

  • 파일 시스템 생성 날짜 등을 확인할 수 있는 값

 

공통적으로 시그니처 값 전에 사용하지 않는 영역이 있는데 이 부분은 특별한 목적이 없기 때문에 사용되지 않는다고 표현하였지만, 일반적으로는 부트 코드와 오류 메시지를 저장한다.

 

 

FSINFO 구조체

  • FAT 32에만 존재하는 구조체

  • 운영체제가 새로운 클러스터를 어디에 할당하는지 설명하는 역할을 담당

 

다음은 FSINFO 구조체 오프셋 구조이다.

범위(Byte)

설명

범위(Byte)

설명

0 ~ 35

시그니처 (0x41615252)

492 ~ 495

다음 할당 클러스터 번호

4 ~ 483

사용 x

496 ~ 507

사용 x

484 ~ 487

시그니처 (0x61417272)

508 ~ 511

시그니처 (0xAA550000)

488 ~ 491

비할당 클러스터 수

   

 

 

FAT 영역

  • 클러스터 할당 상태 파악

  • 어떠한 파일이나 디렉토리에 할당된 클러스터의 다음 클러스터 주소 파악

 

FAT은 보통 FAT 파일 시스템에서는 두 개가 존재하며, 정확한 번호는 부트 섹터에서 할당 한다.

 

첫 번째 FAT은 예약 영역 섹터 다음부터 시작하며, 부트 섹터에서 전체 크기를 할당 한다.

 

두 번째 FAT은 만약 존재한다면 첫 번째 FAT 마지막 섹터 다음부터 시작하며, 구성은 같은 크기의 엔트리들로 구성된다.

 

 

알아두어야 할 점은 엔트리에 Header와 Footer는 존재하지 않는다는 것이다.

 

각 엔트리 크기는 FAT 종류마다 다른데, 해당 종류 숫자 bit 크기를 갖는다. (예 FAT 12는 12bit)

 

엔트리 주소는 0부터 시작하며, 같은 주소의 클러스터와 맵핑된다.

 

클러스터가 할당되지 않은 엔트리는 다음 클러스터 항목에 0값을 가지고, 클러스터가 할당되면 0값이 아닌 파일이나 디렉토리에 할당된 클러스터의 다음 클러스터 주소를 갖게 된다.

 

마지막 클러스터 주소를 가지게 되면 엔트리에는 마지막 클러스터라는 어떠한 값을 가지게 되는데, 그 값은 FAT 종류마다 다르다.

 

  • FAT 12 : 0xFF8

  • FAT 16 : 0xFFF8

  • FAT 32 : 0x0FFF FFF8 

 

만약 위 값들 보다 작은 값을 가진다면 클러스터가 손상되었다는 의미이며, 할당되어서는 안 된다.

 

클러스터의 시작 주소는 2부터여서 FAT 영역에도 당연히 0과 1의 주소를 갖는 엔트리는 꼭 필요하지 않다.

 

보통 0의 주소를 갖는 엔트리는 미디어 유형 복사본을 저장하는 엔트리이고, 1의 주소를 갖는 엔트리는 파일 시스템의 불량 상태를 저장하는 엔트리로 사용된다.

 

부트 섹터에도 미디어 유형 종류를 저장하는 항목이 있지만, 윈도우는 부트 섹터 항목은 사용하지 않고 FAT 영역의 엔트리 0을 사용한다.

 

 

디렉토리 엔트리

  • 디렉토리 이름과 여러 데이터를 대신 설명해 주는 메타 데이터가 포함 되어 있음

  • 이런 엔트리들은 파일과 디렉토리 모두에 할당되며 엔트리 위치는 할당된 파일이나 디렉토리의 부모 디렉토리 클러스터에 위치

  • 엔트리에 저장되는 이름의 최대 길이는 확장자를 제외하고 8글자이며, 확장자는 최대 3글자

 

다음은 디렉토리 엔트리 오프셋 구조에 대한 정리이다.

범위(Byte)

설명

범위(Byte)

설명

0 ~ 0

파일 이름 첫 문자 할당 상태

18 ~ 19

접근 날짜

1 ~ 10

파일 이름 2번째 ~ 11번째 문자 (ASCII)

20 ~ 21

첫 번째 클러스터 주소의 상위 2바이트

11 ~ 11

파일 속성

22 ~ 23

수정 시간

12 ~ 12

예약 영역

24 ~ 25

수정 날짜

13 ~ 13

생성 시간

26 ~ 27

첫 번째 클러스터 주소의 하위 2바이트

14 ~ 15

생성 시간

28 ~ 31

파일 크기

16 ~ 17

생성 날짜

   

 

1) 파일 이름 첫 문자 할당 상태

  • 해당 필드는 디렉토리나 파일 이름 첫 번째 문자가 설정되는 부분

  • 해당 디렉토리 엔트리가 비할당 상태일 시 문자 대신 '0xE5' 또는 '0x00'이 설정 됨

  • 파일명이 8글자 이하일 경우 사용되지 않는 바이트는 'space(0x20)'으로 채워짐

 

2) 파일 속성

  • 00000001 : 읽기 전용

  • 00000010 : 숨김 파일

  • 00000100 : 시스템 파일

  • 00001000 : 볼륨 레이블

  • 00001111 : 긴 파일 이름

  • 00010000 : 디렉토리

  • 00100000 : 아카이브

 

3) 첫 번째 클러스터 주소 상위 2바이트

  • FAT 12 / 16의 경우 이 값은 0으로 설정 됨

 

4) 파일 크기

  • 해당 필드는 파일 크기를 나타내는 필드

  • 디렉토리일 때 0으로 설정 됨

 

디렉토리 엔트리 필드를 보면 타임스탬프 필드들이 여럿 보인다.

 

해당 필드들의 값들을 일반적으로 사용하는 날짜 형식으로 변환하는 과정은 다음과 같다.

 

1) 날짜 변환

  • 타임스탬프 값 중 날짜 값은 다음과 같은 규칙을 가짐

년 (0 ~ 127 유효)

월 (0 ~ 127 유효)

일 (1 ~ 31 유효)

15 14 13 12 11 10 9

8 7 6 5

4 3 2 1 0

 

먼저 hex 값을 2진수로 변환한다.

 

0x3116(예시, 생성 날짜) > 0011000100010110

 

 

다음으로 위 규칙대로 2진수를 끊어 10진수로 변환한다.

  • 0011000 > 30

  • 1000 > 10

  • 10110 > 26

 

년도의 경우 1980년도를 기준으로 하기 때문에 1980 ~ 2107년도까지 표현이 가능하다.

 

계산된 년도 값에 1980을 더해주면 계산이 완료된다.

 

변환 값 : 2010. 10. 26

 

 

2) 시간 변환

  • 날짜와 마찬가지로 시간도 규칙이 있음

시 (0 ~ 127 유효)

분 (0 ~ 59 유효)

초 (0 ~ 29 유효)

15 14 13 12 11

10 9 8 7 6 5

4 3 2 1 0

 

먼저 날짜 계산 과정과 마찬가지로 hex 값을 2진수로 변환한다.

 

0x5C7A (생성 시간) > 0101110001111010

 

 

다음으로 위 규칙대로 2진수를 끊어 10진수로 변환한다.

  • 01011 > 13

  • 100011 > 43

  • 11010 > 32

 

시간은 따로 더해주는 값이 없어 이대로 계산이 끝난다.

 

변환 값 : 오후 13시 43분 32초

 

 

현재 이러한 계산을 자동적으로 수행해 주는 도구가 많이 있으며, 대표적으로 DCode 도구가 이러한 도구들에 속한다.

 

 

LFN 엔트리

  • 디렉토리 엔트리에 포함되는 엔트리

  • 긴 파일명을 사용하는 디렉토리나 파일에 디렉토리 엔트리가 할당되면 LFN 엔트리에 파일명이 저장 됨

  • LFN 엔트리는 일반 엔트리보다 우선시 되어 짧은 이름을 저장하는 기본 엔트리 전에 목록화되며, 순서는 역순

 

다음 표는 LFN 엔트리 바이트 오프셋이다.

범위(Byte)

설명

범위(Byte)

설명

0 ~ 0

일반 헤더

13 ~ 13

체크섬

1 ~ 10

파일 이름 문자

14 ~ 25

파일 이름 문자 6 ~ 11 (유니코드)

11 ~ 11

파일 속성

26 ~ 27

예약 영역

12 ~ 12

예약 영역

28 ~ 31

파일 이름 문자 12 ~ 13 (유니코드)

 

1) 순서 번호 또는 할당 상태

  • 순서 번호는 0x40과 OR 연산되어 할당 상태일 경우 설정 됨

  • 비할당 상태이면 0xE5로 설정 됨

 

파일 이름의 경우 사용되지 않는 바이트 필드들은 0xFF로 채워지며 파일 이름의 끝은 NULL (0x00)로 채워진다.

 


(10) 포렌식 측면에서의 관점

 

슬랙 공간

  • 파일 크기가 클러스터에 맞지 않아 발생하는 빈 공간

  • 파일에 할당된 클러스터가 파일보다 크더라도 클러스터 전체가 할당되며 파일이 사용하고 남은 클러스터 공간이 슬랙 공간이 되는 것

  • 일부 슬랙 공간은 한번 할당되고 다시 할당되지 않아 이전에 할당되어 쓰여진 데이터들이 남아 있을 수 있음

 

슬랙 공간 중 'RAM 슬랙 공간'이라고 부르는 공간이 있는데 이 공간은 운영체제가 파일 내용을 무엇으로 채우는지 결정하도록 한다.

 

그러나 대부분 0으로 채우게 된다.

 

RAM 슬랙 공간 말고 또 다른 공간이 있는데 이 공간은 클러스터의 비사용 섹터가 있는 공간이다.

 

앞에서 말했던 한번 할당되고 다시 할당되지 않은 슬랙 공간이 이 슬랙 공간을 말하는 것이다.

 

 

모든 파일 시스템은 슬랙 공간이 존재할 수 밖에 없다.

 

섹터 단위로 할당을 하기 때문에 슬랙 공간이 발생한다.

 

파일 시스템에서는 슬랙 공간이 할당된 데이터로 간주되기 때문에 만약 분석 시 파일 시스템에서 슬랙 공간을 분석하기 위해 비할당 데이터를 추출한다면 도구로부터 슬랙 공간을 추출받지 못한다.

 

[그림 1] 슬랙 공간

 

FAT 파일 시스템은 데이터 구조체가 다른 파일 시스템들에 비해 수가 적고 그 구조가 단순하다.

 

FAT의 부트 섹터와 FAT 엔트리는 파일 시스템 분석 도구가 자동으로 분석할 때 참조하는 아주 중요한 영역들로 필수적인 영역들이며, 디렉토리 엔트리는 응용 프로그램 도움 없이 삭제 된 파일을 복구하는데 참조되는 중요한 영역이다.

 

파일을 복구하길 원한다면 이 3가지 영역을 분석해야 하며 숨겨진 데이터가 있는지 확인하고 싶다면 각 비할당 영역이나 슬랙 공간을 분석해야 한다.

 

예를 들어, 부트 섹터 영역에는 시그니처 필드 앞 부분에 사용되지 않는 공간들이 존재한다.

 

이 부분은 부팅 파일 시스템일 경우 부트 코드를 저장하는 영역으로 사용하지만 부티 파일 시스템이 아닌 일반 저장 용도로 사용되는 파일 시스템이라면 빈 공간으로 남게 된다.

 

이렇듯 각 영역의 구조들을 살펴보면 사용되지 않는 공간들이 조금씩은 존재한다.

 

악의적 사용자는 이러한 공간들을 이용해 자신의 데이터를 숨기려고 할 것이며, 이러한 비할당 영역 말고도 슬랙 공간도 분석을 진행해야 한다.

 

FAT에서는 대표적으로 볼륨 슬랙이 존재한다.

 

파일 시스템과 볼륨 마지막 사이를 말하는 것이며, 이와 같은 볼륨 슬랙에도 악의적 데이터가 숨겨져 있을 가능성이 농후하다.

 

볼륨 슬랙을 찾기 위해서는 파일 시스템 섹터 수와 볼륨 전체 섹터 수를 비교해 얼마만큼의 슬랙 공간이 존재하는지 파악하는 방법이 있다.

 

볼륨 슬랙 공간을 파악하기 전에, 볼륨 슬랙 공간이 존재하는지, 사람에 의해 생성되었는지 확인하고 싶다면 주 부트섹터와 백업본 부트 섹터의 섹터 수를 저장하는 필드 값을 비교해 보면 된다.

 

 

FAT 영역은 시스템을 자동 분석할 때 중요하게 사용되는 영역이고, 그 안에 있는 디렉토리 엔트리는 응용 프로그램 수준의 기술 없이 삭제된 파일을 복구할 때 중요한 역할을 하는 엔트리이므로 필수적으로 알아두어야 할 부분이다.

 

대부분의 하드 디스크 등의 저장 장치들은 NTFS를 파일 시스템으로 많이 사용하지만 USB와 같은 이동형 저장 장치에서는 아직도 FAT을 사용하기 때문에 이동형 저장 장치를 분석하고 파일을 복구하려면 FAT에 대해 상세하게 알아두어야 할 필요가 있다.


# Reference

 

http://www.yes24.com/Product/Goods/8511539

[Digital Forensic] FAT 파일 시스템 분석 (1)

 

FAT 파일 시스템


(1) FAT (File Allocation System)

  • 흔히 SD 카드에서 많이 사용하는 파일 시스템

  • 파일 시스템 중 가장 간단한 구조를 가짐

  • 종류에는 FAT12, FAT16, FAT32가 있음

  • 모든 윈도우와 대부분 유닉스 기반 운영체제들에서 모두 지원

  • 보통 우리가 사용하는 디지털 카메라의 플래시 카드, USB 드라이브에서 볼 수 있음

 

FAT 파일 시스템은 간단 구조이기 때문에 여러 가지 기능들이 추가되어 정확하게 참조 모델로 구분하기 애매한 구조이다.

 

FAT 파일 시스템에는 중요한 두 가지의 구조체(디렉토리 엔트리, FAT)가 존재한다.

 

디렉토리 엔트리는 각 파일과 디렉토리를 데이터 구조체에 할당할 때 사용되는 구조체를 말한다.

 

 

디렉토리 엔트리에는 다음의 데이터가 포함된다.

  • 파일명

  • 크기

  • 파일 내용 시작 주소

  • 다른 메타 데이터

 

하나의 파일이나 하나의 디렉토리를 하나 이상의 클러스터에 할당했다면 FAT 구조체를 통하여 나머지 클러스터를 찾을 수 있다.

 

FAT 구조체에는 파일 다음 클러스터와 클러스터 할당 상태를 식별하기 위한 데이터가 포함된다.

 

위에서 FAT 파일 시스템 종류를 나열해 보았는데 종류들의 차이는 FAT 구조체 엔트리 크기에서 차이가 난다.

 

 

다음 그림은 디렉토리 엔트리 구조체와 FAT 구조체의 관계를 나타낸 것이다.

 

[그림 1] 디렉토리 엔트리와 클러스터, FAT 관계

 

FAT 파일 시스템의 물리적 레이아웃은 다음과 같다.

 

[그림 2] FAT 파일 시스템의 물리적 레이아웃

 

1-1. 예약 영역

  • 파일 시스템 참조 모델 데이터를 포함하는 영역

  • FAT12, FAT 16 파일 시스템 경우 해당 영역의 크기는 보통 1개의 섹터 크기지만 어떤 경우에는 부트 섹터에서 해당 영역 크기를 정의하기도 함

 

1-2. FAT 영역

  • 주 FAT 구조체와 부(백업) FAT 구조체를 포함하는 영역

  • 예약된 영역 바로 다음 섹터부터 시작

  • 해당 영역 크기는 FAT 구조체 수와 크기에 따라 달라짐

 

1-3. 데이터 영역

  • 파일과 디렉토리 내용을 저장하는 클러스터를 포함하는 영역


(2) 부트 섹터

  • 예약 영역 중에서도 볼륨 1번째 섹터에 위치

  • FAT 파일 시스템 물리적 레이아웃에서 예약 영역에 위치 (MS사에서는 BPB라 부름)

  • 파일 시스템을 설명하는 데이터를 포함하지만, FAT 종류(FAT 12 / 16 / 32)를 설명하는 데이터는 포함하지 않음

  • 부트 섹터 데이터를 참조하여 파일 시스템 종류를 결정 

 

FAT32 파일 시스템 부트 섹터에는 부트 섹터 백업본의 섹터 주소, 주/부 버전 번호와 같은 추가 데이터들이 포함되어 있다.

 

FAT32 파일 시스템은 섹터 0(부트 섹터)에 존재하는 원본이 손상되었을 때 부트 섹터 백업본을 사용 가능하다.

 

MS 문서에서는 원본 부트 섹터가 손상되었는지 자동 검사를 위해 '부트 섹터 백업본이 섹터 6(7번째 섹터)에 있어야 한다'고 설명한다.

 

또 FAT32 파일 시스템은 다음에 할당 가능한 클러스터 위치, 전체 크기에 대한 정보를 포함하는 FSINFO 구조체를 갖고 있다.

 

FSINFO 구조체에 포함되어 있는 데이터들은 운영체제를 안내하기 위해 존재하며, 안내만 하는 역할을 하므로 데이터 정확성을 보증하지 않는다.

 

 

필수 부트 섹터 데이터

  • FAT 파일 시스템 물리적 레이아웃 중 데이터 영역이 있는데 이 데이터 영역은 FAT 12/ 16과 FAT32는 차이를 가짐

  • FAT 12 / 16 파일 시스템 경우 데이터 영역 시작 주소는 루트 디렉토리 주소 다음으로 예약되어 있음

  • 하지만 FAT 32 파일 시스템 경우 루트 디렉토리는 데이터 영역 어디든지 위치 가능

  • FAT 파일 시스템 루트 디렉토리는 대부분 데이터 영역 시작 주소에 위치 

 

FAT 32 파일 시스템은 루트 디렉토리의 위치와 크기를 데이터 영역 시작에 불량 섹터가 있을 경우 루트 디렉토리가 적절하게 대처할 수 있도록 필요한 만큼 조절할 수 있도록 하였다.

 

반면 FAT 12/ 16 파일 시스템 루트 디렉토리는 부트 섹터에 정의된 위치와 크기로 설정된다.

 

FAT 32 파일 시스템 루트 디렉토리 시작 주소는 부트 섹터 처음에만 제공하고, 크기는 FAT 구조체에서 결정한다.

 

 

부가 부트 섹터 데이터

  • 필수 부트 섹터가 가지고 있는 데이터 외에 많은 추가 정보들을 포함

  • 해당 데이터들은 파일 시스템을 구동하기 위한 데이터들이 아닌 편의를 위한 데이터이므로 정확성은 보증되지 않음

  • 예로 OEM Name이 부가 부트 섹터 데이터에 포함 되며, OEM Name은 필수 데이터가 아니므로 사용자가 임의로 변경 가능

 

부트 코드

  • 파티션 테이블 처리와 운영체제 위치를 파악하는 명령어

  • FAT 파일 시스템의 부트 코드는 부트 코드를 완전하게 분리하는 유닉스 파일 시스템과는 다른 형태를 띄고 있음

  • 부트 섹터 첫 3Byte는 CPU에게 부트 코드의 나머지 설정 데이터로 이동하라는 기계어 코드(점프 명령어)

 

FAT 종류마다 부트 섹터로 예약되어 있는 바이트 단위 오프셋은 다음과 같다.

  • FAT 12 / 16 : 62 ~ 509

  • FAT 32 : 90 ~ 509

 

위 오프셋들은 부트 코드를 포함하고 있는 곳이기 때문에 일반적으로 다른 곳에 사용되지 않으며, 위 오프셋 다음에 오는 섹터들은 추가 부트 코드를 위해 사용될 수 있다.

 

또 FAT 파일 시스템은 부팅을 하지 않아도 부트 코드를 가지며, 해당 부트 코드는 해당 시스템을 부팅하기 위해 다른 디스크가 필요하다는 메시지를 출력하는 역할을 한다.

 

출력된 후 디스크 MBR 부트 코드에서 FAT 부트 코드를 호출한다.

 

호출 후 부트 코드는 적절한 OS 파일들을 위치시키고 적재하여 실행시킨다.


(3) 클러스터

  • 연속적인 섹터의 그룹

  • 섹터의 개수는 2의 제곱(1, 2, 4, 8, ...)이어야 함

  • 주소를 가지며, 0이나 1이 아닌 2라는 주소부터 시작 (1번째 클러스터는 클러스터 2가 됨)

 

첫 번째 클러스터 찾기

  • FAT 파일 시스템은 첫 번째 클러스터인 클러스터 2부터 시작하지 않아 위치를 쉽게 찾지는 못 함

  • FAT 파일 시스템은 모든 논리적 볼륨 주소가 논리적 파일 시스템 주소로 맵핑 되지 않음

  • 따라서 FAT 파일 시스템 예약 영역과 FAT 영역은 클러스터 주소를 사용하지 않음

 

첫 번째 클러스터를 찾는 방법은 FAT 12/16과 FAT 32가 서로 다르다.

 

FAT 12/16 파일 시스템의 경우 파일 시스템이 생성될 때 데이터 영역 첫 번째 섹터에 루트 디렉토리가 부트 섹터에서 정의된 고정 크기를 갖고 할당된다.

 

그래서 FAT 12/16 파일 시스템의 클러스터 2는 루트 디렉토리 다음 섹터를 포함하게 된다.

 

 

FAT 12/16 파일 시스템 클러스터 2 위치는 다음과 같다.

 

[그림 3] FAT 12 /16

 

이와 다르게 FAT 32 파일 시스템 경우 루트 디렉토리 유동성 때문에 데이터 영역 첫 번째 섹터를 클러스터 2가 포함된다.

 

즉 데이터 영역 첫 번째 섹터가 클러스터 2이다.

 

[그림 4] FAT 32

 

클러스터와 섹터 주소 변환

  • 클러스터와 섹터 주소 간에 변환을 위해서는 클러스터 2의 주소를 알아야 함

  • 또 클러스터 당 몇 개의 섹터를 포함하고 있는지도 파악 필요

 

다음은 클러스터 X (계산하고자 하는 클러스터)의 섹터 주소를 계산하는 기본 계산식이다.

 

(X - 2) x (클러스터 당 섹터 수) + (클러스터 2의 섹터 수)

 

역으로 섹터 S (계산하고자 하는 섹터) 가 포함되어 있는 클러스터를 계산하는 계산식은 다음과 같다.

 

((S 클러스터 2의 섹터 수) / (클러스터 당 섹터 수)) + 2

 

 

클러스터 할당 상태

  • FAT 구조체를 통해 알 수 있음

  • 보통 두 개의 FAT 구조체 복사본이 있는데 하나는 파일 시스템 예약 영역 이후에 존재

  • FAT 구조체는 파일 시스템 클러스터마다 하나의 테이블 엔트리를 가짐

  • 테이블 엔트리에는 각 클러스터 번호들이 데이터로 포함되어 있음  

 

테이블 엔트리에 포함되어 있는 번호들의 최대값은 다음과 같다.

  • FAT 12 : 12bit

  • FAT 16 : 16bit

  • FAT 32 : 32bit (하지만 28bit만 사용)

 

만약 테이블 엔트리에 포함되어 있는 값이 0이라면 해당 엔트리가 할당된 클러스터는 파일에 아직 할당되지 않은 것을 의미한다.

 

FAT 종류마다 테이블 엔트리가 갖고 있는 값 중 할당되지 않은 상태를 표시하는 값들이 있으며, 다음과 같다.

  • FAT 12 / 16 : 0xFF7

  • FAT 32 : 0xFFF FFF7

 

만약 어떠한 테이블 엔트리가 위 값을 가지고 있다면 해당 테이블 엔트리의 클러스터는 파일에 할당되지 않음을 의미한다.


(4) 디렉토리 엔트리

  • 파일과 디렉토리마다 할당되는 데이터 구조체를 말함

  • 크기는 32byte

 

디렉토리 엔트리는 다음과 같은 데이터를 포함한다.

  • 파일 이름

  • 파일 속성

  • 파일 크기

  • 클러스터 시작 주소

  • 날짜

  • 시간

 

디렉토리 엔트리는 위에서 보듯이 파일 이름을 포함하기 때문에 파일 이름 참조 모델의 역할도 수행한다.

 

디렉토리 엔트리 위치는 데이터 영역 어디든지 가능하며, 그 이유는 디렉토리에 할당된 클러스터가 해당 디렉토리 엔트리를 포함하기 때문이다.

 

디렉토리 엔트리는 클러스터처럼 고유 주소를 사용하지 않고 할당된 파일이나 디렉토리의 전체 이름을 사용한다. (표준 방법)

 

디렉토리 엔트리에는 위처럼 파일 속성이 포함되며, 파일 속성에는 7가지 항목이 있지만 모두 OS에서 필요로 하는 것은 아니다.

 

 

다음은 파일 속성 중 필수 속성이다.

  • 디렉토리 속성 : 서브 디렉토리를 위한 디렉토리 엔트리인지 구분하는 속성

  • 긴 파일명 속성 : 다른 레이아웃을 갖는 엔트리 유형인지 구분하는 속성

  • 볼륨 레이블 속성 : 하나의 디렉토리에만 설정되는 속성

 

다음은 나머지 4개의 부가 속성이다.

  • 읽기 전용 속성 : 파일 쓰기를 방지하는 속성

  • 숨김 속성 : 파일과 디렉토리 목록을 보여줄 때 사용자에게 해당 속성이 설정된 파일이나 디렉토리를 보여주지 않는 속성

  • 시스템 속성 : 시스템 파일로 구분하는 속성

  • 아카이브 속성 : 일반적인 파일 속성

 

디렉토리 엔트리에는 시간 정보도 포함되는데 세부적으로 나누어 보면 수정 시간(Modify), 접근 시간(Access), 생성 시간(Create)로 나누어진다.

 

디렉토리 엔트리의 할당 상태는 첫 바이트를 통해 알 수 있으며, 할당된 엔트리는 자신이 할당된 파일이나 디렉토리 이름을 사용하는데 할당 상태인 경우 자신이 할당된 파일명이나 디렉토리 명의 첫 글자가 첫 바이트가 된다.

 

하지만 할당되지 않은 상태라면 디렉토리 엔트리 첫 바이트는 '0xE5'로 설정된다.

 

 

클러스터 연결

  • 디렉토리 엔트리는 클러스터 시작 주소를 포함

  • FAT 구조체는 파일에 할당된 클러스터를 찾는데 사용

  • 클러스터 할당 상태는 FAT 엔트리 값이 0이 아니면 할당 상태이고 0이면 비할당 상태인 것으로 판단 가능

  • FAT 엔트리는 다음 클러스터 주소, 파일 끝(EOF), 불량 섹터가 있는 클러스터를 보여주는 값을 포함

 

다음은 디렉토리 엔트리와 FAT 엔트리가 클러스터를 찾을 때 어떻게 연관되는지를 보여준다.

 

[그림 5] 디렉토리 엔트리와 FAT 엔트리 관계

 

디렉토리

  • OS는 새로운 디렉토리가 생성되면 클러스터를 할당하고 0으로 초기화

  • 디렉토리 크기 필드를 사용하지 않는 경우 항상 0으로 설정

  • 디렉토리 크기 결정 방법은 '클러스터 연결' 원리와 동일

  • 생성 이후에는 생성 시간, 접근 시간, 수정 시간을 업데이트하지 않음 (디렉토리 생성 날짜 무결성을 검증하는데 사용하기도 함)

  • 이유는 디렉토리 생성 날짜와 시간은 디렉토리 내용의 '.' 와 '..' 의 생성 날짜와 시간이 동일하기 때문

 

만약 서로 값이 다르다면 이는 악의적 사용자에 의해 변경되었거나 시스템의 어떠한 응용 프로그램에서 수정했을 가능성이 있다.

 

 

디렉토리 엔트리 주소

 

디렉토리 엔트리 주소를 찾기 위해서는 파일명이나 디렉토리 명의 전체 이름을 사용하는 방법이 있지만, 이 방법에는 다음과 같은 두 개의 문제점이 존재한다.

 

1) 파일이 지워졌을 때의 충돌성

  • 1-1.txt 파일과 2-1.txt 파일이 있다고 가정

  • 파일이 지워지면 해당 디렉토리 엔트리는 첫 바이트가 0xE5로 설정되어 파일명이나 디렉토리명의 첫 글자가 지워짐

  • 이럴 경우 두 txt 파일은 -1.txt, -1.txt 파일명이 되어 이름이 충돌하게 됨

 

2) 디렉토리 엔트리 재할당

  • 디렉토리가 삭제된다고 하여 디렉토리 내용도 모두 데이터 영역에서 삭제되는 것은 아님

  • 삭제된 디렉토리 엔트리 자리에 새로운 디렉토리가 생기고 해당 디렉토리의 디렉토리 엔트리가 할당되면 디렉토리 내용들은 모두 고아 상태가 됨 (이러한 파일들을 고아 파일이라고 함)

 

고아 상태(클러스터 11의 상태)가 된 파일들을 일반 커맨드 명령어로는 접근할 수 없고 데이터 영역의 섹터를 전체적으로 분석해야만 찾을 수 있다.

 

다음은 고아 파일에 대한 내용이다.

 

[그림 6] 고아 파일

 

시간 값 할당

  • 디렉토리 엔트리에 포함되는 시간 값들은 부가적 데이터

  • 잘못된 값을 가지고 있을 수도 있음 

 

1) 생성 시간

  • 새로운 파일을 생성하면 새로운 디렉토리 엔트리를 할당하는데 이때 설정 됨

  • 다른 디렉토리나 다른 디스크로 파일을 이동시키면 이동시킨 디렉토리나 디스크로 옮겨진 원본 파일의 새로운 엔트리가 할당

  • 새롭헤 할당된 엔트리를 기존 원본 엔트리가 덮어 씌움 (생성 시간 변하지 않음)

  • 예외 경우가 있으며, 커맨드 명령어로 다른 디렉토리나 디스크로 이동시킬 시 생성 시간은 이동 시간으로 다시 할당

  • 복사의 경우 새로운 파일로 간주하여 새로운 엔트리가 생성되고 새롭게 생성 시간이 할당 됨

 

2) 수정 시간

  • 윈도우가 파일에 내용을 써 넣을 때 설정 됨

  • 속성이나 파일명은 수정 시간 업데이트에 영향을 주지 않음

  • 파일의 이동 및 복사할 시에 새롭게 할당된 엔트리는 원본 엔트리의 수정 시간을 할당 받음

  • 윈도우 경우 응용 프로그램이 파일에 접근하여 내용을 수정한 후 저장하지 않아도 수정 시간을 새롭게 할당

 

3) 접근 시간

  • 파일을 열 때나 클릭할 때 설정 됨

  • 파일을 열 때 할당 됨

  • 파일의 속성 창 버튼을 클릭하면 할당

  • 파일을 다른 볼륨으로 이동시킬 시 윈도우는 해당 파일의 내용을 참조하기 위해 파일에 접근하고 이때 접근 시간 또한 다시 할당


(5) FAT 파일 이름 관리

  • FAT은 파일명의 길이가 8보다 크거나, 이름에 특별한 문자가 있으면 디렉토리에 LFN(Long File Name) 타입을 추가

  • LFN 타입을 갖고 있는 디렉토리(파일)은 SFN(Short File Name)이라는 디렉토리 엔트리를 또 갖게 됨

  • LFN 엔트리는 시간, 크기, 시작 클러스터 정보를 포함하지 않아 SFN이 대신하여 해당 정보들을 포함하기 때문에 추가되는 것

  • LFN과 SFN 속성 항목은 같은 위치에 존재, LFN 엔트리의 경우 특별한 속성 값을 사용함

  • 해당 속성 항목을 제외한 나머지 바이트들은 UTF-16으로 인코딩된 13개의 유니코드 문자들을 저장하는데 사용

  • 만약 파일명의 길이가 13글자 이상이면 추가적으로 LFN 엔트리를 사용

  • LFN 엔트리는 SFN 엔트리와의 관계를 나타내는 체크섬을 포함

 

LFN 엔트리는 파일명만 포함하며 디렉토리 엔트리에 파일 할당이 비할당 상태로 전환되는 것은 LFN 엔트리가 비할당 상태로 전환되는 것을 뜻한다.

 

그리고 이때 디렉토리 엔트리 첫 번째 바이트가 '0xE5'로 설정된다.

 

LFN 엔트리들은 순서가 반대이기 때문에 파일명 첫 번째 부분이 SFN 엔트리와 가깝다.


(6) 파일 생성 및 삭제

 

파일 생성 과정

  • 디렉토리(dir)는 생성되어 있으며 클러스터 크기는 4096byte

  • 파일 크기는 5000byte라고 가정한 과정

 

1) 볼륨 섹터 0에서 부트 섹터를 참조하고, FAT 구조체와 데이터 영역, 루트 디렉토리 위치를 파악한다.

 

[그림 7] 1번 과정

 

2) 디렉토리를 찾기 위해 루트 디렉토리에서 각 디렉토리 엔트리를 해석하고, 찾으려고 하는 디렉토리 이름 및 속성을 이용하여 찾으려고 하는 디렉토리의 엔트리를 찾는다.

 

[그림 8] 2번 과정

 

루트 디렉토리에는 '.' 이 존재하지 않으나, 이미지에는 루트 디렉토리를 나타내기 위한 방편으로 추가하였다.

 

 

3) dir 시작 클러스터(10)의 내용을 읽고, 사용 가능한 디렉토리 엔트리를 찾아 파일 명을 입력한 후 할당 상태로 전환시킨다.

 

또 파일의 크기와 시간 값도 입력한 후 파일 내용을 위한 클러스터를 할당하기 위해 FAT 영역의 FAT 구조체를 이용한다.

 

FAT 구조체에는 파일명, EOF, 다음 클러스터 주소 데이터, 타입 등이 포함된다.

 

FAT 구조체로 클러스터를 할당한 후 클러스터 10의 File.txt 디렉토리 엔트리에 시작 클러스터를 입력하고, 할당된 클러스터에 파일 내용을 입력한다.

 

[그림 9] 3번 과정

 

4) 하지만 클러스터 크기보다 파일 크기가 더 커 또 하나의 클러스터를 할당한다.

 

클러스터를 할당하기 위해 FAT 영역의 FAT 구조체를 이용한다.

 

적당한 구조체를 통해 또 하나의 클러스터를 할당한다.

 

[그림 10] 4번 과정

 

5) 시작 클러스터의 FAT 구조체에서 EOF 데이터를 지우고 다음 클러스터 주소를 입력한다.

 

그 후 나머지 파일 내용을 새롭게 할당된 클러스터에 입력한다.

 

[그림 11] 5번 과정

 

추가 내용으로는 위 [그림 11]에는 나와 있지 않지만, 클러스터 101의 FAT 구조체는 EOF로 설정 되어 있다.

 

 

파일 삭제 과정

 

1) 파일 생성 과정 전체 과정처럼 파일의 클러스터 연결 확인까지 진행한다.

 

2) 클러스터 연결 확인을 수행했다면 해당 파일과 연관되어 할당되어 있는 클러스터의 FAT 구조체 엔트리 모두를 0으로 설정한다.

 

3) 그 후 디렉토리 엔트리의 첫 바이트를 '0xE5'로 변경하여 해당 파일을 디렉토리 엔트리에서 할당 해제시킨다.

 

 

위 과정을 거치면 다음 사진과 같다.

 

[그림 12] 삭제 상태

 

위 [그림 12]의 상태가 되면 커맨드 명령어나 탐색기로는 해당 파일에 접근이 불가능하다.


(7) 파일 복구

  • 파일 삭제 과정을 보면 FAT 엔트리가 0이 되고 디렉토리 엔트리가 비할당 상태로 바뀌면서 디렉토리 엔트리의 첫 바이트가 '0xE5'로 설정 됨

  • 파일을 복구하기 위해서는 파일의 시작 위치(시작 클러스터)와 크기를 알아야 함

  • 하지만 시작 클러스터만 알 수 있을 뿐 나머지 연계되는 클러스터는 정확하게 알지 못 함 

 

파일 시스템의 파일 클러스터들 배치는 다음과 같이 매우 다양하다.

 

연속적인 클러스터 할당의 경우

 

[그림 13] 연속 할당 클러스터

 

위 [그림 13]의 경우 파일 복구가 매우 쉽다.

 

시작 클러스터인 45를 시작으로 파일의 크기만큼인 클러스터 48까지만 복구해주면 되기 때문이다.

 

 

할당 클러스터 사이의 다른 클러스터

 

[그림 14] 클러스터 단편화

 

위 [그림 14]의 경우 파일 내용 클러스터 사이에 전혀 다른 파일의 할당 클러스터가 위치 하고 있어 시작 클러스터인 45부터 파일의 크기만큼 복구를 시도하면 47이라는 전혀 다른 파일의 할당 클러스터가 섞여 완전한 복구가 되지 않는다.

 

 

할당 클러스터 사이의 비할당 클러스터

 

[그림 15] 클러스터 단편화 (2)

 

위 [그림 15]의 경우도 두 번째 경우와 마찬가지로 복구 시도 시 비 할당 클러스터 때문에 완전한 복구가 되지 않는다.

 

이런 문제점 해결을 위해 파일을 지우기 전 디스크 파일 조각 모음을 통해 클러스터를 한 곳으로 모아야 한다.

 

파일 조각 모음을 할 경우 클러스터가 좀 더 연속적으로 배치되기 때문이다.

 

지워진 후 파일 조각 모음은 의미가 없으며 해당 클러스터들은 다시 할당될 수 있기 때문에 불필요하다.


(8) FAT 파일 시스템 종류 결정

  • FAT 파일 시스템은 여러 종류가 있지만 정작 파일 시스템은 그 종류를 결정하는 기능이 없음

  • FAT 파일 시스템은 데이터 영역의 클러스터 개수에 따라 종류 결정 가능

  • 클러스터 개수를 알기 위해서는 데이터 영역의 섹터 개수를 알아야 함

  • FAT 12 / 16 파일 시스템의 경우 루트 디렉토리는 FAT 영역 다음 데이터 영역 첫 번쩨 섹터에 위치하며, 이 영역 다음 클러스터 2가 시작

  • FAT 32 파일 시스템 경우 루트 디렉토리가 유동적이어서 클러스터 2가 데이터 영역 첫 번째에 위치

  • 이러한 루트 디렉토리 엔트리 개수는 부트 섹터에서 알 수 있으며 FAT 32 경우에는 0

 

다음은 루트 디렉토리 섹터 개수(루트 디렉토리 크기)를 계산하는 계산식이다.

 

((루트 디렉토리 엔트리 개수 x 32) + (섹터 별 바이트1)) / (섹터 별 바이트)

 

 

클러스터에 할당된 섹터 수(데이터 영역)는 파일 시스템 전체 섹터에서 예약 영역 크기, FAT 영역 크기, 루트 디렉토리 크기를 빼면 된다.

 

파일 시스템 전체 섹터 수 - 예약 영역 크기 - (FAT 구조체 개수 * FAT 구조체 크기) - 루트 디렉토리 크기

 

 

위 계산식의 계산으로 인해 데이터 영역의 크기가 나오고 이 값을 클러스터 별 섹터 수로 나누면 클러스터 개수가 나온다.

 

데이터 영역 크기 / 클러스터 별 섹터 수

 

 

각 FAT 종류는 데이터 영역 클러스터 개수가 다음과 같이 다르다.

  • FAT 12 : 4,085보다 작을 때

  • FAT 16 : 4,085보다 크거나 같을 때

  • FAT 32 : 62,525와 크거나 같을 때


# Reference

 

http://www.yes24.com/Product/Goods/8511539

[Digital Forensic] RAID & Disk Spanning

 

RAID & Disk Spanning


(1) RAID(Redundant Arrays of Inexpensive Disks)

  • 성능 향상을 위해 디스크 하나 대신 여러 개를 사용하는 중복 디스크 개념

  • 하드웨어 컨트롤러나 소프트웨어 드라이버가 여러 디스크들을 하나로 병합

  • 컴퓨터는 그 볼륨을 단일 디스크로 인식

 

예전에는 RAID가 고성능 서버 컴퓨터에서만 사용되었지만, 요즘은 일반 Desktop 컴퓨터에도 쓰이고 있다. 

 

RAID 기술에는 여러 레벨이 있고 각 레벨마다 신뢰성과 성능 향상 등의 정도가 다르다.

 

총 7가지 레벨이 있으며 그 레벨들에 대하여 알아보자.


(2) RAID 레벨

2-1. RAID 레벨 0

  • RAID Level 0은 스트라이핑 모드 (Striping Mode)라고도 함

  • 2개 이상의 디스크를 사용, 두 디스크에 데이터를 볼륨 묶음으로 교차하여 나열해 놓은 방식

  • 해당 레벨은 읽기/쓰기 성능에 향상을 제공하지만, 데이터가 나누어져 나열되어 있는 경우이기 때문에 하나의 디스크만 고장 나도 데이터를 복구할 수 없음

 

[그림 1] RAID Level 0

 

2-2. RAID 레벨 1

  • RAID Level 1은 미러링 모드 (Mirroring Mode)라고도 함

  • 동일한 디스크가 두 개 있는 것

  • 한쪽 디스크에 데이터를 입력할 때 다른 한쪽 디스크에도 동일한 데이터가 입력됨

  • 신뢰성에서는 선호되는 구조지만, 한 번 입력 시 두 번의 디스크 입력 퍼포먼스로 인해 성능 저하와 디스크 구성 비용이 2배로 들어 일반적으로 사용하지 않는 구조

 

[그림 2] RAID Level 1

 

2-3. RAID 레벨 2

  • RAID Level 0의 장점과 신뢰성을 향상시킨 구조

  • 패리티 코드를 사용, 디스크 고장 시 데이터를 복구할 수 없는 문제점을 해결

  • 패리티 코드 계산 시에 해밍 코드가 사용되며 패리티 디스크 개수는 (저장 디스크 개수 -1)

 

[그림 3] RAID Level 2

 

2-4. RAID 레벨 3

  • RAID Level 2를 개선시킨 구조

  • 패리티 코드를 포함하는 많은 디스크를 단 하나의 디스크를 사용하여 동일한 효과를 볼 수 있도록 함

  • 패리티 코드 계산은 XOR 연산을 통해 계산

 

[그림 4] RAID Level 3

 

2-5. RAID 레벨 4

  • 구조는 Level 3와 별반 다를 것 없음

  • 차이는 패리티 코드 계산에 있으며, Level 3 경우 바이트 단위로 패리티 코드를 계산

  • 그러나 Level 4는 미리 정해진 블록 단위로 패리티 코드 계산

 

[그림 5] RAID Level 4

 

2-6. RAID 레벨 5

  • Level 4의 단점을 개선한 구조

  • 각 데이터들의 변화가 많을 경우 패리티 비트 또한 변화해야 하기 때문에 빈번한 접근으로 인해 디스크에 부하 발생

  • 이를 방지하기 위해 패리티 비트 디스크를 따로 만드는 것이 아닌 데이터 디스크 내에 패리티 비트를 저장하는 방식 사용

 

[그림 6] RAID Level 5

 

2-7. RAID 레벨 6

  • 신뢰성에 기반을 둔 구조

  • Level 5의 경우 두 개의 디스크에서 동시에 오류 발생 시, 복구하지 못하는 단점이 있는데 이를 해당 레벨에서 패리티 디스크를 하나 더 추가하여 해결

  • 디스크 하나가 더 추가되었다보니 구현 시 추가 비용이 발생

  • 데이터 (A ~ E) Q가 레벨 6에서 추가된 패리티 코드

 

[그림 7] RAID Level 6

 

지금까지 알아 본 RAID 구조들은 표준 구조들이며 현재는 시스템 별로 다른 구조를 혼용하여 사용하고 있다.

 

RAID 볼륨을 생성하는 방법으로는 하드웨어 방식과 소프트웨어 방식으로 나뉘며, 두 가지를 알아보도록 하자.


(3) RAID 구성 방식

3-1. 하드웨어 방식

  • 해당 방식은 하드웨어 장비로 RAID를 구성하는 방식으로 두 가지 방식으로 나눌 수 있음

 

1) 독립된 컨트롤러 방식

  • 해당 방식은 독자적인 프로세서와 메모리, 입출력 장치 등을 갖고 있어 CPU 없이도 입출력이 가능하여 최적화된 성능 발휘 가능

  • 하지만 별도로 메인보드에 장착되는 이유로 인해 가격이 비쌈

  • 볼륨 부팅 등의 경우에서 일어나는 악의적 행위들에 대해 안정적이며, 독립적이어서 시스템이 고장 나도 영향을 받지 않음

 

2) 일반적인 디스크에 삽입하는 컨트롤러

  • 하나의 칩(Chip)에 모든 기능이 구현되어 있는 형태

  • 다른 하드웨어와 통합하여 사용할 수 있고, 기존 I/O 컨트롤러 등과도 교체가 가능

  • 가격은 비교적 독립된 컨트롤러 방식에서 사용하는 장치보다 저렴

  • 이 방식은 독립된 컨트롤러 방식과 얻어지는 성과물은 대부분 같지만, 기존 하드웨어에 장착되어 있는 방식이기 때문에 다른 시스템으로 이전하여 사용하기 어려움

 

[그림 8] 하드웨어 RAID 방식 기본 구조

 

 

3-2. 소프트웨어 방식

  • RAID 기능이 소프트웨어적으로 구현된 방식

  • 이 방식으로 RAID를 구현할 경우 사용자는 볼륨만을 확인 가능

  • 각 디스크에 직접 접근하기 위해 유닉스 수준의 저수준 장치를 이용해야만 함

  • RAID 기능을 지원하는 OS는 MS Windows NT, 2000, XP, Apple Mac OS X, Linux, Sun Solaris, HP-UX, IBM AIX 정도가 있음

  • CPU를 사용하기 때문에 하드웨어 RAID에 비해 많은 제약이 있고 성능이 효율적이지 못함

  • 하드웨어 방식과 마찬가지로 두 가지로 나뉨

 

1) 순수 소프트웨어 방식

  • 하드웨어 없이 소프트웨어로만 구현하는 방식으로 구현 비용 저렴

  • 그러나 RAID 기능이 OS에 로드되기 전인 부팅 시에 일어나는 악의적 행위나 여러 가지 에러에 대해 안전하지 못함

  • CPU를 사용하므로 해당 시스템 성능에 영향을 주며 시스템 에러나 고장으로 인해 얻어지는 결과물에 대한 무결성 보장 못함

 

2) 하이브리드 방식

  • 순수 소프트웨어 방식의 RAID 기능이 OS에 로드되기 전 안전하지 못한 점 해결을 위해 하드웨어와 혼합하여 구현한 방식

  • 실제 구현은 소프트웨어 방식이며, 도움을 주는 하드웨어는 메인보드에 설정된 RAID BIOS

  • 해당 방식은 결국 소프트웨어 방식이기 때문에 RAID 기능이 OS에 로드된 후 에러나 악의적 행위에 대한 안전 보장 못함

  • 다른 시스템으로의 이전이 쉽지 않음

  • 무결성 또한 보장 못함

 

[그림 10] 소프트웨어 방식 기본 구조


(4) RAID 포렌식

  • RAID 볼륨을 분석할 때에는 어떻게 이미징 해야 하는지 선택해야 함

  • 각각 디스크를 이미징할 지, 아니면 각 방식에 의해 생성된 볼륨을 이미징할 지 선택

 

4-1. 하드웨어 방식

  • 해당 방식에서 사용하는 컨트롤러 경우 비교적 저렴하지만, 저렴하지 않은 것들도 있어 만약 디스크를 개별적으로 이미징한 경우 컨트롤러 구입이나 자신이 사용하는 RAID 볼륨을 생성하여 분석 필요

  • 하지만 만약 분석해야 할 시스템에 고가의 컨트롤러를 사용하고 자신이 갖고 있지 않은 컨트롤러라면 해당 컨트롤러를 구입해서 사용해야함 (쉽지 않은 일)

  • 그렇기에 개별적 디스크를 이미징하는 것은 이런 경우 좋지 못함 (그렇다고 디스크 이미징을 안 하면 안 됨)

 

RAID 볼륨을 만들지 않고 디스크 자체를 제한적인 방법들(Strings Search)로 분석을 시도해야 한다.

 

다양한 방법이 있겠지만 쉬운 방법으로는 해당 컨트롤러 드라이버를 갖추고 있는 Live CD(Linux)들로 부팅하여 수집하는 것이 있다.

 

 

4-2. 소프트웨어 방식

  • 해당 방식 컨트롤러 경우 소프트웨어이기 때문에 디스크를 이미징 하여도 되고 RAID 볼륨을 이미징 하여도 크게 문제 없음

  • 두 방식 모두 볼륨 이미징 방식을 포함하게 되는데 볼륨을 이미징할 때는 비할당 영역도 세심하게 살피고 주의해야 함


(5) 디스크 스패닝

  • RAID와 비슷한 개념으로 여러 디스크를 하나의 큰 디스크로 운영체제가 인식하게끔 하는 기술

  • 하지만 RAID와 같이 성능 향상이나 중복성 등은 지원하지 않고, 오직 디스크 크기만을 늘려 줌

  • 이러한 점 때문에 통합되어 있는 디스크에 또 다른 디스크 추가나 파일 시스템 크기를 동적으로 늘릴 수 있음

 

많은 운영체제에서 디스크 스패닝 기술을 지원하고 있지만 이 글에서는 리눅스와 윈도우만 다룬다.

 

5-1. 리눅스 디스크 스패닝

  • 두 가지로 된 디스크 스패닝 기술이 있으며 MD, LVM으로 나눌 수 있음

 

리눅스는 부팅할 때 디스크 스패닝 볼륨을 마운트하지 않더라도 슈퍼블록 값은 업데이트 한다.

 

이를 이용해 커널이 디스크를 제거 했는지와 디스크 순서를 체크한다.

 

1) MD

  • 리눅스에는 'MD 드라이버'라고 불리는 드라이버가 있는데 이 드라이버는 도스 기반 파티션을 사용

  • 파티션이 할당된 순서대로 목록을 정리한 'etc/raidtab' 이라는 파일이 존재하는데 볼륨은 이 파일 없이 마운트 가능

  • 해당 파일 설정 값 중에 persistent-superblock이라는 항목 값이 0일 경우 설정 데이터들이 /etc/raidtab 파일 안에만 존재

  • 값이 1일 경우 설정 데이터들이 MD 장치를 생성할 수 있도록 디스크나 파티션 끝에 포함 됨 

 

이는 '자동 감지' 기능을 뜻하며 자동 감지 기능이 동작하기 위해서는 설정 데이터가 위치한 파티션 타입이 'Linux raid partition with autodetect using persistent superblock(0xfd)'이어야 한다.

 

부팅하는 동안 MD 장치가 생성된 것을 확인하려면 Messages 로그를 보면 된다.

 

MD 장치가 생성되도록 superblock이 설정되어 있다면 디스크나 파티션은 1024Byte로 나눠진 여러 구역의 구조를 갖는다.

 

각 구역에는 다음과 같은 정보가 포함되어 있다.

구역

정보

첫 번째 구역

디스크 스패닝 또는 RAID 버전, 디스크 수, 생성 시간, 식별자

두 번째 구역

마지막 업데이트 시간, 카운터, 볼륨 상태, 동작 중인 디스크와 오류난 디스크 수

나머지 구역

주/부 장치 번호, 볼륨 내 각 장치 역할, 디스크 상태

 

2) LVM 

  • Logical Volume Manager의 약자로, MD의 개선된 기술로 볼륨 그룹이라는 것을 사용

  • LVM을 사용하려면 파티션은 'Linux Logical Volume Manager Partition(0x8e)'이어야 함

  • 각 시스템에는 1개 또는 그 이상 볼륨 그룹이 있으며, 각 볼륨 그룹은 /dev/ 디렉토리에 하위 디렉토리를 가짐

  • 물리적 확장 세트를 볼륨 그룹을 이용하여 논리적 볼륨을 생성하는데 이는 물리적 확장 세트들을 연속적으로 연결하거나 스트라이핑을 사용하여 생성

  • 이렇게 생성된 볼륨은 /dev/ 볼륨 그룹 하위 디렉토리 내 장치 파일이 주어지며, 논리적 볼륨 설정 데이터는 로컬 시스템과 볼륨 두 곳에 저장 됨

  • 설정 파일 같은 경우는 '/etc/lvmtab, /etc/lvmtab.d'에 저장 됨 (설정 파일들은 바이너리 파일이며, vgimport, vgscan, vgchange 등의 유틸리티로 업데이트 됨)

 

[그림 11] LVM

 

위 [그림 11]에서 디스크 0과 1은 물리적 세트이고, 볼륨 그룹을 통해 생성된 디스크는 논리적 세트이다.

 

 

5-2. 윈도우 디스크 스패닝

  • 윈도우는 NT 버전 이후로 디스크 스패닝을 지원해 왔으며 사용하는 기술은 LDM

  • LDM은 기본 파티션, 디스크 스패닝, RAID 레벨 0, 1, 5와 유사하고 간단한 볼륨들을 지원

  • 기본 디스크들은 LDM이 사용되지 않으며 LDM이 사용되기 위해서는 디스크에 추가적 데이터 구조체가 포함 되어야 함

 

[그림 12] LDM(동적 디스크) 기본 구조

 

위 [그림 12]를 보면 LDM 파티션 영역 뒤에 LDM 데이터베이스라는 것이 있는데 이 영역은 동적 파티션을 정의하고 논리적 볼륨을 생성한 규칙을 만드는 곳이다.

 

이 영역은 다음과 같은 엔트리를 갖는다.

  • 디스크 엔트리 : 도스나 GPT 디스크가 있는 각 동적 디스크를 위해 존재

  • 파티션 엔트리 : 동적 디스크 파티션 방법을 설명

  • 컴포넌트 엔트리 : 파티션들의 결합 방법을 설명

  • 볼륨 설명 엔트리 : 파티션 컴포넌트 유형을 적용한 결과인 논리적 볼륨을 포현


(6) 디스크 스패닝 포렌식

  • 리눅스 MD 볼륨을 분석하기 위한 최선의 선택은 단일 드라이브 또는 파티션으로 볼륨을 수집하고 표준 분석 도구를 사용하는 것

  • 슈퍼블록이 설정되어 있다면 쉽겠지만, 그렇지 않다면 대상 시스템에서 /etc/raidtab 파일 생성 필요

  • 그 후 raidstart 명령어로 MD 장치 생성 후, dd 종류 도구로 MD 장치를 이미징 할 수 있음

  • 수집 후에 MD 장치를 정지시키기 위해 raidstop 명령어 사용 필요

 

리눅스 LVM 볼륨 분석은 MD 장치보다 분석을 더 자동화할 수 있다.

 

시스템으로부터 디스크를 분리하여 신뢰할만한 리눅스 시스템에 디스크를 결합하여 분석할 수 있고, LVM을 지원하는 Live CD(Linux)를 대상 시스템에 부팅 시켜 분석이 가능하다.

 

vgscan 명령어를 사용하면 '/etc/lvmtab, /etc/lvmtab.d' 파일이 자동 생성되는데, 자동 생성되면 vgchange -a y 명령어를 실행하여 볼륨을 활성화 시킨 후에 dd 종류 도구로 이미징 시도가 가능하다.

 

윈도우 LDM 경우 분석이 어렵고, 읽기 전용으로 볼륨을 재생성하는 것 또한 쉽지 않다.

 

Live CD(Linux)를 사용하여 LDM을 분석할 수 있는데 이는 조금 수정이 필요하다.

 

기본적으로 리눅스는 LDM을 지원하지 않아 커널 재컴파일을 해야 하며, 재컴파일된 커널은 데이터베이스를 읽고, 각 동적 디스크에 물리적 파티션을 위해 하드 디스크 장치를 생성하게 된다.

 

위와 같은 장치와 방법을 통해 이미징을 시도하면 된다.


# Reference

 

http://www.yes24.com/Product/Goods/8511539

+ Recent posts