Filesystem

EXT4에 대한 이해 (Part 1) : Extents

behonestar 2015. 2. 15. 14:36

이 글은 Understanding EXT4 (Part 1): Extents 포스트를 번역한 자료입니다. 


EXT4는 리눅스 파일시스템의 EXT2/EXT3 패밀리를 대체할 차세대 파일 시스템이다. 2008년 10월 리눅스 2.6.28 커널에 안정적으로 적용되었다.[각주:1] 개발자들이 EXT2/EXT3과의 하위 호환성을 어느 정도 유지하려고 한 반면에 EXT4는 상당히 새롭고 많이 바뀌어버렸다. Sleuthkit과 같은 유명한 포렌식 툴은 EXT4의 이러한 변화에 완벽하게 호환되지 않는다. 


EXT4와 관련된 몇몇의 프레젠테이션을 읽는 동안[각주:2] EXT4 구조체가 실제로 디스크에서 어떻게 보여지는지, EXT4의 어떠한 변화가 현존하는 포렌식 툴을 비정상적으로 동작하게 하는지 궁금증이 생겼다. 그래서 나는 오래된 나의 hex editor를 사용하여 스스로 분석해보기로 했다. 이 글은 내가 발견한 것들을 정리한 첫번째 글이다.


Block Addressing


EXT4는 48비트 주소 체계로 바뀌었다. 그 이유들(최대 파일 시스템 크기 등)을 설명한 페이퍼는 나중에 언급할 것이다. EXT4는 extents를 사용하는 것부터 시작한다. 이는 EXT2/EXT3의 비효율적인 간접 블락[각주:3] 매커니즘을 대체한다. Extents는 NTFS 파일 시스템에서 동작하는 클러스터와 유사하다. 이들은 최초의 블록 주소와 extent를 이루는 블록의 개수를 명시한다. EXT4는 블록의 연속성을 최대한 유지하려고 하지만, 그럼에도 조각난 파일은 여러개의 extents로 구성된다.


이러한 새로운 블록 주소 체계는 현존하는 포렌식 툴의 많은 문제를 야기하는 요소 중 하나이다. 예를 들어, EXT4 파일 시스템에 새로운 파일을 생성할 때 무슨 일이 일어나는지 보자. 


# echo Here is a new file >testfile

# ls -li testfile

918817 -rw-r--r-- 1 root root 19 2010-12-05 11:08 testfile

# istat /dev/mapper/elk-home 918817

inode: 918817

Allocated

Group: 112

Generation Id: 3173542730

uid / gid: 0 / 0

mode: rrw-r--r--

Flags:

size: 0

num of links: 1


Inode Times:

Accessed:      Sun Dec 5 11:08:49 2010

File Modified: Sun Dec 5 11:08:49 2010

Inode Modified: Sun Dec 5 11:08:49 2010



Direct Blocks:


istat이 새로운 extent 구조체를 완전하게 decode할 수 없을 뿐더러 블록 주소 또한 보여지지 않는다. 파일 사이즈 또한 0 byte로 잘못 표시된 것을 볼 수 있다. 반면 -owner, group owner, MAC times 등과 같은- inode 메타데이터의 값들은 올바르게 표시되어있다.


사실 EXT4 개발자들은 EXT2/EXT3와의 inode 하위호환성을 유지하기 위해 매우 노력했지만 extents 또는 timestamp와 같은 변화들로 인해 완벽한 호환성을 유지하기는 어려웠다.


Unpacking the EXT4 inode


나는 hex editor를 사용하여 EXT4 inode를 확인하고 싶었다. 이를 위해서는 이 파일에 대한 inode가 실제 디스크에 위치한 곳을 정확히 알아내는 것이 우선이다. 다행히도 EXT4의 superblock과 block group descriptor table은 fsstat을 사용하여 우리가 필요한 정보를 얻는데 충분히 호환성이 있었다.


# fsstat /dev/mapper/elk-home

FILE SYSTEM INFORMATION

--------------------------------------------

File System Type: Ext3

[...]

CONTENT INFORMATION

--------------------------------------------

Block Range: 0 - 113971199

Block Size: 4096

Free Blocks: 13506529


BLOCK GROUP INFORMATION

--------------------------------------------

Number of Block Groups: 3479

Inodes per group: 8192

Blocks per group: 32768

