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

 

EXT 파일 시스템


(13) 파일 생성 / 삭제

 

해당 시나리오에서 블록 크기는 1024Byte, 블록 그룹의 블록 개수는 8192개, 블록 그룹별 inode 개수는 2016개이다.

 

또 해당 시나리오에서는 inode 테이블 시작 블록이 5라고 가정하며, 루트 디렉토리 엔트리가 블록 260에 있다고 가정한다.

 

 

13-1. 파일 생성 과정

 

이 과정에서는 dir이라는 디렉토리가 있다고 가정, File.txt 파일을 생성한다는 가정 상황을 시나리오로 한다.

 

  • 일단 파일 시스템 1024byte 오프셋에 위치 하는 슈퍼 블록을 참조하여 블록 크기와 블록 그룹의 블록 개수, 블록 그룹 내의 inode 개수를 파악

  • 슈퍼 블록의 분석이 끝나면 그룹 기술자 테이블을 참조하며, 이 테이블은 각 블록 그룹의 레이아웃을 설명하며 블록 2 ~ 3에 위치

 

위 과정은 다음 [그림 1]과 같다.

 

[그림 1] 생성 과정 1

 

 

  • 파일을 생성할 디렉토리인 dir을 찾으려면 먼저 루트 디렉토리를 찾아야 함

  • 루트 디렉토리는 보통 inode 2를 사용하며, inode 2의 위치는 슈퍼 블록을 참조하여 파악해 둔 블록 그룹별 inode 개수를 이용하면 쉽게 위치를 파악할 수 있고, 해당 시나리오에서는 블록 그룹 0에 위치

  • 블록 그룹 0의 그룹 기술자 테이블을 참조하면 inode 테이블의 위치응 알려주는 엔트리가 있고 그 엔트리를 참조하면 inode 테이블의 위치를 파악할 수 있음

 

위 과정은 다음 [그림 2]와 같다.

 

[그림 2] 생성 과정 2

 

 

  • 블록 5에서 inode 테이블을 읽고, 두 번째 엔트리(inode 2)를 분석하면 루트 디렉토리의 디렉토리 엔트리가 어떤 블록에 위치하는지 알 수 있음

위 과정은 다음 [그림 3]과 같다.

 

[그림 3] 생성 과정 3

 

 

  • 블록 260의 디렉토리 엔트리를 읽고, 디렉토리 엔트리의 내용을 해석

  • 디렉토리 엔트리의 첫 번째와 두 번째 엔트리는 . 과 .. 을 위한 엔트리이고, 각 엔트리 레코드를 참고하여 다음 엔트리 위치를 파악

  • 엔트리 위치 파악이 모두 되었다면 dir 디렉토리를 검색

 

해당 시나리오에서는 inode 5444를 할당 받았다고 가정하며, 이 때 dir 디렉토리의 접근 시간은 업데이트 된다.

 

위 과정은 다음 [그림 4]와 같다.

 

[그림 4] 생성 과정 4

 

 

  • 이번에는 dir 디렉토리의 위치를 알아야 함

  • dir 디렉토리의 inode를 그룹별 inode 수로 나누면 어떤 블록 그룹에 위치하는지 알 수 있음

 

dir 디렉토리 inode(5444) / 슈퍼 블록에서 알아낸 블록 그룹별 inode 수(2016) = 2

 

 

dir 디렉토리는 계산 결과 블록 그룹 2에 위치하며, 또 블록 그룹 2의 그룹 기술자 테이블을 참조하여 inode 테이블이 어디에 위치하는지 알 수 있다.

 

이 시나리오에서는 블록 그룹 2의 inode 테이블이 17889 블록에서 시작한다고 가정한다.

 

 

  • inode 테이블을 읽고 inode 5444의 엔트리를 참조

  • 엔트리를 분석하면 dir 디렉토리의 디렉토리 엔트리가 어떤 블록에 위치하고 있는지 파악할 수 있음

  • 엔트리는 블록 그룹 0에서부터 계산해보면 알 수 있음

 

해당 시나리오에서는 dir 디렉토리의 디렉토리 엔트리가 블록 18556에 있다고 가정한다.

 

위 과정은 다음 [그림 5]와 같다.

 

[그림 5] 생성 과정 5

 

 

  • dir 디렉토리의 디렉토리 엔트리를 읽고 디렉토리 엔트리의 목록을 파악

  • 그 후 디렉토리에서 사용되고 있지 않은 공간을 찾음

  • 생성 할 파일이 필요 공간을 계산하면(고정 8byte + 파일 이름 길이(7byte), 4의 배수로 반올림) 총 16바이트가 필요

  • 만약 해당 디렉토리에 다른 파일이 있다면 파일 이름을 비교하여 그 파일들의 이름과 해당 파일의 이름 순서를 고려해 할당

 

이 때 디렉토리에는 수정 시간과 변경 시간이 업데이트된다.

 

그리고 .. 가 dir 디렉토리의 마지막이라고 가정한다.

 

 

  • 아직 파일이 완전히 생성된 것은 아님

  • 파일에 할당할 inode가 있어야 하는데 하드 디스크 헤더에 부담을 덜어주기 위해 Ext 파일 시스템은 부모와 동일한 그룹 블록에 inode를 할당

  • inode의 할당 상태를 관리하는 inode 비트맵을 찾기 위해 그룹 기술자 테이블을 참조

  • inode 비트맵을 찾아 참조하고 비할당 inode를 검색

  • 그 후 검색이 완료된 inode를 할당하기 위해 해당 inode 비트맵 값을 0에서 1로 변경

 

해당 시나리오에서는 inode 비트맵은 17880 블록에 존재하며, 비할당 inode는 inode 5576이 있다고 가정한다.

 

 

  • inode 테이블에 inode 5576을 초기화하고 타임스탬프 값을 현재 시간으로 업데이트

  • 또 링크 수는 디렉토리 엔트리 링크에 해당하는 1로 설정 (링크는 선으로 표시)

 

위 과정은 다음 [그림 6]과 같다.

 

[그림 6] 생성 과정 6

 

 

  • 이제 파일 내용을 저장하기 위한 블록을 할당해야 함

  • 블록의 할당 상태는 블록 비트맵에서 관리하는데 inode 비트맵을 찾았던 것처럼 그룹 기술자 테이블을 참조하여 블록 비트맵의 위치를 파악하고 비할당된 블록을 찾음

  • 검색이 완료되면 찾은 블록을 할당하기 위해 비트맵 값을 0에서 1로 변경

 

이 때 슈퍼 블록과 그룹 기술자 테이블에 있는 블록 개수 현황들이 업데이트 되며, 해당 시나리오에서는 블록 비트맵은 블록 17881에 위치하고, 할당 할 블록들은 총 5개이며, 20004 ~ 20007, 20010 블록이라고 가정한다.

 

할당이 되면 블록 포인터를 설정해야 하는데 블록 게수가 12개를 넘지 않으므로 직접 포인터로 설정되어 inode에 블록의 주소들이 저장된다.

 

위 과정은 [그림 7]과 같다.

 

[그림 7] 생성 과정 7

  • 파일 내용이 할당된 블록에 저장됨


13-2 파일 삭제

 

파일 삭제는 위 과정과 거의 동일하며 후반부 과정이 조금 다를 뿐이다.

 

위 생성 과정에서 다시 File.txt를 삭제한다고 하였을 때 다음과 같은 과정을 거친다.

 

  • dir 디렉토리의 디렉토리 엔트리를 찾고 그 내용을 분석하여 목록을 파악하는 과정까지는 동일

  • 그 후 File.txt를 삭제하게 되면 File.txt 파일 이전에 존재하는 .. 디렉토리 엔트리의 레코드 값이 증가되어 만약 File.txt를 삭제하게 되면 File.txt가 삭제되어 .. 가 마지막 디렉토리 엔트리라면 블록 끝을 가리키게 됨

 

해당 시나리오에서는 블록의 끝을 1500이라고 가정하고, 이때 dir 디렉토리의 수정 시간과 변경 시간이 업데이트 된다.

 

위 과정은 [그림 8]과 같다.

 

[그림 8] 삭제 과정 1

 

  • inode 테이블의 inode 5576은 파일이 삭제되었다는 것을 표시하기 위해 링크 값을 1에서 0으로 변경

위 과정은 다름 [그림 9]와 같다.

 

[그림 9] 삭제 과정 2

 

  • inode 5576의 할당 상태를 비할당 상태로 변경하기 위해 inode 비트맵의 inode 5576 비트맵을 1에서 0으로 변경

  • 이때 슈퍼 블록과 그룹 기술자 테이블에 있는 비할당 inode 개수 현황이 업데이트 됨

 

  • 또 할당된 파일 내용의 블록을 할당 해제하기 위해 해당 블록의 블록 비트맵 값을 1에서 0으로 변경

  • 블록 포인터 또한 inode에서 제거

  • 이때 해당 inode의 수정 시간, 변경 시간, 삭제 시간이 업데이트 됨

 

위 과정은 다음 [그림 10]과 같다.

 

[그림 10] 삭제 과정 3

 

위처럼 삭제된 후 inode나 블록이 재할당만 되지 않으면 다시 파일을 복구할 수 있다.


(14) 파일 복구

 

Ext 파일 시스템은 Ext4 파일 시스템까지 버전이 출시되어 있는데, Ext2와 Ext3의 파일 삭제 방식이 조금 달라 파일 복구 방법도 조금 다르다.

 

Ext2에서는 파일 복구가 대체로 수월한 편이며, 이유는 파일이 삭제될 때 inode에 블록 포인터 값이 지워지지 않고 계속 남아 있기 때문이다.

 

또 삭제 시간이 업데이트 되어 파일이 언제 삭제되었는지 안다면 그에 맞는 inode를 찾는 일은 좀 더 쉬워짐하지만 블록 포인터 값이 inode에 남아 있다고 하여 100% 해당 파일의 내용을 복구하는 것은 아니다.

 

inode가 가리키고 있는 블록이 재할당되면 그 내용은 전혀 다른 내용이 되기 때문이며, 또 디렉토리 엔트리와 inode의 연결은 영구적으로 삭제가 되서 삭제된 inode를 찾으려면 비할당 inode 엔트리를 검색해야 한다.

 

Ext3에서는 디렉토리 엔트리와 inode 연결이 삭제 되지 않지만, 블록 포인터가 삭제되기 때문에 카빙 기술을 이용하여 파일 복구를 시도해야 한다.

 

카빙을 시도할 때의 정보 수집 범위는 보통 같은 블록 내에 할당하기 때문에 블록 그룹 단위이지만 어떤 OS는 파일 시스템 전체를 할당 대상으로 하기 때문에 OS에 따라 그 정보 수집 범위를 달리해야 한다.

 

만약 파일이 최근에 삭제된 것을 알고 싶다면 저널을 분석하는 것이 좋으며, 이유는 inode의 복사본이 저널 블록에 포함되어 있을지도 모르기 때문이다.


(15) 데이터 구조

15-1. 슈퍼 블록

  • 슈퍼 블록의 파일 시스템에서 1024byte 오프셋에 위치하고, 그 크기 또한 1024byte

 

다음 표는 슈퍼 블록 오프셋 구조에 대한 내용이다.

 

[표 1] 슈퍼 블록 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

0~3

