Android Forensic/File System

[Digital Forensic] Android Ext4 File System File Recovery Analysis

DF_m@ster 2024. 3. 6. 13:58

 

Ext4 File System File Recovery

본 문단은 안드로이드의 Ext4 파일 시스템에서 파일 삭제 정책을 토대로 파일 복구 과정을 정의하고, 삭제된 파일 복구 과정을 정리한 글이다. 파일 복구 실습은 두 가지 파일로 나누어 진행한다.
 
첫 번째 복구의 경우 Extent 내부에 Extent Entry가 하나 존재하는 파일 단편화가 일어나지 않은 파일이다.
두 번째 복구의 경우 파일 단편화가 5번 이상 일어나, Extent Depth가 1 이상인 파일의 복구이다.
아래는 복구 실습에 사용한 두 파일의 기본적인 정보이다.

File Name Size Extent Entry Count Extent Depth
20240302_135410.jpg 1,941 KB
(1,986,687 Byte)
1 0
20240302_135412.Mp4 177 MB
(186,212,521 Byte)
8 1

 
 
 

Ext4 Deletion Policy

Ext4 파일 시스템에서 파일 복구 과정을 정의하기 위해 먼저 파일 삭제 정책을 확인한다. 파일 삭제 정책은 Extent Depth가 0인 경우와 1 이상인 경우로 나뉜다. Extent Depth와 상관없이 공통적으로 발생하는 삭제 정책은 Inode Entry의 Deletion Time이 생성되고, File Size, Extent Header의 Valid Extent Entry, Extent Depth가 모두 zerofill 된다. Extent Depth가 0인 경우 추가적으로 Inode Entry 내부 Extent Entry 값이 모두 zerofill 된고, Extent Depth가 1 이상인 경우 Extent Entry 값은 유효하지만, Index Extent 혹은 Leaf Extent의 Extent Header에서 Valid Extent Entry 값과 Extent Entry의 Logical Block Number를 제외한 영역이 zerofill 된다.
 
 
 

File Recovery Flow Chart

본 문단의 파일 삭제 복구 과정은 삭제 이벤트 이후의 이미지 파일을 기점으로 한다. Ext4 파일 삭제 정책을 기반으로 파일 복구 흐름도를 정의하고, 각 순서 번호의 설명은 아래와 같다.
 
1. 복구할 파일의 상위 디렉터리 경로를 아는가?
 - 이때 파일의 이름 여부는 관련이 없다.
 - Yes -> 2번으로 이동
 - No -> 5번으로 이동
2. 복구할 파일의 Inode Number 확보.
 - 상위 디렉터리의 Directory Table에서 복구하려는 파일(삭제된 파일)의 Inode Number를 확보한다. 만약 파일의 이름을 아는 경우, 파일의 이름을 검색해 Inode Number를 확보한다.
3. Inode Number로 Inode Entry 접근.
 - 확보한 Inode Number로 Inode Entry에 접근한다.
4. Inode Number가 재할당 되었는가?
 - Inode Number가 재할당 되었다면 복구하려는 파일의 Inode Entry는 Inode Table에 존재하지 않기 때문에, Ext4의 journal에서 검색을 해야 한다. 
 - Yes -> 5번으로 이동
 - No -> 6번으로 이동
5. Ext4의 journal 혹은 Inode Table에서 삭제된 Inode Entry 전부 확보.
 - 1번에서 넘어온 경우: 복구하려는 파일의 경로를 모르는 경우로, Ext4의 journal 혹은 Inode Table에서 삭제된 Inode Entry(File Size == 0, Deletion Time != 0)를 전부 확보해야 한다.
 - 4번에서 넘어온 경우: Inode Number가 재할당된 경우로, Ext4의 journal에서만 삭제된 Inode Entry(File Size == 0, Deletion Time != 0)를 전부 확보해야 한다. Inode Table에는 존재할 수 없기 때문이다.
6. 삭제 이전의 Inode Entry 확보.
 - 이전의 과정에서 확보한 삭제된 Inode Entry의 File Version을 Ext4의 journal에서 검색해 삭제 이벤트 발생 이전의 Inode Entry를 확보한다.
7. Extent Depth가 '0'인가?
 - Extent Depth에 따라 Ext4의 journal에서 삭제 이전의 Extent 확보방법이 다르기 때문이다.
 - Yes -> 종료
 - No -> 8번으로 이동
