모두의 dream
Ext4 File System 본문
*공부를 위해 정리한 내용으로 틀린 부분이 있을 수 있습니다. *
미리 쓰는 느낀점: NTFS, FAT만 보고 가볍게 덤볐다간 큰 코 다칠 수 있습니다. 너무 어렵다;;
I. GPT (MBR)
디스크의 기본 구조인 GPT(MBR)에 대해 서술한다.
컴퓨터(Ext4) 부팅 절차
BIOS → POST → MBR(GPT) → GRUB(Boot Loader) → 메모리(RAM)에 커널 로딩 → 운영체제 실행 및 제어권 이동
GPT (MBR)
실습 파일을 GPT 방식으로 만들어서 GPT 를 설명한다.
GPT는 기존 MBR의 한계를 해결하기 위해 만들어졌다.
내 컴퓨터의 펌웨어가 레거시(BIOS, Basic Input/Output System)라면 MBR 파티션을 사용하고, UEFI(Unified Extensible Firmware Interface)라면 GPT 파티션을 사용한다.
파일시스템의 종류와 상관없이 MBR과 GPT는 디스크의 첫 번째 섹터에 위치하는 데이터로, 운영체제에 대한 정보가 담겨있는 영역이다. 따라서 이 영역이 손상될 경우 운영체제가 정상적으로 부팅되지 않는다.
따라서 GPT(MBR) 영역을 파괴시키거나 암호화 시키는 악성코드가 존재한다.
GPT 구조의 첫 번째 섹터는 호환성을 위해 MBR과 동일하다.
LBA(Logical Block Addressing)는 논리적인 주소로 섹터에 접근하는 방법이다. 섹터 1개를 LBA n 으로 부르게 된다.
(참고: https://velog.io/@markyang92/partition)
MBR은 GRUB Boot Loader, Partition table entry, signature로 구성되어 있다.
Partition table entry는 위 사진처럼 16bytes 씩 4개로 구성되어 있다.
Partition table은 부팅이 가능한 파티션의 정보가 있는 곳이다. (멀티 부팅을 하게 되면 총 4개의 파티션 까지 가능)
Partition table entry의 데이터 구조는 다음과 같다.
Partition table entry 에서 유심히 본 곳은 부트 식별자(Boot indicator) 와 파티션 타입, 파티션의 시작위치를 가리키는 LBA 주소값과 파티션 전체의 섹터 개수였다.
offset (bytes) | 내용 | 해석 |
0x04 (1 bytes) | Partition Type | 0xEE, GPT 파티션 |
0x08 (4 bytes) | LBA 주소값 | 0x01(리틀엔디안) → 1번 섹터(주소: 1 * 512 = 0x200) |
0x0C (4 bytes) | 섹터 개수 | 0x4FFFFFF → 83,886,079개 |
GPT Header
GPT에 대한 설정 정보를 저장하고 있으며 92bytes로 구성되어 있다.
Header 에서 유심히 본 곳은 Backup LBA, Starting LBA for partition, Ending LBA for partitions 이었다.
Backup LBA: 0x4FFFFFF → 83,886,079 섹터
위 섹터에 가보면 GPT Header 가 백업 되어있다.
offset | 내용 | 해석 |
0x20 (8 bytes) | Backup LBA | 0x4FFFFFF → 83,886,079 섹터 |
0x28 (8 bytes) | Starting LBA for partition | 0x800 → 2,048 섹터 |
0x30 (8 bytes) | Ending LBA for partitions | 0x4FFFFDE → 83,886,046 섹터 |
Starting LBA for partion, 2,048 섹터에 가보면 첫 번째 파티션을 확인할 수 있다.
정확히 뭔지는 모르겠지만 윈도우처럼 리눅스에 기본적으로 존재하는 파티션이 아닐까 예상해본다.
GPT Partition Entry
총 2개의 파티션이 확인되며 FTK Imager로 확인해보면 동일하다.
GPT Partition entry의 구조는 다음과 같다.
offset | bytes | 내용 |
0 (0x00) | 16 bytes | 파티션 타입을 표현하는 고유한 정보 |
16 (0x10) | 16 bytes | 파티션마다 할당하는 고유한 값 |
32 (0x20) | 8 bytes | 파티션 시작 주소 |
40 (0x28) | 8 bytes | 파티션 끝 주소 |
48 (0x30) | 8 bytes | 파티션 속성 (플래그) |
56 (0x38) | 72 bytes | 파티션 이름 |
아래 사진으로 자세히 분석해보겠다.
Partition Entry 2번째 파티션의 정보는 다음과 같다.
First LBA | 0x1000 → 4,096 섹터 |
Last LBA | 0x4FFE7FF → 83,879,935 섹터 |
II. Ext4 파일시스템
Extended File System, 리눅스에서 사용하기 위해 개발된 Ext 파일시스템의 4번째 후속 버전이다
III. Ext4 파일시스템 구조
Ext4 파일시스템은 블록이라는 단위로 구성되어 있으며 블록의 크기는 일반적으로 4096 bytes 이다. (1KB, 2KB, 4KB 중 선택하여 사용 가능하다.)
블록 그룹 (Block Group)
크게는 블록 그룹(Block Group), 세부적으로 여러개의 블록(Block)들이 존재한다.
한 블록의 크기는 일반적으로 1KB, 2KB, 4KB, 8KB로 설정될 수 있고, 흔히 사용되는 크기는 4KB(4096 Bytes)이다.
슈퍼블록 (Super Block): 슈퍼블록은 파일 시스템에 대한 전반적인 정보를 저장한다. 따라서 여러개의 블록 그룹에 모두 동일한 값으로 저장되어 있다.(총 블록 수, 사용 가능한 블록 수, 사용 중인 블록 수 등)
그룹 디스크립터 (Group Descriptors): 그룹 디스크립터는 각각의 블록 그룹에 대한 정보를 가지고 있다.
GDT 예약 블록 (Reserved GDT Block): 파일시스템 확장을 위해 예약되어 있는 영역.
블록 비트맵 (Block Bitmap): 비트맵은 해당 블록 그룹 내에서 사용 가능한(할당 된) 데이터 블럭을 추적.
아이노드 비트맵 (Inode Bitmap): 아이노드 비트맵은 해당 그룹 내에서 사용 가능한(할당 된) 아이노드를 추적.
아이노드 테이블 (Inode Table): 아이노드 테이블은 개별 파일/디렉터리에 대한 메타데이터(소유자 정보, 접근 권한 등)와 데이터가 저장된 실제 위치 정보 등을 포함하는 아이노드들을 저장하고 있다.
데이터 블럭 (Data Blocks): 실제 파일 데이터가 저장되는 곳이다.
Block Group 0
파일시스템에 존재하는 Block Group에 대한 정보들이 저장되어 있다.
정보들은 0번 Block Group 의 Super block 과 Group descriptors에 저장되며 각 그룹들은 이 데이터만 사용하지만 손상될 경우를 대비하여 각 그룹에 사본 또한 저장되어 있다.
Block Group 0의 첫 1024 bytes(Group 0 padding)는 여러 이유로 사용되지 않는다.
슈퍼블록 (Super Block)
Super block의 크기는 1,024 Bytes이며 파일 시스템에 대한 전반적인 정보를 저장하고 있다.
Super block 의 Magic Number(시그니처) 값은 Super block 시작 지점에서 0x38 앞으로 가면 있는 "0xEF53" 이다.
Super block 의 중요한 몇가지 필드를 확인해보자.
offset | 내용 | 해석 |
0x00 ~ 0x03 | s_inodes_count (총 inode 개수) |
0x280000 → 2,621,440 |
0x04 ~ 0x07 | s_blocks_count_lo (총 Block 개수) |
0x009FFD00 → 10,484,992 |
0x0C ~ 0x0F | s_free_blocks_count_lo (사용 가능한 Block 개수) |
0x073C553 → 7,587,155 |
0x10 ~ 0x13 | s_free_inodes_count (사용 가능한 inode 개수) |
0x24D826 → 2,414,630 |
0x14 ~ 0x17 | s_first_data_block (첫 번째 Data Block) |
0x00000000 → 0 |
0x18 ~ 0x1B | s_log_block_size (기본 블록 크기) |
계산방법: ( 2 ^ (10 + s_log_block_size)) 2 → ( 2 ^ (10 + 2)) → 4096 Bytes |
0x20 ~ 0x23 | s_blocks_per_group (그룹 별 Blocks) |
0x8000 → 32,768 |
0x28 ~ 0x2B | s_inodes_per_group (그룹 별 Inodes) |
0x2000 → 8,192 |
0x38 ~ 0x39 | s_magic (Magic Nuber (Signature)) |
0xEF53 |
0x58 ~ 0x59 | s_inode_size (각 inode의 크기) |
0x100 → 256 bytes |
0x60 ~ 0x63 | s_feature_incompat | 0x2C2 → 0010 1100 0010 설정되어 있는 값: INCOMPAT_FILETYPE, INCOMPAT_EXTENTS, INCOMPAT_64BIT, INCOMPAT_FLEX_BG |
0x68 ~ 0x77 | s_uuid[16] (128 bits 볼륨 UUID) |
F3 04 36 D8 B3 E6 47 09 AD F6 BC 40 3A 9D 4C C8 |
0xD0 ~ 0xDF | s_journal_uuid[16] (저널 superblock UUID) |
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
0x108 ~0x10B | s_mkfs_time (파일시스템 생성시간) |
0x65BC8551 → 1,706,853,713 |
0x160 ~ 0x163 | s_flags (Flags) |
0x00000001 → 1 |
0x170 ~ 0x173 | s_raid_stripe_width (RAID 현재 디스크 논리 번호, RAID stripe width ) |
0x00000000 → 0 |
0x274 ~ 0x3FB | s_reserved[98] (padding to the end of the block) |
- |
0x3FC ~ 0x3FF | s_checksum (superblock checksum) |
33 5A BD E8 |
(1) 32비트/64비트 확인하기
현재 Ext4가 32비트, 64비트 중 어떤 것으로 운영되는지 확인해보려면 s_feature_incompat 필드를 확인해보면 된다.
s_feature_incompat 필드의 INCOMPAT_64BIT 플래그(값: 0x80, 7번째 비트)값이 1로 설정되어 있으면 64비트 모드, 설정되어 있지 않으면 32비트 모드로 운영됨을 뜻한다.
s_feature_incompat 필드의 플래그 값들은 다음과 같다.
0x1 | Compression. Not implemented. (INCOMPAT_COMPRESSION). |
0x2 | Directory entries record the file type. See ext4_dir_entry_2 below. (INCOMPAT_FILETYPE). |
0x4 | Filesystem needs journal recovery. (INCOMPAT_RECOVER). |
0x8 | Filesystem has a separate journal device. (INCOMPAT_JOURNAL_DEV). |
0x10 | Meta block groups. See the earlier discussion of this feature. (INCOMPAT_META_BG). |
0x40 | Files in this filesystem use extents. (INCOMPAT_EXTENTS). |
0x80 | Enable a filesystem size over 2^32 blocks. (INCOMPAT_64BIT). Multiple mount protection. Prevent multiple hosts from mounting the filesystem concurrently by updating a reserved block |
0x100 | periodically while mounted and checking this at mount time to determine if the filesystem is in use on another host. (INCOMPAT_MMP). |
0x200 | Flexible block groups. See the earlier discussion of this feature. (INCOMPAT_FLEX_BG). |
0x400 | Inodes can be used to store large extended attribute values (INCOMPAT_EA_INODE). |
0x1000 | Data in directory entry. Allow additional data fields to be stored in each dirent, after struct ext4_dirent. The presence of extra data is indicated by flags in the high bits of ext4_dirent file type flags (above EXT4_FT_MAX). The flag EXT4_DIRENT_LUFID = 0x10 is used to store a 128-bit File Identifier for Lustre. The flag EXT4_DIRENT_IO64 = 0x20 is used to store the high word of 64-bit inode numbers. Feature still in development. (INCOMPAT_DIRDATA). |
0x2000 | Metadata checksum seed is stored in the superblock. This feature enables the administrator to change the UUID of a metadata_csum filesystem while the filesystem is mounted; without it, the checksum definition requires all metadata blocks to be rewritten. (INCOMPAT_CSUM_SEED). |
0x4000 | Large directory >2GB or 3-level htree. Prior to this feature, directories could not be larger than 4GiB and could not have an htree more than 2 levels deep. If this feature is enabled, directories can be larger than 4GiB and have a maximum htree depth of 3. (INCOMPAT_LARGEDIR). |
0x8000 | Data in inode. Small files or directories are stored directly in the inode i_blocks and/or xattr space. (INCOMPAT_INLINE_DATA). |
0x10000 | Encrypted inodes are present on the filesystem (INCOMPAT_ENCRYPT). |
리틀엔디안으로 값을 가져온 후
각 자리에 맞게 해석해주면 된다. (INCOMPAT_64BIT 는 7번째 비트를 해석하면 된다.)
offset | 내용 | 해석 |
0x60 ~ 0x63 | s_feature_incompat | 0x2C2 → '0010 1100 0010' sparse_super: 1 |
현재 실습 파일의 INCOMPAT_64BIT 값은 1 이므로 64비트 모드로 운영되고 있음을 확인할 수 있다.
(2) Super block 백업본이 저장되는 블록 확인하기
sparse_super 이라는 값이 활성화되면 Super block 백업본이 블록 그룹 0과 1 그리고 3, 5, 7의 거듭제곱 그룹에 저장된다.
활성화 되어있지 않는다면 모든 블록 그룹에 슈퍼블록 백업본이 저장된다.
sparse_super 값은 s_feature_ro_compat 필드에 있으며 0x64 ~ 0x67 까지 값을 가지고 있다.
값을 해석하는 방법은 다음과 같다.
1. 리틀 엔디안으로 값을 가져온 후 2진수로 변환한다.
2. 변환된 2진수의 각 비트별 자릿수는 아래의 값들을 가지고 있다.
0x1 | Sparse superblocks. See the earlier discussion of this feature. (RO_COMPAT_SPARSE_SUPER). |
0x2 | Allow storing files larger than 2GiB (RO_COMPAT_LARGE_FILE). |
0x4 | Was intended for use with htree directories, but was not needed. Not used in kernel or e2fsprogs (RO_COMPAT_BTREE_DIR). |
0x8 | This filesystem has files whose space usage is stored in i_blocks in units of filesystem blocks, not 512-byte sectors. Inodes using this feature will be marked with EXT4_INODE_HUGE_FILE. (RO_COMPAT_HUGE_FILE) |
0x10 | Group descriptors have checksums. In addition to detecting corruption, this is useful for lazy formatting with uninitialized groups (RO_COMPAT_GDT_CSUM). |
0x20 | Indicates that the old ext3 32,000 subdirectory limit no longer applies. A directory's i_links_count will be set to 1 if it is incremented past 64,999. (RO_COMPAT_DIR_NLINK). |
0x40 | Indicates that large inodes exist on this filesystem, storing extra fields after EXT2_GOOD_OLD_INODE_SIZE. (RO_COMPAT_EXTRA_ISIZE). |
0x80 | This filesystem has a snapshot. Not implemented in ext4. (RO_COMPAT_HAS_SNAPSHOT). |
0x100 | Quota is handled transactionally with the journal (RO_COMPAT_QUOTA). |
0x200 | This filesystem supports "bigalloc", which means that filesystem block allocation bitmaps are tracked in units of clusters (of blocks) instead of blocks (RO_COMPAT_BIGALLOC). |
0x400 | This filesystem supports metadata checksumming. (RO_COMPAT_METADATA_CSUM; implies RO_COMPAT_GDT_CSUM, though GDT_CSUM must not be set) |
0x800 | Filesystem supports replicas. This feature is neither in the kernel nor e2fsprogs. (RO_COMPAT_REPLICA). |
0x1000 | Read-only filesystem image; the kernel will not mount this image read-write and most tools will refuse to write to the image. (RO_COMPAT_READONLY). |
0x2000 | Filesystem tracks project quotas. (RO_COMPAT_PROJECT) |
3. 각 자리에 맞는 값을 해석해주면 되고, sparse_super 값은 첫 번째 플래그인 RO_COMPAT_SPARSE_SUPER(값: 0x1, 0번째 비트)의 값을 확인해주면 된다.
offset | 내용 | 해석 |
0x64 ~ 0x67 | s_feature_ro_compat | 0x46B → ''0100 0110 1011" sparse_super: 1 |
특정 블록 그룹에만 백업이 저장되는 경우: sparse_super 값이 "1"
모든 블록 그룹에 백업이 저장되는 경우: sparse_super 값이 "0"
현재 실습 파일의 sparse_super 값은 1 이므로 특정 블록 그룹(0과 1 그리고 3, 5, 7의 거듭제곱 그룹)에 백업이 저장되고 있다는 사실을 알 수 있다. 이 사실을 증명하기 위해 Block Group의 주소를 계산해봤다.
현재 블록의 크기(s_log_block_size)는 4096 bytes, 하나의 블록 그룹이 가지고 있는 블록의 개수(s_blocks_per_group)는 32,768개이다.
Block Group 1의 시작 주소를 구하기 위해 Block Group 0의 시작 주소 0x200000에 4,096 * 32,768의 결과값 0x8000000를 더해주면 Block Group 1의 시작주소로 이동할 수 있다.
Block Group | Offset |
0 | 0x200000 |
1 | 0x8200000 |
2 | 0x10200000 |
3 | 0x18200000 |
4 | 0x20200000 |
5 | 0x28200000 |
6 | 0x30200000 |
7 | 0x38200000 |
8 | 0x40200000 |
9 | 0x48200000 |
· · · |
· · · |
Super Block이 0과 1 그리고 3, 5, 7의 거듭제곱 그룹에만 있는지 직접 확인해봤다.
확인해본 결과 0과 1 그리고 3, 5, 7의 거듭제곱 그룹에서 Super Block의 Magic Number "0xEF53"을 확인할 수 있었다.
Super block 시작점에서 한 블록의 크기 4096 bytes 만큼 이동하면 Group Descriptors 로 이동할 수 있다.
다만 Block Group 0의 경우 첫 1024 bytes가 NULL 값으로 채워져 있었으므로 3072 bytes 만큼 이동하면 Group Descriptors 로 이동할 수 있다. (혹은 NuLL 값의 시작점부터 (0x200000) 4096 bytes 만큼 이동해도 된다.)
그룹 디스크립터 테이블 (Group Descriptors Table)
그룹 디스크립터는 블록 비트맵 주소, 아이노트 비트맵 주소와 아이노드 테이블 주소 등과 같은 각 블록 그룹의 주요 정보 위치를 기록하고 있다. 32 bits일 경우 블록 디스크립터는 32 bytes의 길이, 64 bits일 경우 64 bytes의 길이를 갖게 된다.
Group descriptor의 구조는 다음과 같다.
나머지 필드의 값들은 이후 과정에 크게 영향이 없어보여서 별도로 표시하지 않았으며, 추후 필요해질 경우 추가할 예정이다. (직접 확인: Ext4 Disk Layout - Block Descriptor)
현재 실습파일은 64비트 모드이므로 블록 디스크립터의 길이는 64 bytes이다.
그룹 당 블록의 개수는 32,768개로 super block의 s_blocks_per_group 필드의 값을 통해 알 수 있다.
따라서 현재 Group Descriptors 개수 또한 32,768개이고 전체 크기는 32,768 * 64의 결과인 0x200000 이다.
블록 비트맵 (Block Bitmap)
Block Group 내의 데이터 Block 들의 사용량을 비트 단위로 기록한다.
Block Bitmap의 크기는 한 블록으로 4096 bytes이다.
현재 한 Block 의 크기는 4096 bytes, Group Descriptor에서 확인한 Block bitmap offset은 0x406 부터 1씩 증가하고 있다.
Super Block(혹은 Block Group의 시작지점) 에서 부터 0x406 블록 만큼 떨어져 있다는 뜻으로 주소로 계산해보면 다음과 같다.
Super Block 시작주소 (혹은 Block Group의 시작지점) : 0x200000
Descriptor 0의 Block Bitmap 주소: 1030(0x406) * 4096 = 0x406000
Descriptor 1의 Block Bitmap 주소: 1030(0x407) * 4096 = 0x407000
이동해보면 Block Bitmap을 확인할 수 있다.
각 Descriptor의 Block Bitmap은 정확히 1 Block (4096 bytes) 만큼 차이난다.
아이노드 비트맵 (inode Bitmap)
inode Table에서 사용중인 항목을 비트 단위로 기록한다.
현재 한 Block 의 크기는 4096 bytes, Group Descriptor에서 확인한 inode bitmap offset은 0x416 부터 1씩 증가하고 있다.
Super Block (혹은 Block Group의 시작지점) 에서 부터 0x416 블록 만큼 떨어져 있다는 뜻으로 주소로 계산해보면 다음과 같다.
Super Block 시작주소 (혹은 Block Group의 시작지점) : 0x200000
Descriptor 0의 inode Bitmap 주소: 1046(0x416) * 4096 = 0x416000
Descriptor 1의 inode Bitmap 주소: 1047(0x417) * 4096 = 0x417000
이동해보면 inode Bitmap을 확인할 수 있다.
각 Descriptor의 inode Bitmap은 정확히 1 Block (4096 bytes) 만큼 차이난다.
아이노드 테이블 (inode Table)
개별 파일/디렉터리에 대한 메타데이터(소유자 정보, 접근 권한 등)와 데이터가 저장된 실제 위치 정보 등을 포함하는 아이노드들을 저장하고 있다.
블록 그룹에 있는 inode의 수는 8,192개이며, 각 inode의 크기는 256 bytes이다.
현재 한 Block 의 크기는 4096 bytes, Group Descriptor에서 확인한 inode Table offset은 0x426 부터 시작한다.
Super Block (혹은 Block Group의 시작지점) 에서 부터 0x426 블록 만큼 떨어져 있다는 뜻으로 주소로 계산해보면 다음과 같다.
Super Block 시작주소 (혹은 Block Group의 시작지점) : 0x200000
Descriptor 0의 inode Table 주소: 1062(0x426) * 4096 = 0x426000
Descriptor 1의 inode Table 주소: 1574(0x626) * 4096 = 0x626000
이동해보면 inode Table을 확인할 수 있다.
(1) inode 개념
inode는 특정 파일이나 디렉토리를 가리키는 고유한 번호이다.
소유자 UID, 파일 크기, 액세스 시간, 수정 시간, 삭제 시간 등의 메타데이터가 포함되어 있다.
inode의 크기는 기본적으로 256 bytes로 실습파일의 inode 크기는 Super block을 통해 256bytes로 확인할 수 있다.
inode table에 inode는 1번부터 시작되며 오름차순으로 나열되어 있다.
(각 그룹마다 inode table이 있지만 inode 번호는 초기화되지 않고 쭉 이어진다.)
또한 특별한 기능을 위해 예약되어 있는 inode 값이 있다. (Special inodes)
만약 삭제된 특정 파일을 복구하고자 한다면 2번 root directory, 8번 journal inode를 먼저 확인해보면 된다.
inode | Description |
0 | Doesn't exist; there is no inode 0. (0번은 존재하지 않음.) |
1 | List of defective blocks. |
2 | Root Directory |
3 | User quota |
4 | Group quota |
5 | Boot loader |
6 | Undelete directory |
7 | Reserved group descriptor indoe |
8 | journal inode |
9 | The exclude inode |
10 | Replica inode |
11 | Traditional first non-reserved inode. Usually used for lost+found directory |
(2) inode 구조
inode의 구조는 다음과 같다.
offset | 이름 | 내용 |
0x00 ~ 0x01 | i_mode |
File mode. Any of: 0x1 S_IXOTH (Others may execute) 0x2 S_IWOTH (Others may write) 0x4 S_IROTH (Others may read) 0x8 S_IXGRP (Group members may execute) 0x10 S_IWGRP (Group members may write) 0x20 S_IRGRP (Group members may read) 0x40 S_IXUSR (Owner may execute) 0x80 S_IWUSR (Owner may write) 0x100 S_IRUSR (Owner may read) 0x200 S_ISVTX (Sticky bit) 0x400 S_ISGID (Set GID) 0x800 S_ISUID (Set UID) These are mutually-exclusive file types: 0x1000 S_IFIFO (FIFO) 0x2000 S_IFCHR (Character device) 0x4000 S_IFDIR (Directory) 0x6000 S_IFBLK (Block device) 0x8000 S_IFREG (Regular file) 0xA000 S_IFLNK (Symbolic link) 0xC000 S_IFSOCK (Socket) |
0x02 ~ 0x03 | i_uid | Lower 16-bits of Owner UID. |
0x04 ~ 0x07 | i_size_lo (Size in bytes) |
Lower 32-bits of size in bytes. |
0x08 ~ 0x0B | i_atime (Access time) |
Last access time, in seconds since the epoch. However, if the EA_INODE inode flag is set, this inode stores an extended attribute value and this field contains the checksum of the value. |
0x0C ~ 0x0F | i_ctime (Inode Change time) |
Last inode change time, in seconds since the epoch. However, if the EA_INODE inode flag is set, this inode stores an extended attribute value and this field contains the lower 32 bits of the attribute value's reference count. |
0x10 ~ 0x13 | i_mtime (Modification time) |
Last data modification time, in seconds since the epoch. However, if the EA_INODE inode flag is set, this inode stores an extended attribute value and this field contains the number of the inode that owns the extended attribute. |
0x14 ~ 0x17 | i_dtime (Deletion Time) |
Deletion Time, in seconds since the epoch. |
0x18 ~ 0x19 | i_gid (Low 16 bits of Group Id) |
Lower 16-bits of GID. |
0x1A ~ 0x1B | i_links_count (Links count) |
Hard link count. Normally, ext4 does not permit an inode to have more than 65,000 hard links. This applies to files as well as directories, which means that there cannot be more than 64,998 subdirectories in a directory (each subdirectory's '..' entry counts as a hard link, as does the '.' entry in the directory itself). With the DIR_NLINK feature enabled, ext4 supports more than 64,998 subdirectories by setting this field to 1 to indicate that the number of hard links is not known. |
0x1C ~ 0x1F | i_blocks_lo (Blocks count) |
Lower 32-bits of "block" count. If the huge_file feature flag is not set on the filesystem, the file consumes i_blocks_lo 512-byte blocks on disk. If huge_file is set and EXT4_HUGE_FILE_FL is NOT set in inode.i_flags, then the file consumes i_blocks_lo + (i_blocks_hi << 32) 512-byte blocks on disk. If huge_file is set and EXT4_HUGE_FILE_FL IS set in inode.i_flags, then this file consumes (i_blocks_lo + i_blocks_hi << 32) filesystem blocks on disk. |
0x20 ~ 0x23 | i_flags (File flags) |
Inode flags. Any of: 0x1 This file requires secure deletion (EXT4_SECRM_FL). (not implemented) 0x2 This file should be preserved, should undeletion be desired (EXT4_UNRM_FL). (not implemented) 0x4 File is compressed (EXT4_COMPR_FL). (not really implemented) 0x8 All writes to the file must be synchronous (EXT4_SYNC_FL). 0x10 File is immutable (EXT4_IMMUTABLE_FL). 0x20 File can only be appended (EXT4_APPEND_FL). 0x40 The dump(1) utility should not dump this file (EXT4_NODUMP_FL). 0x80 Do not update access time (EXT4_NOATIME_FL). 0x100 Dirty compressed file (EXT4_DIRTY_FL). (not used) 0x200 File has one or more compressed clusters (EXT4_COMPRBLK_FL). (not used) 0x400 Do not compress file (EXT4_NOCOMPR_FL). (not used) 0x800 Encrypted inode (EXT4_ENCRYPT_FL). This bit value previously was EXT4_ECOMPR_FL (compression error), which was never used. 0x1000 Directory has hashed indexes (EXT4_INDEX_FL). 0x2000 AFS magic directory (EXT4_IMAGIC_FL). 0x4000 File data must always be written through the journal (EXT4_JOURNAL_DATA_FL). 0x8000 File tail should not be merged (EXT4_NOTAIL_FL). (not used by ext4) 0x10000 All directory entry data should be written synchronously (see dirsync) (EXT4_DIRSYNC_FL). 0x20000 Top of directory hierarchy (EXT4_TOPDIR_FL). 0x40000 This is a huge file (EXT4_HUGE_FILE_FL). 0x80000 Inode uses extents (EXT4_EXTENTS_FL). 0x200000 Inode stores a large extended attribute value in its data blocks (EXT4_EA_INODE_FL). 0x400000 This file has blocks allocated past EOF (EXT4_EOFBLOCKS_FL). (deprecated) 0x01000000 Inode is a snapshot (EXT4_SNAPFILE_FL). (not in mainline) 0x04000000 Snapshot is being deleted (EXT4_SNAPFILE_DELETED_FL). (not in mainline) 0x08000000 Snapshot shrink has completed (EXT4_SNAPFILE_SHRUNK_FL). (not in mainline) 0x10000000 Inode has inline data (EXT4_INLINE_DATA_FL). 0x20000000 Create children with the same project ID (EXT4_PROJINHERIT_FL). 0x80000000 Reserved for ext4 library (EXT4_RESERVED_FL). Aggregate flags: 0x4BDFFF User-visible flags. 0x4B80FF User-modifiable flags. Note that while EXT4_JOURNAL_DATA_FL and EXT4_EXTENTS_FL can be set with setattr, they are not in the kernel's EXT4_FL_USER_MODIFIABLE mask, since it needs to handle the setting of these flags in a special manner and they are masked out of the set of flags that are saved directly to i_flags |
0x24 ~ 0x27 | OS dependent 1 | Union osd1 Tag: linbux1, hurd1, masix1 |
0x28 ~ 0x63 (60bytes) |
i_block[EXT4_N_BLOCKS=15] (Pointers to blocks) |
Block map or extent tree. See the section "The Contents of inode.i_block". |
0x64 ~ 0x67 | i_generation (File version (for NFS)) |
File version (for NFS). |
0x68 ~ 0x6B | i_file_acl_lo (File ACL) |
Lower 32-bits of extended attribute block. ACLs are of course one of many possible extended attributes; I think the name of this field is a result of the first use of extended attributes being for ACLs. |
0x6C ~ 0x6F | i_size_high / i_dir_acl | Upper 32-bits of file/directory size. In ext2/3 this field was named i_dir_acl, though it was usually set to zero and never used. |
0x70 ~ 0x73 | i_obso_faddr (Obsoleted fragment address) |
(Obsolete) fragment address. |
0x74 ~ 0x7F | OS dependent 2 | Union osd2: Tag: linux2, hurd2, masix2 |
0x80 ~ 0x81 | i_extra_isize | Size of this inode - 128. Alternately, the size of the extended inode fields beyond the original ext2 inode, including this field. |
0x82 ~ 0x83 | i_checksum_hi (crc32c(uuid+inum+inode) BE) |
Upper 16-bits of the inode checksum. |
0x84 ~ 0x87 | i_ctime_extra ( extra Change time (nsec << 2 | epoch)) |
Extra change time bits. This provides sub-second precision. See Inode Timestamps section. |
0x88 ~ 0x8B | i_mtime_extra (extra Modification time(nsec << 2 | epoch)) |
Extra modification time bits. This provides sub-second precision. |
0x8C ~ 0x8F | i_atime_extra (extra Access time (nsec << 2 | epoch)) |
Extra access time bits. This provides sub-second precision. |
0x90 ~ 0x93 | i_crtime ( File Creation time) |
File creation time, in seconds since the epoch. |
0x94 ~ 0x97 | i_crtime_extra (extra FileCreationtime (nsec << 2 | epoch)) |
Extra file creation time bits. This provides sub-second precision. |
0x98 ~ 0x9B | i_version_hi | Upper 32-bits for version number. |
0x9C ~ 0x9F | i_projid | Project ID. |
Union osd1, Union osd2 의 자세한 값들은 문서를 확인해 보면 된다.
(3) inode의 i_block 필드
0x28 번째 부터 0x63까지 존재하는 i_block 필드는 60 bytes의 길이를 갖고 있으며 inode가 기술하는 파일의 종류에 따라 다양하게 사용될 수 있다.
일반적으로 파일(혹은 디렉토리) 데이터 블록의 주소를 가리킬때 사용하고, 특수 파일은 특수한 목적에 사용한다.
Symbolic Links
"The target of a symbolic link will be stored in this field if the target string is less than 60 bytes long. Otherwise, either extents or block maps will be used to allocate data blocks to store the link target." 라는 문장이 있는데 정확히는 모르겠지만 서술해보면 다음과 같다.
i_block이 가리키는 파일이 심볼릭 링크 파일일때 상황을 설명하는 것 같다.
대상 경로 문자열의 길이가 60 bytes 미만일 경우 경로 문자열 자체를 i_block 필드에 저장한다.
대상 경로 문자열의 길이가 60 bytes 이상일 경우에는 별도의 블록을 할당한 후 그 블록에 경로를 저장한다. 이때 사용되는게 ext4의 extents 구조나 block map 구조이다. i_block 필드는 할당한 별도의 블록을 가리키게 된다.
Direct(직접)/Indirect(간접) Block Addressing
ext2/3에서 사용된 방식으로 직접 / 간접블록 방식으로 파일에 접근한다.
총 15개의 엔트리가 존재하며, 12개의 직접블록, 3개의 간접블록이 있다.
12개의 직접 블록은 파일의 실제 데이터가 저장된 블록을 직접 가리키고 있다.
3개의 간접블록은 각각 Single(단일) Indirect Block, Double(이중) Indirect Block, Triple(삼중) Indirect Block으로 직접블록 만으로는 가리킬 수 없는 크기를 갖고 있는 파일을 가리킬 때 사용된다.
단점으로는 연속된 파일 (큰 파일)을 관리할 때 비효율적이다.
예시) 1000개의 연속된 블록을 가리키기 위한 간접 블록이 필요하다.
Extent Tree
ext4에서 Direct(직접)/Indirect(간접) Block Addressing 의 단점을 개선하기 위해 나온 파일 접근 방식.
연속된 블록을 가리킬 때 필요한 자원이 감소한다.
Extent Tree의 구조는 다음과 같다.
Extent Tree 구조
12 bytes의 Header와 최대 4개의 Extent 엔트리(각 12 bytes, 총 48 bytes) 로 구성되어 있다.
Extent Tree의 Root Node는 inode의 i_block에 저장되며, 이를 통해 추가 메타데이터 블록을 사용하지 않고 4개의 Extent를 기록할 수 있다. (i_block 필드에 있는 extent 와 extent block 은 다르다. extent block이 i_block 필드로 부터 참조가 되는건 맞다.)
5개 이상의 extent 가 필요한 대용량 파일은 HTree 방식의 extent tree가 사용된다고 한다.
참고 링크: POSIX 알아보기 #1
구조는 다음과 같은데 지금 당장 이해하기엔 어려워 보이므로 파일 복구과정 포스팅, 혹은 별도의 포스팅에서 다뤄보려고 한다.
Header는 고정이며 상황에 따라 Internal nodes, Leaf nodes 가 사용된다.
Header의 eh_depth 값이 1 이상이라면 Internal nodes, 0이라면 Leaf nodes이다.
Header
총 12 bytes로 구성되어 있다.
offset | 이름 | 내용 |
0x00 ~ 0x01 | eh_magic | Magic number, 0xF30A |
0x02 ~ 0x03 | eh_entries | Number of valid entries following the header. |
0x04 ~ 0x05 | eh_max | Maximum number of entries that could follow the header. |
0x06 ~0x07 | eh_depth | Depth of this extent node in the extent tree. 0 = this extent node points to data blocks; otherwise, this extent node points to other extent nodes. The extent tree can be at most 5 levels deep: a logical block number can be at most 2^32, and the smallest n that satisfies 4*(((blocksize - 12)/12)^n) >= 2^32 is 5. |
0x08 ~ 0x0B | eh_generation | Generation of the tree. (Used by Lustre, but not standard ext4). |
Internal nodes (Index nodes)
총 12 bytes로 구성되어 있다.
offset | 이름 | 내용 |
0x00 ~ 0x03 | ei_block | This index node covers file blocks from 'block' onward. |
0x04 ~ 0x07 | ei_leaf_lo | Lower 32-bits of the block number of the extent node that is the next level lower in the tree. The tree node pointed to can be either another internal node or a leaf node, described below. |
0x08 ~ 0x09 | ei_leaf_hi | Upper 16-bits of the previous field. |
0x0A ~ 0x0B | ei_unused |
Leaf nodes
총 12 bytes로 구성되어 있다.
offset | 이름 | 내용 |
0x00 ~ 0x03 | ee_block | First file block number that this extent covers. |
0x04 ~ 0x05 | ee_len | Number of blocks covered by extent. If the value of this field is <= 32768, the extent is initialized. If the value of the field is > 32768, the extent is uninitialized and the actual extent length is ee_len - 32768. Therefore, the maximum length of a initialized extent is 32768 blocks, and the maximum length of an uninitialized extent is 32767. |
0x06 ~ 0x07 | ee_start_hi | Upper 16-bits of the block number to which this extent points. (상위 16bit) |
0x08 ~ 0x0B | ee_start_lo | Lower 32-bits of the block number to which this extent points. (하위 32 bit) |
ext4_extent_tail
Extent Tree 블록의 무결성을 검증하기 위해 사용되는 데이터 구조로 CRC32C 체크섬을 사용하여 데이터를 보호하며, 총 4 bytes의 값을 갖는다. Extent Bock에만 존재하고 inode에 있는 4개의 Extent에는 이미 inode 자체로 체크섬 처리가 되어 있기 때문에 존재하지 않는다.
offset | 이름 | 내용 |
0x00 ~ 0x03 | eb_checksum | Checksum of the extent block, crc32c(uuid+inum+igeneration+extentblock) |
각 접근 방식의 자세한 설명과 비교하는 과정은 쉽지 않아보여서 여유가 생기면 진행해보려고 한다.
(사실 직접 블록의 12개의 의미도 정확히 파악하지 못했기 때문에 작성할 자신이 없다.)
https://roklcw.tistory.com/100
Block Mapping & Extent Tree (Ext Filesytem)
모두의 dream Block Mapping & Extent Tree (Ext Filesytem) 본문 분야/Digital Forensics Block Mapping & Extent Tree (Ext Filesytem) 오리꽥이로 2024. 5. 31. 15:03
roklcw.tistory.com
저널 (Journal)
https://roklcw.tistory.com/111
Ext4 Journal
모두의 dream Ext4 Journal 본문 카테고리 없음 Ext4 Journal 오리꽥이로 2024. 10. 7. 20:26
roklcw.tistory.com
IV. Ext4 파일 접근 & 삭제된 파일 복구
실습을 위해 /home/user/Downloads 폴더에 Flag_of_South_Korea.svg.png, baseball.jpg 라는 파일을 다운로드 받아놨다.
다음 포스팅에서 이 파일에 접근하는 과정에 대해 서술한다.
Ext4 파일 데이터 접근 (with Directory Entry)
모두의 dream Ext4 파일 데이터 접근 (with Directory Entry) 본문 분야/Digital Forensics Ext4 파일 데이터 접근 (with Directory Entry) 오리꽥이로 2023. 9. 15. 10:05
roklcw.tistory.com
삭제된 파일을 복구하는 과정은 다음 포스팅에서 서술한다.
https://roklcw.tistory.com/108
Ext4 삭제된 파일 복구
모두의 dream Ext4 삭제된 파일 복구 본문 분야/Digital Forensics Ext4 삭제된 파일 복구 오리꽥이로 2024. 9. 30. 11:15
roklcw.tistory.com
Reference
https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout
https://www.kernel.org/doc/html/latest/filesystems/ext4/
Ext4 기반 오픈 플랫폼 시스템의 디지털 포렌식 연구 (Digital Forensic Techniques for Ext4 based Open Platform Systems)
https://maj3sty.tistory.com/962
'분야 > Digital Forensics' 카테고리의 다른 글
FAT32 File System (1) | 2024.03.04 |
---|---|
Ext4 파일 데이터 접근 (with Directory Entry) (1) | 2023.09.15 |
윈도우 아티팩트 정리 (1) | 2023.09.07 |
NTFS 삭제된 파일 복원 (1) | 2023.08.29 |
파일시스템 분석 실습 준비 (vmdk & 이미징) (0) | 2023.08.28 |