파일 시스템에 있는 inode 개수

76~79

주 버전

4~7

파일 시스템에 있는 블록 개수

80~81

예약 블록 사용 가능 UID

8~11

예약 블록 개수

82~83

예약 블록 사용 가능 GID

12~15

비할당 블록 개수

84~87

예약되지 않은 첫 번째 inode

16~19

비할당 inode 개수

88~89

inode 크기

20~23

블록 그룹 0 시작 블록

90~91

슈퍼 블록의 블록 그룹

24~27

블록 크기

92~95

호환성 가능 플래그

28~31

단편 크기

96~99

비호환성 기능 플래그

32~35

각 블록 그룹의 블록 개수

100~103

읽기 전용 속성 플래그

36~39

각 블록 그룹의 단편 개수

104~119

파일 시스템 ID

40~43

각 블록 그룹의 inode 개수

120~135

볼륨 이름

44~47

마지막 파일 시스템 마운트 시간

136~199

마지막 마운트 지점 경로

48~51

마지막 파일 시스템 수정 시간

200~203

비트맵 사용 알고리즘

52~53

파일 시스템 마운트 횟수

204~204

미리 할당된 블록 개수 (파일)

54~55

마운트 가능한 파일 시스템 최대 개수

205~205

미리 할당된 블록 개수 (디렉토리)

56~57

시그니처(0xEF53)

206~207

사용 X

58~59

파일 시스템 상태

208~223

저널 ID

60~61

오류 처리

224~227

저널 inode

62~63

부 버전

228~231

저널 장치

64~67

일관성 검사 간격

232~235

고아 inode 목록의 헤드

72~75

파일 시스템 생성 운영체제

236~1023

사용 X

 

블록 크기

  • 이 값은 직접적인 값이 아닌 간접적인 값

  • 1024를 해당 오프셋의 값만큼 왼쪽으로 쉬프트 연산하여 블록 크기를 구해야 함

 

단편 크기

  • 이 값 또한 블록 크기와 동일한 방법으로 구함

 

파일 시스템 상태

  • 0x0001 : 정상

  • 0x0002 : 오류

  • 0x0004 : 고아 inode 복수

 

오류 처리

  • 1 : 정상

  • 2 : 파일 시스템을 읽기 전용으로 다시 마운트해야 함

  • 3 : 패닉

 

파일 시스템 생성 운영체제

  • 0 : 리눅스

  • 1 : GNU hard

  • 2 : Masix

  • 3 : FreeBSD

  • 4 : Lites

 

주 버전

  • 파일 시스템의 버전을 나타내는 값

  • 일반 버전(0), 동적 버전(1) 두 가지 버전이 존재

  • 값이 1로 설정되어 있지 않으면 84byte 오프셋 앞에 있는 값들은 정확하지 않을 수 있음

 

호환성 기능 플래그

  • 0x0001 : 디렉토리 블록을 미리 할당 (단편화 예방)

  • 0x0002 : AFS 서버 inode 지원

  • 0x0004 : 파일 시스템 저널 지원 (Ext3)

  • 0x0008 : inode가 확장된 속성을 가짐

  • 0x0010 : 파티션 크기 다시 설정

  • 0x0020 : 디렉토리가 해시 인덱스를 사용

 

비호환성 기능 플래그

  • 0x0001 : 압축

  • 0x0002 : 디렉토리 엔트리가 파일 타입 필드를 포함

  • 0x0004 : 파일 시스템 복구 필요

  • 0x0008 : 저널 장치 사용

 

읽기 전용 속성 플래그

  • 0x0001 : Sparse 슈퍼 블록과 그룹 기술자 테이블

  • 0x0002 : 대용량 파일을 포함

  • 0x0004 : B-Tree 알고리즘 사용


15-2. 그룹 기술자 테이블

  • 파일 시스템 블록에 위치하는 그룹 기술자 그룹의 목록을 뜻함

  • 슈퍼 블록 다음 블록에 위치

  • 그룹 기술자 테이블의 엔트리는 각 블록 그룹의 정보를 가지고 있으며, 테이블의 크기는 32byte

 

테이블 파일 시스템 블록의 크기가 4096byte일때는 슈퍼 블록이 0에 위치하고, 그룹 기술자 테이블은 블록 1에 위치한다.

 

또 파일 시스템 블록의 크기가 1024byte 일때는 슈퍼 블록이 1에 위치하고, 그룹 기술자 테이블은 블록 2에 위치한다.

 

 

다음 표는 그룹 기술자 테이블 오프셋 구조에 대한 내용이다.

 

[표 2] 그룹 기술자 테이블 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

0~3

블록 비트맵 시작 블록 주소

14~15

그룹에 할당되지 않은 inode 개수

4~7

inode 비트맵 시작 블록 주소

16~17

그룹의 디렉토리 개수

8~11

inode 테이블 시작 블록 주소

18~31

사용 X

12~13

그룹에 할당되지 않은 블록 개수

   

 

블록 비트맵의 시작 블록 주소

  • 해당 오프셋의 값은 오프셋이 아니라 단순히 블록 번호에 불과

 

inode 비트맵의 시작 블록 주소

  • 블록 비트맵의 시작 블록 주소 오프셋과 의미가 동일


15-3. 블록 비트맵

  • 파일과 디렉토리의 내용이 저장되는 블록의 할당 상태를 관리하는 부분

  • 각 비트와 블록은 맵핑 관계

  • 시작 위치는 그룹 기술자 테이블에 정의되어 있음

 

[그림 11] 블록 비트맵 내용

 

각 바이트를 비트로 변환하면 할당 상태를 알 수 있다.


15-4. inode

  • inode 데이터 구조체는 파일이나 디렉토리의 메타 데이터를 저장

  • inode들은 각 블록 그룹에 위치하는 inode 테이블에 위치

  • inode 테이블 위치는 그룹 기술자 테이블에 정의되어 있고, 그룹별 inode 개수는 슈퍼 블록에 정의되어 있음

 

다음 표는 inode 오프셋 구조에 대한 내용이다.

 

[표 3] inode 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

0~1

파일 크기

88~91

단일 간접 블록 포인터

2~3

사용자 ID 하위 16bit

92~95

이중 간접 블록 포인터

4~7

파일 크기(byte)

96~99

삼중 간접 블록 포인터

8~11

접근 시간

100~103

생성 번호(NFS)

12~15

변경 시간

104~107

확장 속성 블록(파일 ACL)

16~19

수정 시간

108~111

크기 상위 32bit

20~23

삭제 시간

112~115

단편 블록 주소

24~25

그룹 ID 하위 16bit

116~116

블록 단편 인덱스

26~27

링크 개수

117~117

단편 크기

28~31

섹터 개수

118~119

사용 X

32~35

플래그

120~121

사용자 ID 상위 16bit

36~39

사용 X

122~123

그룹 ID 상위 16bit

40~87

직접 블록 포인터 (12개)

124~127

사용 X

 

기본적인 inode의 크기는 128byte이며, 만약 파일 시스템 버전이 동적 버전으로 설정되면 inode의 크기 또한 동적으로 변한다.

 

 

파일 모드

  • 타입과 허가권을 나타냄

  • 오프셋이 2byte 크기인데 bit로 변환하여 3개의 구역으로 나누어 플래그 값들이 설정

 

해당 오프셋의 값을 bit로 변환하여 구역을 나눈 모습을 다음 [그림 12]에서 볼 수 있다.

 

[그림 12] 파일 모드의 bit 구역

 

각 구역에는 다음 목록과 같은 플래그 값이 2진수로 변환되어 들어갈 수 있다.

 

[표 4] 접근 권한 플래그 목록

설명

설명

0x001

기타 사용자 - 실행 권한

0x020

그룹 - 읽기 권한

0x002

기타 사용자 - 쓰기 권한

0x040

사용자 - 실행 권한

0x004

기타 사용자 - 읽기 권한

0x080

사용자 - 쓰기 권한

0x008

그룹 - 실행 권한

0x100

사용자 - 읽기 권한

0x010

그룹 - 쓰기 권한

   

 

계산은 간단하다.

 

[그림 12]에 나와 있는 값을 예로 들어보자.

 

값을 각 자리 별로 분리하여 hex로 변환 후 플래그 목록 값에서 해당하는 값을 찾으면 된다.

 

만약 리눅스의 권한을 숙지하였다면, 해당 2진수 값을 8진수로 변환하여 권한을 바로 파악하는 것도 좋다. (110100100 > 644)

 

  • 110100100 > 100000000, 10000000, 100000, 100

  • 100000000 > 0x100 > 사용자 - 읽기 권한

  • 10000000 > 0x80 > 사용자 - 쓰기 권한

  • 100000 > 0x20 > 그룹 - 읽기 권한

  • 100 > 기타 사용자 - 읽기 권한

 

[표 5] 실행 속성 플래그 목록

설명

0x200

Sticky bit

0x400

Set GID

0x800

Set UID

 

[표 6] inode 파일 타입 플래그 목록

설명

설명

0x1000

FIFO

0x8000

일반 파일

0x2000

문자 장치

0xA000

심볼릭 링크

0x4000

디렉토리

0xC000

유닉스 소켓

0x6000

블록 장치

   

 

타임스탬프(접근, 변경, 수정, 삭제 시간)

  • 해당 오프셋 값들은 UTC 1970년 1월 1일을 기준으로 현재 시간까지의 초 값

  • 이 값들은 2038년 1월부터는 계산이 불가능

 

플래그

  • inode가 할당된 파일에 설정되어 있는 속성들을 표시한  오프셋 필드

 

다음 표는 inode 플래그 목록에 대한 내용이다.

 

[표 7] inode 플래그 목록

설명

0x00000008

동시 업데이트(업데이트 데이터를 디스크에 바로 씀)

0x00000010

고정 파일(내용 수정 불가)

0x00000020

덮어쓰기 불가, 이어쓰기 가능

0x00000040

Dump 불가능 파일

0x00001000

해시 트리 사용 디렉토리

0x00002000

저널링(Ext3)


15-5. 확장 속성

  • Ext 파일 시스템에서 파일이나 디렉토리에 존재

  • 우리가 흔히 알고 있는 권한도 확장 속성에 해당

  • 확장 속성 또한 다른 영역들과 마찬가지로 구조체 형식으로 정의되어 있음

 

확장 속성은 기본적으로 다음의 3가지 영역으로 나누어져 있다.

  • 헤더 영역

  • 이름 엔트리 영역

  • 데이터 영역

헤더 영역 다음에 이름 엔트리 영역이 오는데 일반적으로 영역들은 붙어 있지만, 데이터 영역은 나머지 두 영역과 다르게 블록 마지막에 존재하여 두 영역과 붙어 있지 않다.

 

더군다나 데이터 영역은 블록 마지막에서 블록 처음을 향하여 데이터가 점차 쌓인다.

 

데이터 영역에 있는 데이터들은 속성에 이름 엔트리와 대응되는 데이터들이지만, 이름 엔트리 순서와 데이터 순서가 동일하게 매칭되는 것은 아니다.

 

 

헤더 영역

  • 확장 속성의 헤더 영역은 32byte 크기

  • 시그니처를 가지고 있고 블록의 0byte 오프셋부터 시작

 

다음 표는 헤더 영역 오프셋 구조에 대한 내용이다.

 

[표 8] 헤더 영역 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