8. Ext4의 journal에서 삭제 이전의 Index Extent 혹은 Leaf Extent 확보
 - Ext4의 journal에 백업된 Index Extent 혹은 Leaf Extent의 특징을 이용해 삭제 이전의 Index Extent 혹은 Leaf Extent를 확보한다. 구체적인 확보 방안은 복구 과정에서 자세히 서술한다.

Ext4 File Recovery Flowchart

 
 
 

File Recovery 1 (Non-Fragmentation File)

첫 번째 복구의 경우 Extent 내부에 Extent Entry가 하나 존재하는 파일 단편화가 일어나지 않은 파일의 복구이다. 때문에 Extent Depth가 0이다. 아래는 파일의 기본적인 정보로, 해당 파일은 카메라로 촬영한 이미지 파일이다. 

File Name Size Extent Entry Count Extent Depth
20240302_135410.jpg 1,941 KB
(1,986,687 Byte)
1 0

 
상위 디렉터리가 "Camera" 디렉터리이기 때문에, 복구하려는 이미지의 Inode Number를 확보하기 위해서는 Camera의 Directory Table에 접근한다. 아래는 Camera의 Directory Table로, 복구하려는 Directory Entry를 표시하였다. 확인한 정보는 다음과 같다.

Camera Directory Table

Name Value
Inode Number 0x09 04 7D
(590,973 (d))
File Name Length 0x13
File Type 0x01 == Regular File
File Name 20240302_135410.jpg

 
Inode Number(0x09 04 7D) 값을 이용해 Inode Entry에 접근하기 위해서는 먼저 FTK Imager로 Inode Table을 확보한다. Inode Table은 첫 번째 Inode Entry를 제외하고, 순차적으로 Inode Entry를 기록한다. 때문에 Inode Table에서 Inode Number에 Inode Entry Size인 '0x100'을 곱하고 '0x100'을 뺀 주소로 이동하면 Inode Entry에 접근할 수 있다.

Inode Entry Offset = Inode Number * 0x100 - 0x100

Inode Number가 '0x9047D'인 경우 Inode Table에서 해당 Inode Entry의 Offset은 '0x9047C00'이 된다.
 
해당 주소로 이동해 Inode Entry를 확인하면, Deletion Time이 유효한 값으로 존재하고, File Size, Extenet Header의 Valid Extent Entry, Extent Entry가 zerofill 되었음을 확인할 수 있다. 결과적으로 해당 Inode Number가 삭제 이후에 재할당 되지 않았으며, 온전히 삭제 이벤트만 발생한 경우임을 알 수 있다. Ext4의 journal에서 삭제 이전의 Inode Entry 확보에 필요한 File Version(0x96 60 6F 07)을 확인한다.

복구할 파일의 Inode Entry (삭제 후, Inode Table)

 
Ext4 journal에서 File Version을 검색해 삭제 이전의 Inode Entry를 확보한다. 총 41개가 검색되었으며, 파일 삭제 이벤트 직전의 Inode Entry를 추출하기 위해 순차적으로 Inode Entry를 검토하며 Deletion Time이 생성되기 이전의 Inode Entry를 확보한다.
 
아래는 Deletion Time이 생성되기 이전의 Inode Entry 모습이다. Deletion Time이 존재하지 않고, File Size와 Extent Entry 값이 유효함을 확인할 수 있다.

복구할 파일의 Inode Entry (삭제 전, journal)

 
복구하려는 파일의 Extent Entry가 Pointing 하는 Data Block 위치인 4,784,803번 Block으로 이동해본결과 zerofill이 진행된 이후였다.

복구할 파일의 Data Block (삭제 이후 이미징)

 
성공적으로 Extent를 확보했는지 검증하기 위해 파일 삭제 이벤트 이전에 이미징 작업을 수행하였다. 해당 이미지 파일에서 4,784,803번 Block으로 이동한 결과 jpg 헤더 시그니처가 존재해 성공적으로 Extent를 복구하였음을 검증하였다.

복구할 파일의 Data Block (삭제 이전 이미징)

 
 
 
 
 

File Recovery 2 (Fragmentation File)

 번째 복구의 경우 파일 단편화가 5번 이상 일어나, Extent Depth가 1 이상인 파일의 복구이다. 때문에 Extent Depth가 1 이상이다. 아래는 파일의 기본적인 정보로, 해당 파일은 카메라로 촬영한 영상 파일이다.