[...]

Group: 112:

 Inode Range: 917505 - 925696 //8192개

 Block Range: 3670016 - 3702783

 Layout:

 Data bitmap: 3670016 - 3670016

 Inode bitmap: 3670032 - 3670032

 Inode Table: 3670048 - 3670559 //512 블록

 Data Blocks: 3670033 - 3670047, 3670560 - 3702783

 Free Inodes: 3281 (40%)

 Free Blocks: 0 (0%)

 Total Directories: 2

[...]


위의 istat 결과물을 통해 inode가 블록 그룹 112에 위치한다는 것과 그룹 112에 대한 inode 주소가 918817이라는 것을 확인할 수 있다. 또한 fsstat 결과물을 통해 inode의 주소가 실제로 inode의 블록 범위에 포함된다는 것도 확인할 수 있다.


EXT4의 한가지 중요한 변화는 inode가 256 bytes라는 것이다. 이는 4K 블록당 16개의 inode가 존재한다는 것을 의미한다. (256 * 16 = 4096) 따라서 "블록 그룹당 8192개의 inode"는 각 그룹의 시작점에서 512개(8192/16)의 블록을 차지해야 한다. 그리고 블록 그룹에 대한 inode table 역시 512 블록(3670048 - 3670559)을 차지하는 것을 볼 수 있다.


그런데 어떤 블록에 우리가 찾으려는 inode가 들어있을까? 그룹 112의 첫번째 inode 주소는 917505이다. 918817에서 이 값을 빼면 우리의 inode는 inode table의 시작으로부터 1312번째 inode라는 것을 알 수 있다. 운좋게도 이것은 블록의 중간이 아닌 시작점으로 우리를 안내한다. (1312 inodes / 16 inodes per block은 정확히 82번째 블록) 만약 inode table의 첫번째 블록 주소가 3670048이라면, 3670130 블록의 처음 256 byte가 우리가 찾는 inode이다.


blkcat을 사용하여 이 블록을 dump하면 hex editor에서 보다 쉽게 inode를 확인할 수 있다.


# blkcat /dev/mapper/elk-home 3670130 >blk-3670130



Ext4 Inode Under the Microscope


EXT4의 inode 크기가 기존 EXT3 inode의 2배이지만 EXT4 개발자들은 inode의 처음 128 bytes는 최대한 기존 방식을 유지하려고 했다. 예를 들어, 여전히 byte 4-7은 low-order 32비트로 파일 사이즈를 표현하고 있다.[각주:4]



리틀 엔디안 방식으로 이것을 해석하면 파일 사이즈는 우리가 기대한대로 19bytes이다. 우리가 정확한 inode를 찾은 것으로 보인다.


하지만 EXT4는 블록 포인터 대신 extents를 사용하기 때문에 기존의 블록 포인터를 담기 위해 사용됐던 40-99까지의 60bytes를 현재는 extent 정보를 담는데 사용된다. extent 구조체 크기는 12bytes 이기 때문에 inode당 최대 5개의 extetns가 존재할 수 있을 것으로 예상한다. 하지만 첫 12bytes는 extent header 구조체가 차지하기 때문에 하나의 inode당 최대 exetns 개수는 실제로는 4개이다.


extent header의 값은 아래와 같다.



Bytes 40-41: Magic number (0xF30A = 62218)

      42-43: Number of extents (0x0001 = 1)

      44-45: Max number of extents (0x0004 = 4)

      46-47: Depth of tree (0x0000 = 0)

      48-51: Generation ID (0x00000000 = 0)


Magic number는 다른 extent 수행과 구분하기 위해서 설계되었다. 새로운 기능이 추가됨에 따라 magic number는 하위 호환성을 보장하기 위해 바꿀 수 있다. "Depth of tree"와 "Generation ID"값들에 대해서는 나중에 논의할 것이다.


위에서 얘기했던 inode내의 최대 extents 개수 4개는 44-45 bytes에 나타나있다. 이 2 bytes가는 나중에 extent 구조체를 4개 이상 저장해야하는 경우의 place-holder 역할을 하기도 한다.


다음 12 bytes는 이 extent에 대해 우리가 알아야할 것들을 말해준다.