0~3

시그니처(0xEA020000)

12~15

해시 값

4~7

참고 횟수

16~31

예약 영역

8~11

블록 개수

   

 

  • 참고 횟수 : 확장 속서의 블록은 여러 파일이나 디렉토리에 공유되어 참고 카운트는 해당 블록을 공유 받아 사용 중인 블록이 몇 개인지 판별해 주는 필드

  • 블록 개수 : 확장 속성을 가진 블록이 몇 개의 확장 속성을 가졌는지 판별해 주는 필드 (현재까지는 사용되지 않음)

  • 해시 값 : 중복 속성을 구별할 때 사용되는 해시 값

 

 

이름 엔트리 영역

  • 헤더 영역 바로 다음에 위치

  • 이름 엔트리와 매칭되는 데이터의 정보와 이름 정보가 포함되어 있음

 

다음 표는 이름 엔트리 오프셋 구조에 대한 내용이다.

 

[표 9] 이름 엔트리 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

0~0

이름 길이

8~11

데이터 크기

1~1

속성 타입

12~15

데이터 해시

2~3

데이터의 위치 오프셋

16~

이름(ASCII)

4~7

데이터가 포함되어 있는 블록 위치

   

 

 

속성 타입

  • 1 : 사용자 공간 속성

  • 2 : POSIX ACL

  • 3 : POSIX ACL 기본

  • 4 : 신뢰성이 있는 공간 속성

  • 5 : LUSTRE

  • 6 : 보안 공간 속성 

 

값 중 3이라는 값을 가지는 속성은 디렉토리에만 해당하며, 5라는 값을 가지는 속성은 현재 리눅스에서는 사용되지 않고 있다.

 

POSIX ACL 속성은 헤더와 엔트리로 구성되어 있다.

 

 

[표 10] POSIX ACL 헤더 오프셋 구조

범위(Byte)

설명

0~3

버전

 

[표 11] POSIX ACL 엔트리 오프셋 구조

범위(Byte)

설명

0~1

타입

2~3

접근 권한

4~7

사용자 / 그룹 ID

 

POSIX ACL 엔트리의 첫 번째 오프셋인 타입 필드는 POSIX ACL 속성이 설정된 엔트리의 허가된 종류를 의미한다.

 

POSIX ACL 허가 타입 목록은 다음과 같다.

  • 0x01 : 사용자 - inode에서 지정

  • 0x02 : 사용자 - 속성에서 지정

  • 0x04 : 그룹 - inode에서 지정

  • 0x08 : 그룹 - 속성에서 지정

  • 0x10 : 효과적인 권한 마스크

  • 0x20 : 기타

 

0x01, 0x04, 0x20의 경우 inode에서 복사된 정보들이다.

 

그렇기에 따로 접근 권한을 설정해 줄 필요가 없다.

 

나머지 값들의 접근 권한 플래그는 엔트리 목록에 있는 필드 중 접근 권한 필드에서 설정해 주어야 한다.

 

접근 권한 필드의 플래그 목록은 다음과 같다.

  • 0x01 : 실행

  • 0x02 : 쓰기

  • 0x03 : 읽기

 

데이터의 위치 오프셋

  • 해당 이름 엔트리와 대응 되는 데이터의 오프셋 위치 

 

데이터가 포함되어 있는 블록 위치

  • 해당 이름 엔트리와 대응 되는 데이터의 블록 위치

  • 현재 리눅스에서는 하나의 블록만 사용하기 때문에 해당 필드에 설정 되어 있지 않을 수도 있음

 

데이터 크기

  • 해당 엔트리와 대응 되는 데이터의 크기


15-6.디렉토리 엔트리

  • 파일이나 디렉토리의 이름을 저장하고, 파일이나 디렉토리에 할당된 inode의 주소를 저장

  • 자신과 맵핑 관계인 디렉토리에 할당 된 블록에 위치

  • 디렉토리 엔트리 데이터 구조에는 두 가지 유형이 존재

  • 하지만 이 두 유형의 크기는 동일하며 차이점은 파일 타입의 유무

  • 디렉토리 엔트리에 어떤 유형이 사용되는지는 슈퍼 블록에서 정의

  • 현재는 파일 타입 필드가 포함된 디렉토리 엔트리 유형을 사용

 

먼저 파일 타입이 없는 데이터 구조를 확인해보자.

 

[표 12] 예전에 사용되었던 디렉토리 엔트리 오프셋 구조

범위(Byte)

설명

0~3

inode 번호

4~5

해당 엔트리 길이

6~7

이름 길이

8~

이름 (ASCII)

 

[표 13] 현재 사용 중인 디렉토리 엔트리 오프셋 구조

범위(Byte)

설명

0~3

inode 번호

4~5

해당 엔트리 길이

6~6

이름 길이

7~7

파일 타입

8~

이름 (ASCII)

 

inode 번호

  • 우리가 흔히 보는 inode 번호를 나타냄

 

해당 엔트리 길이

  • 해당 구조체를 포함하고 있는 엔트리 길이

 

이름 길이

  • 해당 디렉토리 엔트리가 할당된 파일(디렉토리)의 이름 길이

 

이름

  • 이름 길이에 따라 이름 필드의 크기는 달라짐

 

파일 타입

  • 해당 디렉토리 엔트리가 할당된 것이 파일인지 디렉토리인지를 구분하여 주는 필드

 

파일 타입은 다음과 같은 목록 갑들에 따라 구분

  • 0 : 정의되지 않은 타입

  • 1 : 정규 파일

  • 2 : 디렉토리

  • 3 : 문자 장치

  • 4 : 블록 장치

  • 5 : FIFO

  • 6 : 유닉스 소켓

  • 7 : 심볼릭 링크

 

두 번째 디렉토리 엔트리들을 찾으려면 해당 엔트리의 크기를 해당 디렉토리 시작 오프셋에서 더하면 두 번째 디렉토리 엔트리를 찾을 수 있다.

 

이러한 식으로 계속 다음 디렉토리 엔트리를 찾으면 되는데 만약 디렉토리 엔트리 크기가 이름 길이에 비해 볼 필요할 정도로 크다면 그 디렉토리 엔트리와 다음 디렉토리 엔트리 사이에 파일이 삭제되었음을 의미한다.


15-7. 해시 트리

  • Ext 파일 시스템에서 디렉토리의 엔트리들을 정렬하기 위해 사용하는 알고리즘

  • 각 노드는 디렉토리의 각 블록

  • 노드에는 노드 기술자라는 데이터 구조체가 있는데 노드 기술자는 다음 계층의 블록을 알려주는 역할을 함

  • 노드 기술자는 헤더와 엔트리로 나누어 지는데, 헤더는 디렉토리 엔트리 다음에 위치

 

다음 표는 노드 기술자 헤더 오프셋 구조에 대한 내용이다.

 

[표 14] 노드 기술자 헤더 오프셋 구조

범위(Byte)

설명

0~3

사용 X

4~4

해당 버전

5~5

해당 구조체 길이

6~6

리프(leaf) 레벨

7~7

사용 X

 

노드 기술자 엔트리는 노드의 해시 값 중 가장 작은 해시 값과 노드의 디렉토리 블록을 저장하고 있다.

 

[표 15] 노드 기술자 엔트리 오프셋 구조

범위(Byte)

설명

0~3

노드의 가장 작은 해시 값

4~7

블록 주소

 

첫 번째 노드 기술자 엔트리의 경우 최소 해시 값이 0이어야만 해서 해시 값이 설정되지 않는다.

 

이러한 이유로 첫 번째 노드 기술자 엔트리의 구조는 [표 15]와 조금 다른데 그 형태는 [표 16]과 같다.

 

[표 16] 첫 번째 노드 기술자 엔트리 오프셋 구조

범위(Byte)

설명

0~1

노드 기술자 최대 번호

2~3

노드 기술자 번호

4~7

첫 번째 노드의 블록 위치

 

저널

  • 저널링은 파일 시스템이 손상되었을 때 복구를 하기 위하여 평상시에 메타데이터 업데이트 사항을 기록해 두는 기술

  • Ext3 파일 시스템에는 저널을 위한 4개의 블록이 존재

  • 저널 슈퍼 블록, 기술자 블록, 적용 블록, 취소 블록이 4가지 블록에 해당

  • 이 4개의 블록의 데이터 구조체는 모두 동일한 헤더를 가짐

 

다음 표는 저널 블록들의 표준 헤더 오프셋 구조에 대한 내용이다.

 

[표 17] 저널 블록들의 표준 헤더 오프셋 구조

범위(Byte)

설명

0~3

시그니처(0xC03b3998)

4~7

블록 타입

8~11

순서 번호

 

블록 타입 (4개의 블록들을 구분하는데 사용)

  • 1 : 기술자 블록

  • 2 : 적용 블록

  • 3 : 슈퍼 블록 버전 1

  • 4 : 슈퍼 블록 버전 2

  • 5 : 취소 블록

 

블록 타입이 기술자 블록 값을 가지면 해당 저널 블록은 다음 표와 같은 구조를 가진다.

 

[표 18] 기술자 블록 오프셋

범위(Byte)

설명

범위(Byte)

설명

0~11

표준 헤더

16~19

엔트리 플래그

12~15

파일 시스템 블록

20~35

UUID

 

엔트리 플래그 (어떤 상태인지를 나타내주는 플래그)

  • 0x01 : 저널 블록 취소

  • 0x02 : 엔트리는 이전 UUID를 보유

  • 0x04 : 이번 트랜젝션으로 블록이 삭제

  • 0x08 : 기술자 블록의 마지막 엔트리

 

기술자 블록의 20~35 오프셋 필드인 UUID는 SAME_UUID 플래그가 설정되지 않으면 존재하지 않는 필드이다.

 

엔트리 플래그의 UUID 또한 마찬가지이며, 엔트리 플래그의 트랜젝션 블록 삭제 플래그는 현재 사용되지 않고 있다.

 

슈퍼 블록 버전 1과 2는 구조가 조금 다르기 때문에 값 또한 다른 것이다.

 

버전 1과 2는 다음과 같은 공통 구조체를 가진다.

 

[표 19] 슈퍼 블록 버전 1과 2의 공통 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

0~11

표준 헤더

24~27

첫 번째 트랜젝션 순서 번호

12~15

저널 블록 크기

28~31

첫 번째 트랜젝션 저널 블록

16~19

저널 블록 개수

32~35

오류 번호

20~23

저널의 실제 시작위치 블록

   

 

버전 1이라면 [표 19]의 36byte만 사용하지만, 버전 2일 경우 추가적인 오프셋 구조를 가진다.

 

추가적인 오프셋 구조는 [표 20]과 같다.

 

[표 20] 버전 2일 경우의 사용하는 추가적인 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

36~39

호환 기능

68~71

슈퍼 블록 복사본 위치

40~43

비호환 기능

72~75

트랜젝션별 저널 블록 최대 개수

44~47

읽기 전용 호환 기능

76~79

트랜젝션별 파일 시스템 블록 최대 개수

48~63

저널 GUID

80~255

사용 X

64~67

저널을 사용하는 파일 시스템 개수

256~1023

저널을 사용하는 파일 시스템 ID(16byte)

 

취소 블록은 포쥰 헤더를 기본적으로 가지고 있고, 독자적인 정보로는 취소된 파일 시스템 블록들의 목록을 가지고 있다.

 