File Name Size Extent Entry Count Extent Depth
20240302_135412.mp4 177 MB
(186,212,521 Byte)
8 1

 
상위 디렉터리가 "Camera" 디렉터리이기 때문에, 복구하려는 이미지의 Inode Number를 확보하기 위해서는 Camera의 Directory Table에 접근한다. 아래는 Camera의 Directory Table로, 복구하려는 Directory Entry를 표시하였다. 확인한 정보는 다음과 같다.

Camera Directory Table

Name Value
Inode Number 0x09 04 7E
(590,974 (d))
File Name Length 0x13
File Type 0x01 == Regular File
File Name 20240302_135412.mp4

복구할 파일의 Inode Entry (삭제 후, Inode Table)

 
Inode Number가 '0x9047E'인 경우 Inode Table에서 해당 Inode Entry의 Offset은 '0x9047D00'이 된다.
 
해당 주소로 이동해 Inode Entry를 확인하면, Deletion Time이 유효한 값으로 존재하고, File Size, Extenet Header의 Valid Extent Entry가 zerofill 되었음을 확인할 수 있다. Extent Depth가 1 이상 이기 때문에 Inode Entry의 Extent Entry가 유효하게 존재한다. 결과적으로 해당 Inode Number가 삭제 이후에 재할당 되지 않았으며, 온전히 삭제 이벤트만 발생한 경우임을 알 수 있다. Ext4의 journal에서 삭제 이전의 Inode Entry 확보에 필요한 File Version(0x9A 60 6F 07)을 확인한다.
 
Ext4 파일 시스템은 Inode Entry의 Valid Extent Entry 값이 감소할 때, 비할당 처리된 Extent Entry를 zerofill 하지 않기 때문에 예시처럼 Extent Entry가 4개 존재하더라도 4개의 Extent Entry가 유효한 Extent라고 판단해서는 안된다. 때문에, 삭제 직전의 유효한 Extent Entry를 정확하게 확보하기 위해서는 Ext4의 journal에서 삭제 이전의 Inode Entry를 복구해야 한다.
 
Ext4 journal에서 File Version을 검색해 삭제 이전의 Inode Entry를 확보한다. 총 40개가 검색되었으며, 파일 삭제 이벤트 직전의 Inode Entry를 추출하기 위해 순차적으로 Inode Entry를 검토하며 Deletion Time이 생성되기 이전의 Inode Entry를 확보한다.
 
아래는 Deletion Time이 생성되기 이전의 Inode Entry 모습이다. Deletion Time이 존재하지 않고, File Size와 Extent Entry 값이 유효함을 확인할 수 있다. 추가로 Extent Entry는 1개 존재하고 Extent Depth가 1 임을 확인할 수 있다.

복구할 파일의 Inode Entry (삭제 전, journal)


Extent Depth 증가 시 Inode Entry의 변화를 구체적으로 분석하기 위해 Extent Depth가 1로 변하기 직전의 Inode Entry를 추출하였다.

아래는 해당 Inode Entry로 Valid Extent Entry 값이 4, Extent Depth 값이 0 임을 확인할 수 있다. 즉, Extent Entry가 4개에서 5개로 늘어나는 시점에서 Extent Depth를 증가시키는 정책임을 알 수 있다. 이때 Leaf Extent를 생성하여 5개 이상의 Extent Entry를 관리하며, Inode Entry의 첫 번째 Extent Entry는 기존처럼 Data Block을 포인팅 하는 것이 아니라, Leaf Extent를 포인팅 하기 때문에 값이 변경된다.

복구할 파일의 Inode Entry (삭제 전, journal)


Ext4의 journal에서 File Version의 검색으로 복구한 삭제 이전의 Inode Entry에서 첫 번째 Extent Entry의 Data Block 값이 '0x590000'이기 때문에 이하 Extent의 주소는 4,752,226번 Block이 된다.
 
해당 블록으로 이동해 이하 Extent를 확인하면, Extent Header에서 Valid Extent Entry, Extent Depth 값과 각 Extent Entry의 Logical Block Number를 제외한 영역이 zerofill 되었음을 확인할 수 있다.

Extent Entry의 Data Block Pointer값이 존재하지 않기 때문에 Ext4의 journal에서 이하 Extent를 복구해야 한다.

복구할 파일의 이하 Extent (이미지 파일)


Ext4는 트랜잭션이 발생하면 수정 예정인 메타데이터를 수정 이전에 Block 단위로 journal에 백업한다. 때문에 이하 Extent 삭제 이벤트 발생 시 삭제 이전의 이하 Extent는 Ext4의 journal에 백업된다.