Bytes 52-55: Logical block number (0x0000)

      56-57: Number of blocks in extent (0x0001)

      58-59: Upper 16 bits of physical block address (0x0000)

      60-63: Lower 32 bits of physical block address (0x003A883F)


Logical block number는 파일의 시작점을 기준으로 어디서 extent가 시작되는지를 말해준다. multiple extents를 갖고 있을 때 이것의 의미는 훨씬 중요해진다. 하지만 예제의 파일은 단일 extent를 갖고 있기 때문에 logical block number는 파일의 첫부분인 0에서 시작해야 한다.


다음 2bytes는 이 extent가 얼마나 많은 블록을 포함하고 있는지를 말해준다. 예제의 경우 작은 파일이기 때문에 1개의 블록만 필요하다.


다음 6bytes는 이 extent의 첫번째 블록의 물리적인 블록 번호를 나타낸다. -extent가 실제로 디스크의 어디서 시작되는지-  현대 컴퓨터 시스템은 16, 32, 64bit 단위의 값을 원하기 때문에 지금처럼 48bit(6bytes)인 경우 문제가 있다. 그래서 48bit 블록 주소는 실제로는 2개의 값으로 표현된다. 처음 2bytes는 블록 주소의 상위 16비트이고, 나머지 4bytes는 블록 주소의 low-order 32bit이다. 따라서 예제에서는 블록 주소를 0x0000003A883F(3835967)로 해석할 것이다.


우리가 맞았는지 확인해보자.


# blkcat /dev/mapper/elk-home 3835967

Here is a new file


더 이상의 extents가 없기 때문에 inode의 다음 36bytes는 null이다. 사용되지 않는 이 필드들이 데이터를 숨기기 위해서도 사용되는 것을 본다면 재미있을 것이다.



Deleting the File


파일이 삭제됐을 때 inode에 무슨일이 일어나는지 보자.


# rm testfile

# blkcat /dev/mapper/elk-home 3835967

Here is a new file

# blkcat /dev/mapper/elk-home 3670130 >blk-3670130-after_delete


위에서 볼 수 있듯이 파일이 삭제됐지만 실제로 데이터 블록은 clear되지 않는다. 이것은 파일 시스템의 표준 동작이다.


하지만 inode에는 무슨일이 일어날까?



몇가지 변화가 있다.

  • 파일 사이즈 값이 0으로 설정됨
  • extent header의 extents 개수가 0으로 설정됨
  • extent 자신도 clear됨

extent를 clear한다는 것은 우리가 첫번째 블록의 물리적인 블록 주소와 extent의 길이를 잃어버렸다는 것을 의미한다. 다시 말해, 삭제된 파일을 복구하는데 필요한 meta-data가 inode에 남아있지 않다는 것이다. 이 동작은 EXT3의 inode가 해제되었을 때 블록 포인터의 clear 동작과 유사하다. 불행하게도 이는 삭제된 파일을 복구하기 위한 전통적인 file-carving 방법론에   묶여있다는 것을 의미한다. 


More to Come

지금까지는 새롭고 놀라운 EXT4의 extents에 대한 간략한 소개였다. 하지만 논의할 필요가 있는 더 많은 복잡성이 존재한다. 예를 들어, 파일이 너무 조각화되어 -inode에 딱 맞는- 4개 이상의 extent 구조체가 요구되는 경우이다. 


또한 256bytes로 확장된 EXT4 inode에는 몇가지 추가적인 값들이 존재한다. 이는 새로운 timestamp를 포함한다 -EXT는 현재 NTFS와 같은 파일 생성 날짜를 갖는다-. 뿐만 아니라 64bit 값을 사용하여 아주 세밀한 timestamps를 갖는다. 이 모든 것들은 이후의 포스팅에서 다룰 것이다.




  1. Wikipedia: "EXT4", http://en.wikipedia.org/wiki/Ext4 [본문으로]
  2. "The New EXT4 File System: Current Status and Future Plans", http://www.kernel.org/doc/ols/2007/ols2007v2-pages-21-34.pdf [본문으로]
  3. "Understanding Indirect Blocks in Unix File Systems", http://computer-forensics.sans.org/blog/2008/12/24/understanding-indirect-blocks-in-unix-file-systems/ [본문으로]
  4. "File System Forensic Analysis", http://www.amazon.com/System-Forensic-Analysis-Brian-Carrier/dp/0321268172/ [본문으로]