취소 블록의 구조는 다음과 같다.

 

[표 21] 취소 블록의 오프셋 구조

범위(Byte)

설명

0~11

표준 헤더

12~15

취소 데이터의 크기(Byte)

16~

파일 시스템 블록 주소(4Byte) 목록


# Reference

 

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

[Digital Forensic] EXT 파일 시스템 (1)

 

EXT 파일 시스템


(1) EXT 파일 시스템?

  • Minix라는 리눅스 초기 파일 시스템의 문제점 해결을 위해 고안된 파일 시스템

  • UFS(Unix File System)을 기초로 만들어져, 현재 Ext 4까지 업데이트 됨

  • UFS에서 쓸모 없는 기능들을 제외하여 구조를 이해하는데 어려움은 크게 줄음

  • 파일과 관련된 모든 데이터들을 한 곳에 모아 두어 하드 디스크 헤드가 데이터를 읽을 때 불필요한 동작을 하지 않도록 설계

 

1-1. Ext 레이아웃

 

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

 

[그림 1] Ext 파일 시스템 레이아웃

 

위 [그림 1]을 보듯이 구조는 간단하다.

 

블록 그룹들의 개수는 시스템 환경에 따라 달라지지만, 마지막 블록 그룹을 제외한 나머지 블록 그룹들은 같은 블록 수를 가진다.

 

블록 그룹에는 Super Block, Inode Table 등이 존재한다.

 

 

1) Super Block (Block 1개의 크기)

  • Block의 크기 (1KB, 2KB, 4KB)

  • 블록 총 개수

  • 블록 그룹 개수

  • Inode 개수

  • 블록 그룹 내의 블록 / Inode 개수

 

Super Block은 블록 크기가 2KB, 4KB이어도 고정적으로 1KB만 사용한다.

 

즉, 4KB의 블록을 할당 받아도 3KB는 쓰지 않는다.

 

 

2) Inode Table

  • inode라는 데이터 구조체를 포함하고 있는 테이블

  • 각 블록 그룹에 1개씩만 존재

 

3) inode

  • 파일과 디렉토리의 메타데이터를 포함하는 데이터 구조체

  • 고정된 크기를 가짐

 

[그림 2] 블록 내의 관계

 

디렉토리 엔트리는 파일 이름과 파일 inode 포인터를 포함하는 데이터 구조체이다.


(2) 기능

 

 

Ext에는 여러 가지 기능이 존재한다.

 

이 중 주의깊게 보아야 할 기술은 호환성 기능이다.

 

2-1. 호환 기능

  • 마운트 하려는 파일 시스템에 저널링, 확장 속성 등 운영체제에서 지원하지 않는 기능이 있더라도 해당 파일 시스템을 마운트하는 기능

 

2-2. 비호환 기능

  • 마운트 하려는 파일 시스템에 압축, 암호 등 기능이 포함되어 있으면 해당 파일 시스템을 마운트하지 않는 기능

 

2-3. 읽기 전용 호환 기능

  • 비호환 기능처럼 운영체제가 지원하지 않는 기능을 가진 파일 시스템을 강제적으로 마운트 한다면 읽기 전용으로 마운트하는 기능


(3) 슈퍼 블록

  • 파일 시스템의 시작(부트 섹터 제외)으로 부터 1024Byte에 위치

  • 크기는 1024Byte이지만 실제로는 이보다 조금 더 작음

  • 설정 값만 포함하고 있고 부트 코드는 포함하고 있지 않음

  • 복사본은 보통 블록 그룹의 첫 블록(슈퍼 블록)에 저장 

 

슈퍼 블록에 저장되는 정보는 다음과 같다.

 

  • 각 블록의 크기

  • 전체 블록의 수

  • 블록 그룹별 블록 개수

  • 예약 블록 수

  • inode 전체 개수

  • 블록 그룹별 inode 개수

  • 볼륨 이름

  • 마지막 수정 시간

  • 마지막 마운트 시간

  • 마지막 마운트 경로

  • 무결성 식별 실행 여부 값

 

많은 정보들이 포함되어 있지만 마지막 수정 시간부터의 값들은 부가적 데이터이다.

 

또 슈퍼 블록은 비 사용중인 inode 블록들의 전체 개수에 대한 데이터를 기록하기도 하는데 이것의 이유는 inode와 블록들을 할당할 때 참고하기 위해서다.

 

슈퍼 블록에는 앞 글에서 설명한 세 가지의 호환성 기능 말고도 sparse 슈퍼 블록 기능이라고 있는데 이 기능에 대해서 다음과 같이 설명할 수 있다.

 

 

스파스 슈퍼 블록

  • 해당 기능은 기본적으로 Ext 파일 시스템이 리눅스에 생성될 때 활성화 되어 있는 기능

  • 슈퍼 블록과 그룹 기술자 테이블의 복사본을 일부 블록 그룹에 포함되도록 함

  • 이 기능으로 인해 파일 시스템의 시작 위치를 판별하는데 어려움이 생길 수 있음

  • 슈퍼 블록 볼륨 레이블이라는 것이 존재하는데, 이것은 파일 시스템을 구분하기 위해 사용


(4) 그룹 기술자 테이블 블록

  • 슈퍼 블록 다음으로 오는 블록

  • 해당 테이블의 복사본은 sparse 슈퍼 블록 기능이 활성화되어 있지 않으면 각 블록 그룹에 존재하게 됨

  • 해당 테이블에는 파일 내용 이외에 슈퍼 블록, 그룹 기술자 그룹, inode 테이블, inode 비트맵, 블록 비트맵의 설정 데이터에 대한 정보들이 포함되어 있음


(5) 부트 코드

  • 슈퍼 블록 이전에 위치

  • 크기는 1024Byte

  • 즉 MBR 영역과 첫 번째 블록 그룹의 슈퍼 블록 영역 사이에 존재하는 것


(6) 블록

  • Ext 파일 시스템의 블록은 NTFS와 FAT 파일 시스템의 클러스터와 아주 유사한 개념

  • 보통 1024, 2048, 4096 Byte의 크기를 가짐

  • 모든 블록에는 주소가 주어지며, 모든 블록들은 블록 그룹에 속해야만 함

  • 예약 영역(부트 섹터와 부트 코드가 있는 영역)의 블록들은 블록 그룹에 속하지 않음

어떤 그룹에 속한 블록인지를 결정하기 위해서는 다음과 같은 계산을 수행해야 한다.

 

 

그룹 = (해당 블록 - 첫 번째 데이터 블록) / 그룹별 블록 수

 

 

블록 할당

  • 각 블록 그룹에 존재하는 블록 비트맵에 의해서 결정

  • 위치는 그룹 기술자 테이블에 정의되어 있음

  • 블록 비트맵 내용은 비트로 구성되어 있는데 이 비트는 각 블록과 맵핑 관계

  • 어떠한 특정 비트가 어떠한 블록과 맵핑 관계에 있는지 확인하려면 블록 비트맵이 포함되어 있는 블록 그룹의 시작에서 확인하고자 하는 블록의 상대적 주소를 계산해야 함

상대적 주소를 계산하려면 블록 그룹의 첫 번째 블록을 확인해야 하는데 확인 방법은 다음 계산식을 수행하면 된다.

 

 

첫 번째 블록 = 블록 그룹 x 그룹별 블록 수 + 첫 번째 데이터 블록

 

 

Ext 파일 시스템은 관리 목적으로 파일 시스템에 할당된 많은 블록들이 있는데 이 블록들 때문에 NTFS처럼 파일에 모든 블록을 할당하지 않는다.

 

관리 목적으로 파일 시스템 할당된 블록들은 다음과 같은 것들이 있다.

 

  • 슈퍼 블록

  • 그룹 기술자 테이블

  • 블록과 inode의 비트맵 블록

  • inode 테이블


(7) inode

  • Ext 파일 시스템의 메타데이터들은 모두 inode에 저장

  • Ext 파일 시스템에서 inode는 모두 동일한 크기를 가지며, 슈퍼 블록에 정의

  • inode Table이라는 집합체에 저장되어 있음

  • 이 테이블은 각 블록 그룹에 존재하며 크기는 슈퍼 블록에 정의되어 있음

  • inode 테이블 위치는 그룹 기술자 테이블에서 정해줌

 

보통 inode의 1 ~ 10번은 예약되어 있고, 할당 된 상태이다.

 

슈퍼 블록은 이런 예약 inode들을 제외한 첫 번째 inode를 값으로 가지고 있다.

 

각 inode 필드 중에는 고정된 번호를 가지는 필드가 있고 추가 정보로는 확장 속성과 간접 블록 포인터가 있다.

 

또 inode의 할당 상태는 각 그룹에 존재하는 inode 비트맵이 결정한다.

 

 

소유권

  • 해당 정보는 사용자, 그룹 ID로 인해 저장

  • 유닉스에서는 모든 사용자에게 ID를 할당하고 사용자 ID를 사용자 이름으로 변화하는데 /etc/passwd 파일을 사용

  • inode에 사용자 ID는 chown 등의 명령어를 통해 충분히 변경 가능하기 때문에 해당 사용자가 해당 파일을 생성 했다고 전적으로 신뢰하여서는 안 됨

 

타임스탬프

  • inode는 일시적인 정보로 타임스탬프 값을 가짐

  • 한 가지 특이한 점은 기존의 타임스탬프라고 하면 변경, 수정, 접근 시간이 있는데 inode는 여기에 삭제 시간까지 포함

  • 타임스탬프 값은 1970년 1월 1일 UTC를 시작으로 현재 시간까지 경과된 초를 값으로 가짐

  • 하지만 타임스탬프 정보 또한 전적으로 신뢰하여서는 안 됨

  • 이유는 Touch 명령어로 수정이 가능하기 때문

 

모드 필드

  • 파일 타입, 기본 허가권 등의 값이 포함

  • 유닉스에서는 모든 것이 파일로 취급되는데 그 취급되는 유형에는 무수히 많은 유형들이 있음

  • 파일 타입은 이러한 유형들을 말하는 것

  • 기본 허가권은 퍼미션(Permission)에 해당하는 것으로, 이는 운영체제가 다루는 데이터가 아닌 사용자가 다루는 데이터이므로 부가 데이터에 속함

  • 모드 필드는 파일이나 디렉토리가 갖는 특별한 속성을 포함하고 있음

  • 'sticky bit'라는 것이며, 해당 속성이 파일이나 디렉토리에 설정되면 오직 소유주만이 파일이나 디렉토리의 내용을 지울 수 있음

그리고 SUID, GUID라고 하는 것도 있으며, 이 두 가지 속성은 권한이 없는 사용자가 특정 권한을 가지고 프로그램을 실행토록 하는 권한이다.

 

 

링크 카운트

  • 링크 카운트 값은 inode를 가리키는 파일 이름의 개수를 뜻함

 

블록 포인터

  • inode에는 파일에 할당할 12개의 블록 주소가 저장되어 있는데 이것들을 직접 포인터라고 부름

  • 하지만 요즘은 파일 용량이 커져 12개의 블록 가지고는 부족할 때가 있음

  • 이럴 때 하나의 블록을 나머지 블록들의 주소를 저장할 공간으로 할당하여 해당 블록에 나머지 블록들의 주소를 저장하며, 이를 간접 포인터라고 함

  • 만약 간접 포인터를 사용하고도 블록이 더 필요하면 직접 포인터와 간접 포인터를 혼합한 이중 간접 포인터를 사용해야 함

  • 또 더 많은 공간이 필요하다면 삼중 간접 포인터를 사용해야 함

 