Ext4의 journal에서 삭제 이벤트 이전의 이하 Extent를 확보하기 위한 방법은 다음과 같다. 먼저 Ext4 journal의 특성을 이용해 검색 범위를 줄인다. 이하 Extent는 Extent Header의 Magic Signature 값인 '0x0A F3'으로 시작한다. 때문에 Block 단위로 백업하는 Ext4의 journal 특성상 Ext4의 journal을 Block단위로 나누었을 때 각 Block의 시작 값이 '0x0A F3'인 Block을 추출해 검색 범위를 줄인다. 다음으로 추출된 Block(Ext4의 journal에 백업된 모든 이하 Extent Block)에서 Extent Entry Field의 특성을 이용해 복구하려는 파일의 이하 Extent를 백업한 Block을 선별한다. Extent Entry의 첫 4Byte는 Logical Data Block Number값을 갖고 이후의 2Byte는 Data Block Length 값을 갖는다. 이를 통해 마지막 Extent Entry의 첫 4Byte와 이후의 2Byte를 더한 값이 파일 전체 할당에 사용된 Block의 수임을 알 수 있다. Ext4의 journal에서 복구한 Inode Entry의 File Size값을 참조해 파일 전체 할당에 사용된 Block 수를 계산하고 그 값을 첫 번째 과정으로 추출된 Block에서 검색해 이하 Extent를 복구한다.

정리하면 Ext4의 journal을 Block단위로 나누었을 때 시작 값이 '0x0A F3'인 Block을 선별한다. 이후에 복구하려는 파일 저장에 할당된 Block 수를 계산하고, 이전 과정으로 선별된 Block에서 4Byte + 2Byte 하여 계산된 값과 동일한 값이 존재하는 Block을 추가 선별한다.

Logical Size = Block Size * X + Y


파일의 논리 크기로 할당된 Block의 수를 계산하는 방법은 다음과 같다. 파일의 논리크기를 Block size로 나눈 나머지(Y)가 0이라면 X값이 파일 할당에 사용된 총 Block수가 되고, 나머지가(Y)가 0이 아니라면 (X + 1) 값이 파일 할당에 사용된 총 Block수가 된다.

본 글의 경우 복구하려는 파일의 논리 크기는 '0xB1960A9'이고, Block 크기는 '0x1000'이기 때문에 '0xB1960A9'을 '0x1000'으로 나누어 계산한다. 이때 나머지가 존재하기 때문에 파일 할당에 사용된 총 Block 수는 몫에 1을 더한 '0xB197'('0xB196' + '0x1')이 된다.

아래는 위에서 서술한 복구 과정으로 검색한 Leaf Extent이다. Block의 시작 값이 '0x0A F3'이고, 마지막 Extent Entry의 첫 4Byte(Logical Data Block Number)와 2Byte(Data Block Length)를 더한 값이 '0xB197'값을 갖는다.

복구할 파일의 이하 Extent (journal)


복구하려는 파일의 첫 번째 Extent Entry가 Pointing 하는 Data Block 위치인 5,843,968번 Block으로 이동해본결과 zerofill이 진행된 이후였다.

복구할 파일의 Data Block (삭제 이후 이미징)

 
성공적으로 Extent를 확보했는지 검증하기 위해 파일 삭제 이벤트 이전에 이미징 작업을 수행하였다. 해당 이미지 파일에서 5,843,968번 Block으로 이동한 결과 mp4 헤더 시그니처가 존재해 성공적으로 Extent를 복구하였음을 검증하였다.

복구할 파일의 Data Block (삭제 이전 이미징)






 

메인 글

[Digital Forensic] Android Ext4 File System Detailed Analysis

 

[Digital Forensic] Android Ext4 File System Detailed Analysis

Ext4 Ext4(Extended File System): 리눅스 기반 시스템에서 널리 사용되는 파일 시스템으로, 주로 안드로이드의 파일 시스템으로 사용된다. 안드로이드는 리눅스 커널을 기반으로 하기 때문에, Ext4는 안

digitalforensicmaster.tistory.com

 

이전 글

[Digital Forensic] Android Ext4 File System Structure Analysis

 

[Digital Forensic] Android Ext4 File System Structure Analysis

Ext4 Ext4(Extended File System): 리눅스 기반 시스템에서 널리 사용되는 파일 시스템으로, 주로 안드로이드의 파일 시스템으로 사용된다. 안드로이드는 리눅스 커널을 기반으로 하기 때문에, Ext4는 안

digitalforensicmaster.tistory.com

 

 

 

 

Reference

https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout

https://www.dbpia.co.kr/journal/detail?nodeId=T15015734