모두의 dream
Ext4 파일 데이터 접근 (with Directory Entry) 본문
I. inode 분석
inode에 대한 자세한 내용은 아래 링크에서 확인할 수 있다.
Ext4 File System
*공부를 위해 정리한 내용으로 틀린 부분이 있을 수 있습니다. *I. Ext4 파일시스템Extended File System, 리눅스에서 사용하기 위해 개발된 Ext 파일시스템의 4번째 후속 버전이다II. Ext4 파일시스템 구조
roklcw.tistory.com
실습을 위해 /home/user/Downloads 디렉토리에 Flag_of_South_Korea.svg.png, baseball.jpg 라는 파일을 다운로드 받아놨다.
root 디렉토리의 경우 2번 inode를 고정값으로 갖고 있다.
root directory inode
필드들을 해석해보면 다음과 같다.
offset | 이름 | 해석 |
0x00 ~ 0x01 | i_mode |
파일의 권한과 소유자를 나타냄. 구조: type(4bit) + setuid/setgid/sticky bit + user 권한 (3bit) + group 권한 (3bit) + other 권한 (3bit) 0x41ED → 0100 000 111 101 101 0100 (0x4000) : S_IFDIR (Directory) 000: NULL 111 101 101: rwxr-xr-x 결과: 디렉토리, drwxr-xr-x |
0x02 ~ 0x03 | i_uid | 0 |
0x04 ~ 0x07 | i_size_lo (Size in bytes) |
0x1000 → 4096 bytes |
0x08 ~ 0x0B | i_atime (Access time) |
0x66338E41 → 2024-05-02 21:59:45 (UTC+9) |
0x0C ~ 0x0F | i_ctime (Inode Change time) |
0x65BC87AF → 2024-02-02 15:11:59 (UTC+9) |
0x10 ~ 0x13 | i_mtime (Modification time) |
0x65BC87AF → 2024-02-02 15:11:59 (UTC+9) |
0x14 ~ 0x17 | i_dtime (Deletion Time) |
0x00000000 → NULL |
0x18 ~ 0x19 | i_gid (Low 16 bits of Group Id) |
0x0000 → NULL |
0x1A ~ 0x1B | i_links_count (Links count) |
0x14 → 20 |
0x1C ~ 0x1F | i_blocks_lo (Blocks count) |
0x08 → 8 |
0x20 ~ 0x23 | i_flags (File flags) |
0x80000 → 1000 0000 0000 0000 0000 0x80000: Inode uses extents (EXT4_EXTENTS_FL). |
0x24 ~ 0x27 | OS dependent 1 | 0x18 → 24 |
0x28 ~ 0x63 (60bytes) |
i_block[EXT4_N_BLOCKS=15] (Pointers to blocks) |
아래 참조 |
0x64 ~ 0x67 | i_generation (File version (for NFS)) |
0 |
0x68 ~ 0x6B | i_file_acl_lo (File ACL) |
0 |
0x6C ~ 0x6F | i_size_high / i_dir_acl | 0 |
0x70 ~ 0x73 | i_obso_faddr (Obsoleted fragment address) |
0 |
0x74 ~ 0x7F | OS dependent 2 | 0xE8BA0000000000000000 |
0x80 ~ 0x81 | i_extra_isize | 0x20 → 32 |
0x82 ~ 0x83 | i_checksum_hi (crc32c(uuid+inum+inode) BE) |
0x6628 → 26152 |
0x84 ~ 0x87 | i_ctime_extra ( extra Change time (nsec << 2 | epoch)) |
0x79D0475C → 2034-10-06 05:28:12 (UTC+9) |
0x88 ~ 0x8B | i_mtime_extra (extra Modification time(nsec << 2 | epoch)) |
0x79D0475C → 2034-10-06 05:28:12 (UTC+9) |
0x8C ~ 0x8F | i_atime_extra (extra Access time (nsec << 2 | epoch)) |
0xA8050A34 →1923-03-25 07:01:24 (UTC+9) |
0x90 ~ 0x93 | i_crtime ( File Creation time) |
0x65BC8551 → 2024-02-02 15:01:53 (UTC+9) |
0x94 ~ 0x97 | i_crtime_extra (extra FileCreationtime (nsec << 2 | epoch)) |
0x00000000 → NULL |
0x98 ~ 0x9B | i_version_hi | 0 |
0x9C ~ 0x9F | i_projid | 0 |
파일에 접근하기 위해 필요한 i_block 정보는 다음과 같다.
분류 | offset | 이름 | 값 |
Header | 0x06 ~ 0x07 | Header의 eh_depth | 0 → 따라서 Leaf nodes |
Leaf nodes 1 | 0x00 ~ 0x03 | Leaf nodes ee_block | 0 |
0x04 ~ 0x05 | Leaf nodes ee_len | 1 | |
0x06 ~ 0x07 | Leaf nodes ee_start_hi | 0x0000 | |
0x08 ~ 0x0B | Leaf nodes ee_start_lo | 0x2426 |
최종: 블록번호 (ee_start_hi + ee_start_lo) * 한 블록의 크기 4096 bytes (0x1000)
ee_start_hi + ee_start_lo = 0x00002426
(ee_start_hi + ee_start_lo) * 0x1000 = 0x2426000
해당 파티션의 첫 번째 블록그룹 시작점에서 0x2426000 만큼 이동하면 root directory 데이터로 이동할 수 있다.
/home/user/Downloads 디렉토리에 Flag_of_South_Korea.svg.png를 찾는 과정은 journal inode 분석 이후 진행한다.
II. inode를 통해 파일 주소로 접근하기
/home/user/Downloads 폴더에 Flag_of_South_Korea.svg.png 로 접근해보자.
우선 root directory의 inode를 통해 root directory에 접근하면 다음과 같은 데이터가 보이며, 이 데이터를 Directory Entry 라고 한다.
Directory Entry 분석
Directory Entry의 구조는 ext4_dir_entry, ext4_dir_entry_2가 존재한다.
어떤걸 사용하는지에 대한 기준은 슈퍼블록의 s_feature_incompat 필드의 0x2 번째 값(INCOMPAT_FILETYPE)을 통해 결정한다.
0이 (설정되지 않음) 있으면 ext4_dir_entry , 1이 (설정됨) 있으면 ext4_dir_entry_2 구조로 해석하면 된다.
구조는 다음과 같다.
ext4_dir_entry
Offset | Size | Name | 설명 |
0x00 ~ 0x03 | 4 bytes | inode | 디렉토리 엔트리가 가리키는 inode 번호 |
0x04 ~ 0x05 | 2 bytes | rec_len | 디렉토리 엔트리 길이 |
0x06 ~ 0x07 | 2 bytes | name_len | 파일 이름 길이 |
0x08 ~ | - | name[EXT4_NAME_LEN] | 파일 이름 |
ext4_dir_entry_2
Offset | Size | Name | 설명 |
0x00 ~ 0x03 | 4 bytes | inode | 디렉토리 엔트리가 가리키는 inode 번호 |
0x04 ~ 0x05 | 2 bytes | rec_len | 디렉토리 엔트리 길이 |
0x06 | 1 bytes | name_len | 파일 이름 길이 |
0x07 | 1 bytes | file_type | File type code, one of: 0x0 Unknown. 0x1 Regular file. 0x2 Directory. 0x3 Character device file. 0x4 Block device file. 0x5 FIFO. 0x6 Socket. 0x7 Symbolic link. |
0x08 ~ | - | name[EXT4_NAME_LEN] | 파일 이름 |
실습파일에 접근하기
현재 실습파일은 ext4_dir_entry 구조로 되어있으므로 해석해보면 다음과 같다. (슈퍼블록의 s_feature_incompat 확인)
/home/user/Donwoloads 접근하기
접근하고자 하는 파일의 경로는 /home/user/Downloads 폴더에 Flag_of_South_Korea.svg.png 이므로 home directory entry의 구조를 살펴보자.
해석해보면 다음과 같다.
Offset | Size | Name | 설명 |
0x00 ~ 0x03 | 4 bytes | inode | 0x80001 (524,289) |
0x04 ~ 0x05 | 2 bytes | rec_len | 0x0C (12) |
0x06 | 1 bytes | name_len | 0x04 |
0x07 | 1 bytes | file_type | File type code, one of: 0x2 Directory. |
0x08 ~ | - | name[EXT4_NAME_LEN] | home |
inode table에서 0x80001(524,289) 번째 inode 값을 확인한다. (각 그룹마다 inode table이 있지만 inode 번호는 초기화되지 않고 쭉 이어진다. 따라서 각 그룹의 inode table 값을 이어붙인 후 찾아가거나, 각 그룹별 첫번째, 마지막 inode 값을 확인하며 접근해야 한다. 나는 FTK Imager에서 inode table을 별도로 묶어서 확인하고 추출할 수 있도록 해놔서 그걸 참고했다.) 또한 inode는 1부터 시작하므로 이 점에 유의해야 한다. (1번째 inode라고 해서 냅다 0x100을 곱한 값으로 접근하면 2번째 inode 값이다. 따라서 값에 접근할 때는 1을 뺴줘야 한다.)
i_block 값을 분석해보면 다음과 같다.
분류 | offset | 이름 | 값 |
Header | 0x06 ~ 0x07 | Header의 eh_depth | 0 → 따라서 Leaf nodes |
Leaf nodes 1 | 0x00 ~ 0x03 | Leaf nodes ee_block | 0 |
0x04 ~ 0x05 | Leaf nodes ee_len | 1 | |
0x06 ~ 0x07 | Leaf nodes ee_start_hi | 0x0000 | |
0x08 ~ 0x0B | Leaf nodes ee_start_lo | 0x202020 |
최종: 블록번호 (ee_start_hi + ee_start_lo) * 한 블록의 크기 4096 bytes (0x1000)
ee_start_hi + ee_start_lo = 0x0000202020
(ee_start_hi + ee_start_lo) * 0x1000 = 0x202020000
해당 파티션의 첫 번째 블록그룹 시작점에서 0x488000000 만큼 이동하면 home directory로 이동할 수 있다.
그럼 또 Directory Entry를 확인할 수 있다.
마지막 디렉토리 record_length 값은 0x0FDC(4,060)으로 자신을 제외한 디렉토리 블록의 남은 공간을 표현하는 값이다.
마지막 디렉토리 엔트리는 남은 데이터 블록 공간을 모두 차지한다. 또한 디렉토리 엔트리가 저장되어 있는 블록은 한 개 이상의 블록을 차지하지 않는다.
Offset | Size | Name | 설명 |
0x00 ~ 0x03 | 4 bytes | inode | 0x80002 (524,290) |
0x04 ~ 0x05 | 2 bytes | rec_len | 0xFDC (4,060) |
0x06 | 1 bytes | name_len | 0x04 |
0x07 | 1 bytes | file_type | File type code, one of: 0x2 Directory. |
0x08 ~ | - | name[EXT4_NAME_LEN] | user |
inode table에서 0x80002(524,289) 번째 inode 값을 확인한다.
분류 | offset | 이름 | 값 |
Header | 0x06 ~ 0x07 | Header의 eh_depth | 0 → 따라서 Leaf nodes |
Leaf nodes 1 | 0x00 ~ 0x03 | Leaf nodes ee_block | 0 |
0x04 ~ 0x05 | Leaf nodes ee_len | 1 | |
0x06 ~ 0x07 | Leaf nodes ee_start_hi | 0x0000 | |
0x08 ~ 0x0B | Leaf nodes ee_start_lo | 0x202021 |
최종: 블록번호 (ee_start_hi + ee_start_lo) * 한 블록의 크기 4096 bytes (0x1000)
ee_start_hi + ee_start_lo = 0x0000202021
(ee_start_hi + ee_start_lo) * 0x1000 = 0x202021000
해당 파티션의 첫 번째 블록그룹 시작점에서 0x202021000 만큼 이동하면 user로 이동할 수 있다.
그럼 또 Directory Entry를 확인할 수 있다.
Downloads 폴더로 가본다.
Offset | Size | Name | 설명 |
0x00 ~ 0x03 | 4 bytes | inode | 0x80050 (524,368) |
0x04 ~ 0x05 | 2 bytes | rec_len | 0x14 (20) |
0x06 | 1 bytes | name_len | 0x09 |
0x07 | 1 bytes | file_type | File type code, one of: 0x2 Directory. |
0x08 ~ | - | name[EXT4_NAME_LEN] | Downloads |
별개로 마지막 디렉토리의 record_length 값을 확인해보자.
record_length 값이 0xE88로 마지막 디렉토리임을 확인할 수 있다.
inode table에서 0x80050(524,368) 번째 inode 값을 확인한다.
분류 | offset | 이름 | 값 |
Header | 0x06 ~ 0x07 | Header의 eh_depth | 0 → 따라서 Leaf nodes |
Leaf nodes 1 | 0x00 ~ 0x03 | Leaf nodes ee_block | 0 |
0x04 ~ 0x05 | Leaf nodes ee_len | 1 | |
0x06 ~ 0x07 | Leaf nodes ee_start_hi | 0x0000 | |
0x08 ~ 0x0B | Leaf nodes ee_start_lo | 0x202058 |
최종: 블록번호 (ee_start_hi + ee_start_lo) * 한 블록의 크기 4096 bytes (0x1000)
ee_start_hi + ee_start_lo = 0x202058
(ee_start_hi + ee_start_lo) * 0x1000 = 0x202058000
해당 파티션의 첫 번째 블록그룹 시작점에서 0x202058000 만큼 이동하면 Downloads로 이동할 수 있다.
Flag_of_South_Korea.svg.png
찾고자 하는 Flag_of_South_Korea.svg.png의 Directory Entry를 확인할 수 있다. (빨간색 네모)
Offset | Size | Name | 설명 |
0x00 ~ 0x03 | 4 bytes | inode | 0x801AA (524,714) |
0x04 ~ 0x05 | 2 bytes | rec_len | 0xFDC (4,060) |
0x06 | 1 bytes | name_len | 0x1B |
0x07 | 1 bytes | file_type | File type code, one of: 0x1 Regular file. |
0x08 ~ | - | name[EXT4_NAME_LEN] | Flag_of_South_Korea.svg.png |
inode table에서 0x 801AA (524,714) 번째 inode 값을 확인한다.
Offset | Size | Name | 설명 |
0x04 ~ 0x07 | 4 bytes | i_size_lo | 0x61C8 |
0x6C ~ 0x6F | 4 bytes | i_size_high / i_dir_acl | 0x0000 |
inode 분석을 통해 알 수 있는 파일의 크기는 0x61C8이다.
분류 | offset | 이름 | 값 |
Header | 0x06 ~ 0x07 | Header의 eh_depth | 0 → 따라서 Leaf nodes |
Leaf nodes 1 | 0x00 ~ 0x03 | Leaf nodes ee_block | 0 |
0x04 ~ 0x05 | Leaf nodes ee_len | 7 | |
0x06 ~ 0x07 | Leaf nodes ee_start_hi | 0x0000 | |
0x08 ~ 0x0B | Leaf nodes ee_start_lo | 0x20BCA7 |
최종: 블록번호 (ee_start_hi + ee_start_lo) * 한 블록의 크기 4096 bytes (0x1000)
ee_start_hi + ee_start_lo = 0x20BCA7
(ee_start_hi + ee_start_lo) * 0x1000 = 0x20BCA7000
해당 파티션의 첫 번째 블록그룹 시작점에서 0x20BCA7000 만큼 이동하면 최종 목적지인 png 파일이 저장되어 있는 곳으로 이동할 수 있다.
baseball.jpg
baseball.jpg의 Downloads 디렉토리 엔트리는 다음과 같다. (연두색 네모)
baseball.jpg 디렉토리 엔트리를 분석해보면 다음과 같다.
Offset | Size | Name | 설명 |
0x00 ~ 0x03 | 4 bytes | inode | 0x80D92 (527,762) |
0x04 ~ 0x05 | 2 bytes | rec_len | 0xFB8 (4,024) |
0x06 | 1 bytes | name_len | 0xC (12) |
0x07 | 1 bytes | file_type | File type code, one of: 0x1 Regular file. |
0x08 ~ | - | name[EXT4_NAME_LEN] | baseball.jpg |
inode table에서 0x80D92 (527,762) 번째 inode 값을 확인한다.
Offset | Size | Name | 설명 |
0x04 ~ 0x07 | 4 bytes | i_size_lo | 0x2E245 |
0x6C ~ 0x6F | 4 bytes | i_size_high / i_dir_acl | 0x0000 |
inode 분석을 통해 알 수 있는 파일의 크기는 0x61C8이다.
분류 | offset | 이름 | 값 |
Header | 0x06 ~ 0x07 | Header의 eh_depth | 0 → 따라서 Leaf nodes |
Leaf nodes 1 | 0x00 ~ 0x03 | Leaf nodes ee_block | 0 |
0x04 ~ 0x05 | Leaf nodes ee_len | 0x2F (47) | |
0x06 ~ 0x07 | Leaf nodes ee_start_hi | 0x0000 | |
0x08 ~ 0x0B | Leaf nodes ee_start_lo | 0x20BA7D |
최종: 블록번호 (ee_start_hi + ee_start_lo) * 한 블록의 크기 4096 bytes (0x1000)
ee_start_hi + ee_start_lo = 0x20BA7D
(ee_start_hi + ee_start_lo) * 0x1000 = 0x20BA7D000
해당 파티션의 첫 번째 블록그룹 시작점에서 0x20BCA7000 만큼 이동하면 최종 목적지인 jpg 파일이 저장되어 있는 곳으로 이동할 수 있다.
'분야 > Digital Forensics' 카테고리의 다른 글
FAT32 삭제된 파일 복구 (0) | 2024.03.11 |
---|---|
FAT32 File System (1) | 2024.03.04 |
Ext4 File System (0) | 2023.09.12 |
윈도우 아티팩트 정리 (1) | 2023.09.07 |
NTFS 삭제된 파일 복원 (1) | 2023.08.29 |