[그림 3] inode 포인터

 

파일을 강제로 특정 크기를 갖게 끔 생성하거나 블록 내용이 모두 0일 때는 스파스 블록이라고 부른다.

 

스파스 블록에는 어떠한 데이터도 쓸 수 없으며, 스파스 블록이 블록 포인터에 포함될 경우 블록 주소가 0으로 표시된다.

 

 

타임 스탬프 업데이트

 

 

Ext에는 4개의 시간 값이 있으며, 각 시간 값이 언제 업데이트 되는지 알아보도록 하자.

 

대부분의 지워진 파일들은 수정 시간, 변경 시간, 삭제 시간이 동일하다.

 

 

1) 접근 시간

  • 파일이나 디렉토리 내용을 읽을 때 업데이트 됨

  • 복사, 새로운 볼륨으로 이동할 때에도 업데이트 됨

2) 수정 시간

  • 파일이나 디렉토리 내용이 변경될 때 업데이트

  • 복사할 때에도 결국 새로운 파일 내용을 생성하는 경우가 되어 현재 시간으로 업데이트 됨

  • 또 네트워크로 전송할 때에도 네트워크에서 전송받는 시스템의 현재 시간으로 업데이트 됨

3) 변경 시간

  • 파일이나 디렉토리의 메타데이터가 변경될 때 업데이트 됨

  • 예를 들어 파일이나 디렉토리 생성, 퍼미션 변경, 소유권 변경 등의 정보가 변경될 때 업데이트 됨

4) 삭제 시간

  • 파일이 삭제될 때 업데이트 됨

  • 이 시간 값은 inode가 새롭게 할당 되면 삭제


(8) 디렉토리 엔트리

  • Ext 파일 시스템에서는 파일과 디렉토리의 구분을 inode에 있는 특별한 타입 값으로 구분 지음

  • 디렉토리들은 디렉토리 엔트리 데이터 구조체의 목록을 포함하는 블록들을 할당받게 됨

  • 디렉토리 엔트리는 파일 이름과  메타데이터가 어디 있는지 설명하는 데이터 구조체

모든 디렉토리는 자신과 부모를 나타내는 . 과 .. 디렉토리 엔트리를 포함하고 또 이 두 개를 엔트리 시작으로 삼는다.

 

. 과 .. 다음으로는 디렉토리 내의 파일과 하위 디렉토리의 엔트리들이다.

 

모든 파일 이름은 동적이어서 디렉토리 엔트리의 길이 또한 동적이다.

 

이러한 이유로 디렉토리 엔트리에는 이름 길이를 식별하는 디렉토리 엔트리 레코드 값이 존재한다.

 

디렉토리 엔트리의 길이는 이름 이외에 고정된 8Byte가 있어 4의 배수로 반올림 된 레코드 값과 8Byte를 더하여 결정한다.

 

레코드 값은 이름의 길이만큼 값이 주어져 다음 디렉토리 엔트리의 위치를 판별하는데 사용될 수 있다.

 

[그림 4] 디렉토리 엔트리 기본

 

마지막 디렉토리 엔트리의 레코드 값은 블록의 마지막을 가리키며, 마지막 디렉토리 엔트리 이후의 공간은 비할당 공간으로 남겨 둔다.

 

[그림 4]의 경우 이름 길이대로 레코드 값이 설정되어 다음 디렉토리 엔트리 바로 앞을 가리키고 있다.

 

하지만 파일이 삭제되면 파일의 이름이 변경되는데 운영체제는 그러한 파일을 화면상으로 출력하지 못한다.

 

또 운영체제는 삭제 파일 이전의 디렉토리 엔트리의 레코드 값을 삭제 파일 다음 디렉토리 엔트리가 위치한 곳까지의 거리로 값을 증가시켜 삭제된 파일을 숨긴다.

 

하지만 말 그대로 숨겼을 뿐 데아터는 지워지지 않아 복구가 가능하다.

 

[그림 5] 파일을 삭제한 경우

 

[그림 5[의 경우 file2.txt를 삭제한 경우인데 이렇게 하면 사용자는 파일이 지워진 것으로 인식하게 될 것이다.

 

하지만 데이터는 그대로 블록에 남아 있다.

 

만약 이름의 길이와 레코드의 길이를 비교했을 때 레코드의 길이가 필요 이상으로 크다면 현재 디렉토리 엔트리와 다음 디렉토리 엔트리 사이에 파일이 존재했던 것으로 볼 수 있다.


(9) 링크

  • Ext 파일 시스템에서 제공하는 링크는 하드 링크와 소프트 링크가 있음

  • 하드 링크는 같은 파일 시스템에 있는 파일이나 디렉토리에 추가적인 이름을 정의하는 것

  • 소프트 링크는 다른 파일 시스템에 있는 파일이나 디렉토리에 추가적인 이름을 정의하는 것

  • 하드 링크는 링크가 생성되면 원본 이름인지 링크 이름인지 구분할 수 없는 특징이 있음 

[그림 6] 하드 링크

 

[그림 6]처럼 원본 inode를 하드 링크가 같이 가리키고 있기 때문에 같은 파일 시스템에 존재해야 하며 또 원본 파일 이름이 어떤 것인지 구분할 수 없는 것이다. (하드 링크가 모두 해제 되지 않는 이상 파일은 삭제되지 않음)

 

소프트 링크는 심볼릭 링크 파일 타입으로 인해 생성된다.

 

파일이 하나 생성되었기 때문에 소프트 링크 파일만의 inode가 존재하며 해당 inode의 블록 또한 할당된다.

 

소프트 링크 파일이 가리키고자 하는 파일의 전체 경로가 60 글자를 넘지 않으면 목적 파일이나 목적 디렉토리의 전체 경로는 소프트 링크 파일에 할당된 inode나 블록에 저장된다.

 

 

소프트 링크 파일의 블록은 블록 포인터로서 목적 파일을 가리키게 되는데 이와 같은 과정은 다음과 같다.

 

[그림 7] 소프트 링크


(10) 마운트

  • 디렉토리들은 파일과 볼륨을 마운트하는데 사용될 수 있음

  • 어떠한 파일 시스템이 디렉토리에 마운트되면 해당 디렉토리가 가지고 있던 파일들은 보이지 않게 됨

  • 이 방법은 파일을 숨기는데 사용될 수 있음

[그림 8] 마운트


(11) 해시 트리

  • NTFS의 b-tree와 비슷한 개념

  • 그 정렬 기준이 파일 이름이 아닌 해시 값

  • 파일 시스템이 생성될 때 사용자에 따라 사용 여부가 달라짐

  • 만약 사용자가 사용하낟고 설정하면 슈퍼 블록에서 호환 플래그 기능을 설정해 줌

  • 해시 트리를 사용하게 되면 블록은 트리 구조에서 노드가 되며 그 노드는 각 파일들을 포함하게 됨

Ext 파일 시스템에도 b-tree가 있지만 아직 표준은 아니다.


(12) 저널링

  • 파일 시스템의 손상을 대비하여 복구를 위해 파일 시스템의 변경 사항을 기록해 두는 기능

  • Ext에서 저널은 슈퍼 블록에서 그 위치를 지정하여 주기 때문에 파일 시스템 어느 곳이든 위치할 수 있지만 보통 inode 8을 사용

슈퍼 블록에는 저널을 위한 호환 설정 필드가 있는데 이 값을 어떻게 설정하는가에 따라 로컬 저널 기능의 활용 여부를 결정할 수 있다.

 

만약 로컬 저널 기능을 비활성화로 설정하면 외부 저널을 사용할 수 있다.

 

하지만, 이 저널의 데이터는 로컬에 저장되지 않으며, 저널에는 두 가지 동작 모드가 있다.

 

첫 번째로는 메타 데이터의 업데이트만을 기록하는 모드이고, 두 번째는 파일 시스템의 모든 업데이트를 기록하는 모드이다.

 

그리고 메타데이터 업데이트만을 기록하는 모드가 바로 default 이다.

 

 

Ext3의 저널링은 블록 수준에서 수행되는데 만약 어떠한 inode가 1비트 변경된다면 해당 inode를 포함하고 있는 블록 모두 저널에 업데이트된다.

 

저널의 첫 번째 블록은 슈퍼 블록은 위한 것이며, 전체적인 정보를 저장하는데 사용된다.

 

그 뒤로 이어지는 블록들은 저널 엔트리를 위해 사용되고 만약 저널 업데이트가 마지막 블록까지 진행되었다면 다시 처음 블록으로 돌아온다. (저널의 블록 크기는 파일 시스템 블록 크기와 동일)

 

 

업데이트는 하나의 묶음을 기준으로 처리되는데, 각 묶음은 순서 번호를 가지고 있다.

 

이 순서 번호는 같은 블록에 대해서는 동일하다.

 

각 묶음은 기술자 블록을 시작으로 하며, 기술자 블록은 묶음의 순서 번호와 어떤 파일 시스템 블록이 업데이트 되었는지 나타내는 목록을 포함한다.

 

만약 새로운 블록에서 업데이트가 발생하면 기존에 있던 묶음 뒤 블록에 기록된다.

 

또, 저널에 기록되었던 파일 시스템 블록은 취소가 가능하며, 취소를 할 경우 취소 블록이라는 곳에 그 목록이 순서 번호와 함께 저장이 된다.


# Reference

 

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

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

 

NTFS 파일 시스템


(17) 데이터 구조

17-1. Fixup

  • NTFS에서 신뢰성을 향상시키기 위해 사용하는 저장 기술

  • 데이터가 저장된 섹터의 손상 여부를 판단

 

해당 기술의 원리는 일반적인 섹터의 마지막 2바이트를 특정 시그니처로 교체해 두고, 원래의 2바이트 값은 Fixup 배열에 저장하여 교체해 둔 시그니처가 다른 값으로 교체되지 않았다면 섹터가 손상되지 않은 것으로 보고 배열에 있는 원래의 값을 다시 섹터 마지막 2바이트에 넣는다.

 

오직 이 기술은 데이터 구조체에만 사용되며 클러스터 등에는 사용되지 않는다.

 

17-2. MFT 엔트리

  • MFT(Master File Table)는 NTFS에서 핵심적인 부분

  • 파일과 디렉토리에 대한 엔트리를 가짐

  • MFT 엔트리의 크기는 일정하며, 그 크기는 부트 섹터에서 정의하고 일반적 크기는 1024byte

 

다음 표는 MFT 엔트리 오프셋에 대한 구조이다.

 

[표 1] MFT 엔트리 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

0~3

시그니처(FILE)

22~23

플래그

4~5

Fixup 배열 오프셋

24~27

MFT 엔트리 실제 크기

6~7

Fixup 배열 엔트리 개수

28~31

MFT 엔트리 할당 크기

8~15

$LogFile 순서 번호

32~39

기본 레코드 파일 참조

16~17

순서 번호

40~41

다음 속성 ID

18~19

링크 카운트

42~1023

속성과 Fixup 배열 값

20~21

첫 번째 속성 오프셋

   

 

시그니처

  • MFT 엔트리의 시그니처로 'FILE'이란 문자열로 정해져 있음

  • 하지만 chkdsk가 엔트리에 오류를 발견하면 시그니처는 'FILE'이 아닌 'BAAD'로 교체 됨

 

Fixup 배열 오프셋

  • 해당 오프셋은 MFT 엔트리의 시작으로부터 상대적인 오프셋

 

$LogFile 순서 번호

  • 해당 번호는 응용 프로그램 참조 모델에서 알아본 저널링에 사용되는 번호

 

순서 번호

  • 엔트리가 할당되거나 비 할당 될 때 증가하는 값

  • 운영체제에 의해 결정

 

링크 카운트

  • 하드 링크의 개수를 나타냄

 

플래그

  • 해당 오프셋 값은 '0x0001'로 설정된다면 해당 엔트리가 사용 중이라는 것을 의미

  • '0x0002'로 설정된다면 해당 엔트리가 디렉토리에 할당된 엔트리라는 것을 의미

 

다음 속성 ID 필드까지를 'MFT 엔트리 헤더'라고 한다.

 

 

17-3. 속성

  • MFT 엔트리의 대부분은 속성으로 되어 있으며 그 속성들은 속성 헤더와 속성 내용으로 나뉘게 됨

  • 속성 헤더는 모두 같은 데이터 구조체를 지님

  • 속성 내용은 거주 속성과 비거주 속성으로 나뉘어 조금씩 다른 데이터 구조체를 지님

 

다음 표는 속성 헤더 오프셋에 대한 구조이다.

 

[표 2] 속성 헤더 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

0~3

속성 타입 식별자

4~7

속성 길이

8~8

비거주 플래그

12~13

플래그

9~9

이름 길이

14~15

속성 식별자

10~11

속성 이름 오프셋

   

 

비거주 플래그

  • 해당 오프셋 값은 속성 내용이 비거주 속성일 경우 셋팅괴는 값으로 비거주 속성일 경우 '0x01'로 설정

 

속성 이름 오프셋

  • 속성 헤더의 시작으로부터 상대적인 오프셋 값

 

플래그

  • 해당 값은 속성의 압축(0x0001), 암호화(0x4000), sparse(0x8000)을 의미하는 값

 

속성 식별자

  • MFT에서 속성에 대한 고유 번호

 

속성 헤더 바로 다음으로는 거주 또는 비거주 속성 데이터 구조체가 위치한다.

 

 

다음 표는 거주 속성 오프셋 구조이다.

 

[표 3] 거주 속성 오프셋 구조

범위(Byte)

설명

0~15

일반 헤더

16~19

내용 크기

20~21

내용 오프셋

 

다음 표는 비거주 속성 오프셋 구조이다.

 

[표 4] 비거주 속성 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

0~15

일반 헤더

36~39

사용 x

16~23

Runlist 시작 VCN

40~47

속성 내용 할당 크기

24~31

Runlist 끝 VCN

48~55

속성 내용 실제 크기

32~33

Runlist 오프셋

56~63

속성 내용 초기화 크기

34~35

압축 블록 크기

   

 

VCN

  • 논리적 파일 주소에 대한 다른 이름

  • 해당 값의 시작과 끝은 여러 MFT 엔트리들이 하나의 속성을 설명할 필요가 있을 때 사용

 

Runlist 오프셋

  • 해당 값은 속성 헤더 시작 오프셋에서의 상대적인 값

 

MFT 엔트리에 대한 기본적인 분석은 끝났지만 이 정도 분석으로 MFT 엔트리의 분석이 끝나는 것은 아니다.

 

MFT 엔트리에 할당되는 표준 속성들을 모두 분석해야 MFT 엔트리 분석이 모두 끝이 난다.

 

 

STANDARD_INFORMATION 속성

  • 해당 속성은 항상 거주 속성으로 타입 식별자는 16

  • 또 모든 파일과 디렉토리에 존재하며, 파일이나 디렉토리를 위한 기본 메타데이터 파일들을 포함

 

다음 표는 $STANDARD_INFORMATION 속성의 오프셋 별로 의미하는 것을 분석한 것이다.

 

[표 5] $STANDARD_INFORMATION 속성 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

0~7

생성 시간

40~43

버전 번호

8~15

파일 변경 시간

44~47

클래스 ID

16~23

MFT 변경 시간

48~51

소유자 ID (3.0 버전 이상)

24~31

파일 접근 시간

52~55

보안 (3.0 버전 이상)

32~35

플래그

56~63

할당 크기 (3.0 버전 이상)

36~39

버전 번호 중 최대 번호

64~71

업데이트 순서 번호 (USN) (3.0 버전 이상)

 

4개의 시간 값

  • 해당 시간 값들이 우리가 흔히 속성 창에서 볼 수 있는 시간 값

  • 1601년 1월 1일 UTC부터 100 나노초 단위로 계산되어 저장

 

플래그

  • 해당 파일에 적용될 수 있는 속성들 중 어떠한 속성을 나타내는 값이 저장되는 오프셋

 

보안 ID

  • 이 값은 $Sparse 파일의 인덱스 값

  • 보안 ID 값이 아님

 

플래그 오프셋에 대한 정보는 다음과 같다.

  • 0x0001 : 읽기 전용

  • 0x0002 : 숨김

  • 0x0004 : 시스템

  • 0x0020 : 아카이브

  • 0x0040 : 장치

  • 0x0080 : #일반

  • 0x0100 : 임시

  • 0x0200 : Sparse 파일

  • 0x0400 : 재파싱 지점

  • 0x0800 : 압축

  • 0x1000 : 오프라인

  • 0x2000 : 빠른 검색을 위한 인덱스 외의 내용

  • 0x4000 : 암호화

 

 

$FILE_NAME 속성

  • 해당 속성 타입 식별자는 48

  • 파일 이름과 부모 디렉토리 정보 저장을 위해 MFT 엔트리에 위치

  • 디렉토리 인덱스에서 사용

  • MFT 엔트리에서 사용될 때에는 포함되어 있는 정보가 필수적이지 않지만, 디렉토리 인덱스에서 사용될 때에는 다름

  • 해당 속성은 위에서 설명한 $STANDARD_INFORMATION 속성과 함께 필수적인 속성

  • 항상 거주 속성

 

또 해당 속성은 일반적으로 $STANDARD_INFORMATION 속성과 $DATA 속성 가운데에 위치하게 되는데 만약 하나의 파일에 여러 MFT 엔트리가 할당 될 경우 다른 비기준 엔트리의 속성을 포함하는 $ATTRIBUTE_LIST 속성이 $STANDARD_INFORMATION 속성과 $FILE_NAME 속성 사이에 위치한다.

 

 

다음 표는 $FILE_NAME 속성에 대한 오프셋 구조이다.

 

[표 6] $FILE_NAME 속성 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

0~7

부모 디렉토리 파일 참조

48~55

파일 실제 크기

8~15

파일 생성 시간

58~59

플래그

16~23

파일 수정 시간

60~63

재파싱 값

24~31

MFT 수정 시간

64~64

이름 길이

32~39

파일 접근 시간

65~65

네임스페이스

40~47

파일 할당 크기

66~

이름

 

부모 디렉토리 파일 참조

  • 해당 값의 상위 2바이트는 부모 디렉토리의 순서 번호

  • 하위 6바이트는 부모 디렉토리의 MFT 엔트리 번호

 

플래그

  • 해당 오프셋 값은 $STANDARD_INFORMATION의 플래그 값과 동일

 

네임스페이스

  • 이름 필드의 값이 어떤 형식인지 나타내는 값을 가짐

  • 흔히 파일 이름 규칙을 뜻함

 

이름

  • 이름 오프셋의 길이는 파일명에 따라 달라짐

  • 정확한 길이를 알고자 하면 이름 길이 오프셋을 참고하면 됨

 

 

$DATA

  • 해당 속성은 고유한 구조체를 가지고 있지 않음

  • 헤더 이후로는 파일 내용 데이터만 존재

  • 타입 식별자는 128이며 크기는 정해져 있지 않음

  • 하지만 내용이 700Byte 이상이라면 비거주 속성이 되어 클러스터가 할당

 

 

$ATTRIBUTE_LIST

  • 해당 속성은 MFT 엔트리에 존재하는데 $STANDARD_INFORMATION 속성과 $FILE_NAME 속성 사이에 위치

  • 타입 식별자는 32

  • MFT 엔트리에 여러 속성들이 할당되어 엔트리 크기인 1024Byte를 초과할 때 사용

  • 해당 속성 내용으로는 기준 MFT 엔트리에 포함되려 했던 속성들의 엔트리 리스트가 목록화 되어 있음

 

속성 시작 VCN은 여러 MFT엔트리들이 단일 속성을 ㅓㄹ명해야 할 때 필요하며, 이름 오프셋은 해당 엔트리 시작으로부터 상대적 오프셋 값이다.

 

 

다음 표는 $ATTRIBUTE_LIST에 대한 오프셋 구조이다.

 

[표 7] $ATTRIBUTE_LIST 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

0~3

속성 타입 식별자

8~15

속성 시작 VCN

4~5

해당 엔트리 길이

16~23

속성이 위치하려 했던 엔트리

6~6

이름 길이

24~24

속성 ID

7~7

이름 오프셋

   

 

 

$OBJECT_ID

  • 해당 속성은 64 타입 식별자를 가짐

  • 이름 대신 파일을 지칭하는 128bit의 오브젝트 식별자를 포함

  • 해당 속성은 간단한 구조로 되어 있음

  • 총 4개의 필드로 구성되어 있으나 보통 첫 번째 필드만 설정되어 있음

 

다음 표는 $OBJECT_ID 오프셋에 대한 구조이다.

 

[표 8] $OBJECT_ID 오프셋 구조

범위(Byte)

설명

0~15

오브젝트 ID

16~31

파일이 생성된 볼륨 ID

32~47

파일이 생성될 때 받은 오브젝트 ID

48~63

파일이 생성될 때 받은 도메인 ID

 

$OBJECT_ID 속성 구조를 보면 오브젝트 ID 필드가 존재하는데 이 필드는 \$Extend\ObjID 인덱스들을 정렬할 때 사용되기도 한다.

 

 

$REPARSE_POINT

  • 해당 속성은 식별자 192를 가짐

  • 해당 속성은 재파싱 지점의 파일에 할당 됨

  • 8~9 오프셋 범위와 12~13 오프셋 범위는 바이트 오프셋 16에서 상대적인 오프셋 값을 가짐

 

다음 표는 $REPARSE_POINT 속성 오프셋에 대한 구조이다.

 

[표 9] $REPARSE_POINT 속성 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

0~3

Reparse 타입 플래그

10~11

대상 이름 길이

4~5

Reparse 데이터 크기

12~13

대상의 출력 이름 오프셋

6~7

사용 x

14~15

출력 이름 길이

8~9

대상 이름 오프셋

   

 

 

INDEX_ROOT

  • 해당 속성은 타입 식별자 144를 가짐

  • 항상 거주 속성

  • 해당 속성의 엔트리는 항상 인덱스 트리의 루트

 

다음 표는 $INDEX_ROOT 속성 헤더 오프셋에 대한 구조이다.

 

[표 10] $INDEX_ROOT 속성 헤더 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

0~3

인덱스 속성 타입

12~12

인덱스 레코드 크기(클러스터)

4~7

수집 정렬 규칙

13~15

사용 x

8~11

인덱스 레코드 크기

16~

노드 헤더

 

인덱스 내의 속성 타입

  • 인덱스에 포함되어 있는 엔트리의 속성 타입을 포함하는 오프셋

  • 엔트리가 속성을 사용하지 않는 경우 0으로 설정

 

수집 정렬 규칙

  • $INDEX_ALLOCATION 속성에서 정렬되는 규칙

 

인덱스 레코드 크기(Byte)

  • 인덱스 레코드의 바이트 크기를 포함하는 오프셋

 

인덱스 레코드 크기(클러스터)

  • 인덱스 레코드 크기만큼 필요한 클러스터 수

 

$INDEX_ROOT 속성 헤더는 16바이트의 크기를 가지며, 노드 헤더 또한 16바이트의 크기를 가진다.

 

[그림 1] $INDEX_ROOT 속성의 레이아웃

 

 

$INDEX_ALLOCATION

  • 큰 디렉토리일 경우 인덱스 엔트리가 $INDEX_ROOT 속성에 적합하지 않음

  • 이러한 경우 비 거주 속성인 해당 속성이 사용 됨

  • 해당 속성 내용은 인덱스 레코드로 이루어져 있는데, 인덱스 레코드의 크기는 고정

  • 정렬된 트리의 노드 하나를 포함하고 있음

  • 인덱스 레코드의 크기는 $INDEX_ROOT 속성 헤더의 정의되어 있으며, 보통 4096Byte

  • 해당 속성의 타입 식별자는 160이며 해당 속성의 내용인 인덱스 레코드는 특별한 헤더 데이터 구조체로 시작

  • 헤더 다음으로 노드 헤더와 인덱스 엔트리의 목록이 옴

 

[그림 2] $INDEX_ALLOCATION 속성 레이아웃

 

다음 표는 인덱스 레코드 헤더에 대한 오프셋이다.

 

[표 11] 인덱스 레코드 헤더 오프셋

범위(Byte)

설명

범위(Byte)

설명

0~3

시그니처(INDX)

8~15

$LogFile 순서 번호(LSN)

4~5

Fixup 배열 오프셋

16~23

전체 인덱스 스트림에서 해당 레코드 VCN

6~7

Fixup 배열 엔트리 수

24~

노드 헤더

 

시그니처

  • 인덱스 레코드에는 시그니처가 존재

  • 시그니처는 'INDX'

 

Fixup 배열 오프셋

  • 해당 오프셋의 값은 Fixup 배열의 오프셋 주소

  • 인덱스 레코드 헤더 시작 부분에서 상대적

 

 

BITMAP

  • 해당 속성은 인덱스 레코드의 할당 상태를 관리하는 속성

  • 모든 인덱스 레코드가 할당되는 것은 아니며 운영체제 판단에 의해 필요 시 할당

  • $BITMAP 속성은 MFT 엔트리 할당 추적을 위해 $MFT에 의해 사용

  • 해당 속성은 타입 식별자 176을 가지며 각 바이트를 비트로 변환하여 인덱스 레코드와 맵핑

[그림 3] $BITMAP 속성 내용

 

[그림 3]을 분석해 보면 첫 바이트가 0x01인데 비트로 변환 시 0000 0001이다.

 

이것은 인덱스 레코드 0이 할당 되었다는 것을 의미한다.

 

만약 0x02 바이트여서 0000 0010이라면 인덱스 레코드 1이 할당 되었다는 것을 의미한다.

 

 

인덱스 노드 헤더 데이터 구조체

  • $INDEX_ROOT 속성과 $INDEX_ALLOCATION 속성 다음에 위치하게 되는 16Byte의 크기를 가짐

 

다음 표는 노드 헤더 오프셋에 대한 구조이다.

 

[표 12] 노드 헤더 오프셋 구조

범위(Byte)

설명

0~3

인덱스 엔트리 목록 시작에서의 오프셋

4~7

인덱스 엔트리 목록 마지막에서의 오프셋

8~11

할당된 인덱스 엔트리 목록 버퍼 마지막에서의 오프셋

12~15

플래그

 

인덱스 엔트리 목록 시작 오프셋

  • 해당 값은 노드 헤더 시작에서 상대적

 

인덱스 엔트리 목록의 마지막 오프셋

  • 해당 값은 노드 헤더 마지막에서 상대적

 

플래그

  • 플래그는 설정되지 않거나 0x01로 설정되는 경우 밖에 없음

  • 0x01로 설정되는 경우 인덱스 엔트리 목록에 있는 엔트리에 의해 지정된 자식 노드가 있다는 것을 의미

 

 

17-4. 인덱스 엔트리

 

표준 인덱스 엔트리

  • 말 그대로 인덱스 엔트리의 표준 레이아웃을 가진 인덱스 엔트리

  • 어떠한 내용도 가질 수 있는 엔트리

 

다음 표는 인덱스 엔트리 오프셋에 대한 구조이다.

 

[표 13] 표준 인덱스 엔트리 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

0~7

????

12~15

플래그

8~9

엔트리 길이

16~

내용

10~11

내용 길이

   

 

플래그

  • 0x01 : 자식 노드가 존재

  • 0x02 : 인덱스 엔트리 목록에서 마지막 엔트리

 

디렉토리 인덱스 엔트리

  • 파일 이름을 사용하는 디렉토리 인덱스는 자신만의 데이터 구조체를 가짐

 

다음 표는 디렉토리 인덱스 엔트리 오프셋에 대한 구조이다.

 

[표 14] 디렉토리 인덱스 엔트리 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

0~7

파일 이름의 MFT 파일 참조

12~15

플래그

8~9

해당 엔트리 길이

16~

내용

10~11

$FILE_NAME 속성 길이

   

 

플래그

  • 표준 인덱스 엔트리의 플래그와 동일

표준 인덱스 엔트리와 디렉토리 인덱스 엔트리 마지막 8바이트는 $INDEX_ALLOCATION에 있는 자식 노드의 VCN 값을 가지고 있다.


(18) 메타데이터 파일

 

$MFT

 

해당 메타데이터 파일은 앞 내용에서 많이 언급하였으므로 해당 메타데이터 파일의 일반적 구조와 속성은 생략하고, 고유 속성인 $BITMAP 속성만 분석해 볼 것이다.

 

  • $BITMAP 속성은 NTFS의 MFT 엔트리 할당 상태를 관리하는 속성

  • 각 비트가 MFT 엔트리의 맵핑되어 MFT 엔트리가 할당되면 해당 MFT 엔트리와 맵핑 관계인 비트가 1로 설정

[그림 4] $MFT 파일의 $BITMAP 속성 오프셋

 

[그림 4]를 보면 F로 설정된 오프셋과 0으로 설정된 오프셋이 있는데 F로 설정된 오프셋이 할당 상태를 뜻하고 0으로 설정된 오프셋이 비할당 상태를 뜻한다.

 

MFT 엔트리 맵핑 관계는 각 오프셋을 비트로 변환하면 알 수 있다.

 

  • 0 오프셋 (FF) : 1111 1111 (MFT 엔트리 0 ~ 7 할당)

  • 1 오프셋 (FF) : 1111 1111(MFT 엔트리 8 ~ 15 할당)

  • 2 오프셋 (00) : 0000 0000 (MFT 엔트리 16 ~ 23 할당)

  • 3 오프셋 (FF) : 1111 1111 (MFT 엔트리 24 ~ 31 할당)

  • 4 오프셋 (7B) : 0111 1011 (MFT 엔트리 32 ~ 33 할당, 34 비할당, 35 ~ 38 할당, 39 비할당)

  • 5 오프셋 (00) : 0000 0000 (MFT 40 ~ 47 비할당)

  • 6 오프셋 (00) : 0000 0000 (MFT 엔트리 48 ~ 55 비할당)

  • 7 오프셋 (00) : 0000 0000 (MFT 엔트리 56 ~ 63 비할당)

 

$Boot

  • 해당 메타데이터 파일은 MFT 엔트리 여덟 번째에 위치

  • 부트 섹터와 부트 코드를 포함

  • 부트 섹터는 항상 섹터 0에서 시작하며, 부트 섹터를 제외한 섹터들은 부트 코드를 위해 사용

  • 부트 섹터에서 체크해야 할 부분들은 섹터와 클러스터의 크기를 정의하는 부분 (이 부분이 없으면 어떠한 것도 위치 파악 불가능)

  • 다음으로 MFT 엔트리 크기를 정의하는 부분을 체크해야 함

  • MFT 엔트리의 인덱스 레코드를 의미하는 필드들은 모두 특별한 형식을 가짐

 

만약 MFT 엔트리나 인덱스 레코드를 의미하는 필드들의 값이 0보다 크면 각 데이터 구조체에서 사용하는 클러스터 수를 값으로 가지게 된다.

 

또 0보다 작다면 각 데이터 구조체에 있는 바이트 수 밑이 2인 로그 값을 저장한다.

 

이러한 현상은 클러스터 크기가 단일 MFT 엔트리나 인덱스 레코드보다 클 경우 일어난다.

 

보통은 1024Byte이지만 이 값은 언제든지 수정될 수 있기 때문이다.

 

 

다음 표는 $Boot 파일의 오프셋이다.

 

[표 15] $Boot 파일 오프셋

범위(Byte)

설명

범위(Byte)

설명

0 ~ 2

부트 코드 점프 명령

32 ~ 35

사용 X

3 ~ 10

OEM 이름

36 ~ 39

사용 X

11 ~ 12

섹터별 Byte(512, 1024, 2048, 4096)

40 ~ 47

섹터 총 개수

13 ~ 13

클러스터별 섹터 수

48 ~ 55

$MFT 파일의 클러스터 번호

14 ~ 15

예약 영역

56 ~ 63

$MFTMirr 파일의 클러스터 번호

16 ~ 18

언제나 O

64 ~ 67

파일 레코드 세그먼트별 클러스터 개수

19 ~ 20

사용 X

68 ~ 71

인덱스 블록별 클러스터 개수

21 ~ 21

장치 타입

72 ~ 79

볼륨 시리얼 번호

22 ~ 23

언제나 O

80 ~ 83

체크섬

24 ~ 25

저장 장치 트랙별 섹터 수

84 ~ 509

부트 코드

26 ~ 27

저장 장치 헤드 개수

510 ~ 511

시그니처(0xAA55)

 

$AttrDef

  • 해당 메타데이터 파일은 MFT 엔트리 다섯 번째에 위치

  • 파일 시스템 속성들의 이름과 식별자 정의

 

다음 표는 $AttrDef 파일의 오프셋이다.

 

[표 16] $AttrDef 파일 오프셋

범위(Byte)

설명

범위(Byte)

설명

0 ~ 127

속성 이름

140 ~ 143

플래그

128 ~ 131

타입 식별자

144 ~ 151

최소 크기

132 ~ 135

출력 규칙

152 ~ 159

최대 크기

136 ~ 139

수집 규칙

   

 

플래그

  • 0x02 : 인덱스에서 속성이 사용

  • 0x40 : 항상 거주 속성

  • 0x80 : 비거주 속성

 

 

$BITMAP

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

  • 해당 비트맵의 내용은 $DATA 속성에 저장

  • 각 비트별로 클러스터와 맵핑되어 있는데 어떠한 클러스터의 할당 상태를 알고자 할 때 해당 메타데이터 파일 해당 클러스터의 비트를 찾아야 함

  • 하지만 무작정 찾기에는 매우 시간이 오래 걸림

이러한 시간 낭비를 줄이기 위해 다음과 같은 계산식을 적용한다.

 

$BITMAP 내의 바이트 오프셋 = 클러스터 번호 / 8

$BITMAP 내의 클러스터 비트 오프셋 = 클러스터 번호 - 8 x $BITMAP 내의 바이트 오프셋

 

 

$Volume

  • 해당 메타데이터 파일은 두 개의 속성으로 이루어져 있으며 이 속성을 중점적으로 해당 메타데이터 파일을 분석해야 함

  • 해당 메타데이터 파일은 MFT 엔트리 네 번째에 위치

  • 가지고 있는 속성으로는 $VOLUME_NAME과 $VOLUME_INFORMATION이 있음

 

 

VOLUME_NAME

  • 해당 속성은 $VOLUME 파일이 할당되었을 경우만 사용되는 속성

  • 타입 식별자는 96

  • 파일 내용으로는 파일 시스템의 볼륨 이름을 저장하고 있음

[그림 5] $VOLUME_NAME 속성 내용

 

VOLUME_INFORMATION

  • 해당 속성은 $VOLUME 파일의 두 번째 속성

  • 내용으로는 파일 시스템 버전을 포함

  • 타입 식별자는 112

 

다음 표는 $VOLUME_INFORMATION 속성 오프셋 구조이다.

 

[표 17] $VOLUME_INFORMATION 속성 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

0 ~ 7

사용 x

9 ~ 9

부 버전

8 ~ 8

주 버전

10 ~ 11

플래그

 

플래그

  • 0x0001 : 불량

  • 0x0002 : $LogFile 크기 재정의

  • 0x0004 : 다음 업그레이드 볼륨

  • 0x0008 : NT 시스템에 마운트 됨

  • 0x0010 : 변경저널 삭제

  • 0x0020 : 오브젝트 ID를 교정

  • 0x8000 : Chkdsk에 의해 수정

 

 

$ObjId

  • NTFS에서는 다른 파일 시스템과 달리 파일 이름 말고도 오브젝트 ID를 사용하여 파일을 구별할 수 있음

  • 어떠한 파일을 포함하는 인덱스는 $INDEX_ROOT 속성과 $INDEX_ALLOCATION 속성을 일반적으로 가짐

  • 파일을 직접적으로 포함하고 있는 인덱스 엔트리는 특정 데이터 구조체를 가지고 있음

 

다음 표는 $ObjId 파일의 오프셋 구조이다.

 

[표 18] $ObjId 파일 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

0 ~ 1

파일 정보 오프셋

16 ~ 31

오브젝트 ID

2 ~ 3

파일 정보 크기

32 ~ 39

파일 참조

4 ~ 7

사용 x 

40 ~ 55

파일이 생성된 볼륨 ID

8 ~ 9

인덱스 엔트리 크기

56 ~ 71

파일이 생성될 때 받은 오브젝트 ID

10 ~ 11

오브젝트 ID 크기

72 ~ 87

파일이 생성될 때 받은 도메인 ID

12 ~ 15

플래그

   

 

플래그

  • 0x01 : 자식 노드가 존재

  • 0x02 : 목록에서 마지막 엔트리

 

 

$Quota

  • 해당 메타데이터 파일은 $INDEX_ROOT와 $INDEX_ALLOCATION 속성을 일반적으로 사용

  • 두 개의 인덱스를 가짐 

 

두 개의 인덱스는 다음과 같다.

  • $O 인덱스 : 하나의 SID와 소유자 ID를 연결시키는 역할

  • $Q 인덱스 : 할당 정보에 자신의 ID를 연결시키는 역할

 

[표 19] $O 인덱스 오프셋의 구조

범위(Byte)

설명

0 ~ 1

소유자 ID 오프셋

2 ~ 3

소유자 ID 길이

4 ~ 7

사용 x

8 ~ 9

인덱스 엔트리 크기

10 ~ 11

SID 크기

12 ~ 15

플래그

16 ~ (16+SID 크기 -1)

SID

소유자 ID 오프셋 ~

소유자 ID

 

소유자 ID 오프셋

  • 해당 오프셋 값은 $O 인덱스 시작으로부터 상대적

 

플래그

  • 0x01 : 자식 노드가 존재

  • 0x02 : 목록에서 마지막 엔트리

 

소유자 ID

  • 해당 오프셋은 소유자 ID 오프셋(0~1)을 참조

  • 해당 바이트 오프셋부터 소유자 ID 길이 만큼까지가 오프셋 범위

 

 

[표 20] $Q 인덱스 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

0 ~ 1

할당 정보 오프셋

2 ~ 3

할당 정보 크기

4 ~ 7

사용 x

8 ~ 9

인덱스 엔트리 크기

10 ~ 11

소유자 ID 크기

12 ~ 15

플래그

16 ~ 19

소유자 ID

44 ~ 51

임계치

20 ~ 23

버전

52 ~ 59

절대 제한 값

24 ~ 27

할당 플래그

60 ~ 67

초과 시간

28 ~ 35

사용자에게 할당된 바이트 영역

68 ~ 79

SID

36 ~ 43

마지막으로 할당된 시간

   

 

소유자 ID 크기

  • 해당 오프셋의 값은 언제나 '0x0004'

 

플래그

  • 0x01 : 자식 노드 존재

  • 0x02 : 목록에서 마지막 엔트리

 

할당 플래그

  • 0x00000001 : 기본 한계치를 사용

  • 0x00000002 : 한계에 도달

  • 0x00000004 : ID 삭제

  • 0x00000010 : 데이터 사용을 관찰

  • 0x00000020 : 강제적으로 데이터 사용

  • 0x00000040 : 사용량 추적을 요청

  • 0x00000080 : 사용량에 거의 도달하면 로그 생성

  • 0x00000100 : 한계 값에 도달하면 로그 생성

  • 0x00000400 : 기한을 지남

  • 0x00000800 : 사용을 금함

 

 

$LogFile

  • 해당 메타데이터는 MFT 엔트리 세 번째에 위치

  • NTFS 저널링에 사용

  • 속성은 표준 속성을 가지고 있고, 로그 데이터를 내용으로 가지고 있는데 이 내용은 $DATA 속성에 포함되어 있음

  • 하지만 오프셋 구조는 아직 정확히 알려진 바가 없음

 

$UsrJrnl

  • 해당 메타데이터 파일은 변경 저널링에 사용

  • 파일에 변경이 발생하면 해당 메타데이터 파일에 관련 정보가 기록

  • 해당 파일도 $ObjId, $Quota 등의 파일과 마찬가지로 MFT 예약 엔트리에 있지 않고 $Extend 메타데이터 파일에 포함

  • 해당 메타데이터 파일에는 두 가지 $DATA 속성이 존재

 

두 가지의 $DATA 속성은 다음과 같다.

  • $J : 이 속성은 sparse 속성이며, 다른 크기로 된 데이터 구조체 목록을 포함하고 있음

  • $Max : 사용자 저널링 최대 설정의 대한 정보를 포함하고 있음

 

[표 21] $J 속성의 오프셋 구조

범위(Byte)

설명

범위(Byte)

설명

0 ~ 3

해당 저널 엔트리 크기

40 ~ 43

변경 유형 플래그

4 ~ 5

주 버전

44 ~ 47

출처 정보

6 ~ 7

부 버전

48 ~ 51

보안 ID (SID

8 ~ 15

해당 엔트리와 관련된 엔트리 번호

52 ~ 55

파일 속성

16 ~ 23

부모 디렉토리 엔트리 번호

56 ~ 57

파일 이름 크기

24 ~ 31

엔트리 USN

58 ~

파일 이름

32 ~ 39

타임스탬프

   

 

변경 유형 플래그

  • 0x00000001 : 기본 $DATA 속성이 덮어 씌워짐

  • 0x00000002 : 기본 $DATA 속성이 추가됨

  • 0x00000004 : 기본 $DATA 속성이 줄어듦

  • 0x00000010 : 이름이 있는 $DATA 속성이 덮어 씌워짐

  • 0x00000020 : 이름이 있는 $DATA 속성이 추가됨

  • 0x00000040 : 이름이 있는 $DATA 속성이 줄어듦

  • 0x00000080 : 파일이나 디렉토리가 생성됨

  • 0x00000100 : 파일이나 디렉토리가 삭제됨

  • 0x00000400 : 파일의 확장된 속성이 변경됨

  • 0x00000800 : 보안 기술자가 변경됨

  • 0x00001000 : 이름이 변경되고, 변경 저널 엔트리가 이전 이름을 가지고 있음

  • 0x00002000 : 이름이 변경되고, 변경 저널 엔트리가 새로운 이름을 가지고 있음

  • 0x00004000 : 인덱스 상태 변경

  • 0x00008000 : 파일이나 디렉토리 속성이 변경됨

  • 0x00010000 : 하드 링크 생성 또는 삭제

  • 0x00020000 : 압축 상태 변경

  • 0x00040000 : 암호 상태 변경

  • 0x00080000 : 오브젝트 ID 변경

  • 0x00100000 : Reparse 지점값 변경

  • 0x00200000 : 이름이 있는 $DATA 속성이 있는 생성 또는 삭제, 변경됨

  • 0x80000000 : 파일 또는 디렉토리가 닫힘

 

[표 22] $Max 속성 오프셋 구조

범위(Byte)

설명

0 ~ 7

최대 크기

8 ~ 15

할당 크기

16 ~ 23

USB ID

24 ~ 31

최하위 USN

 

$Max 오프셋 구조를 보면 포렌식적 의미를 가진 정보는 없다.

 

NTFS는 여러 가지 기능과 복합적 구조로 인해 분석하기 어려운 편에 속하는 파일 시스템이다.

 

또 아직까지 알려지지 않은 데이터 구조체 필드로 인해 또 어떠한 포렌식적 의미의 정보가 있는지 알 수 없는 파일 시스템이다.


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

 

NTFS에서도 FAT 파일 시스템과 마찬가지로 비할당 영역이나 슬랙 공간을 주시해야 한다. (모든 파일 시스템이 동일)

 

FAT 파일 시스템의 부트 섹터에는 데이터를 숨길 공간이 연속적으로 존재하므로 숨길 가능성이 높았다.

 

하지만 NTFS의 부트 섹터 영역은 그 공간들이 FAT 파일 시스템과 비슷하게 있지만 일부 필드의 값이 무조건적으로 0으로만 설정되어 있어야 파일 시스템이 마운트되기 때문에 이러한 필드들을 제외하고 데이터를 숨기기에는 까다로워 숨기기에는 적합하지 못하다.

 

NTFS의 구조를 아는 공격자라면 부트 섹터보다는 $Boot 파일 이후의 영역에 데이터를 숨길 것이다.

 

또한, NTFS 파일 시스템에도 볼륨 슬랙이 존재하므로 볼륨 슬랙을 체크하는 것이 좋다.


# Reference

 

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

[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

+ Recent posts