no image
Volume Shadow Copy 분석
볼륨 섀도우 카피 ( Volume Shadow Copy ) 시스템 복원 지점은 윈도우 비스타 이후로 넘어오면서 '복원지점' 대신 '볼륨 섀도우 카피(Volume Shadow Copy)를 사용하고 있다. 시스템 복원 지점은 운영체제 재설치 없이 시스템을 백업한 과거의 특정 시점으로 복원하는 기능으로 운영체제 설치 시 기본으로 활성화되어 있다. 시스템 복원 지점은 아래와 같은 방법으로 설정할 수가 있다. 위의 그림과 같이 System에서 좌측의 Advanced system settings를 클릭하여 들어가면 아래와 같은 창을 볼 수가 있다. 여기서 "System Protection"이라는 탭에 해당 항목들이 존재한다. Create...를 통하여 새로운 복원 지점을 형성할 수가 있으며, 사안의 "System ..
2016.01.18
no image
Write Protection - Registry Setting
쓰기 방지 외부 장치를 연결하여 해당 장치를 분석하고자 할 경우 해당 볼륨에 파일이나 디렉터리를 생성, 변경, 삭제 하지 않는 이상 흔적이 남지 않는 줄 알았다. 하지만 직접 해본 결과, 연결 후 몇 가지 읽기 작업만 했을 뿐인데, $MFT, $LogFile, $UsnJrnl 등을 통해 확인할 수가 있었다. 따라서 외부 장치를 연결하여 분석하고자 할 때 무결성을 최대한 유지하기 위하여 쓰기 방지 작업을 선행하여야 한다. 쓰기 방지를 위한 툴들이 존재하지만 간단한 방법을 통해 쓰기 방지를 설정하는 방법에 대하여 알아보자. 여기서 사용할 방법은 레지스트리를 이용한 방법이다. 레지스트리 편집을 위해 Win+R에 regedit를 입력하여 레지스트리 편집기를 실행하자. 위 그림의 경로 HKLM\System\Cur..
2016.01.17
no image
NTFS FIle System (9) $UsnJrnl
$UsnJrnl 응용 프로그램이 특정 파일의 변경 여부를 파악하기 위해 사용한다. 기본적으로 Windows 7부터 활성화가 되어 있으며 비활성화 되어 있을 경우, Fsutil로 활성화 시 킬 수 있다. UsnJrnl은 $Max 속성과 $J 속성으로 구성되는데 $MAX는 변경 로그의 기본 메타 데이터를 저장하며 $J속성은 실제 변경 로그 레코드를 저장하고 있다. 여기서 $J의 각 레코드들은 USN(Updata Sequence Number)정보를 가지며, 이러한 USN 정보를 통해 각 레코드들의 순서를 구분한다. 실제 USN 값은 $J 속성 내에서의 레코드의 Offset 값을 가지고 있으며, USN 값은 MFT 엔트리의 $STANDARD_INFORMATION 속성에도 저장되어 있다. UsnJrnl은 MFT ..
2016.01.16
no image
NTFS File System (8) $LogFile
개요$LogFile? 지금까지의 과정은 $MFT를 위주로 진행되어왔다. 이제 MFT Entry 2번($MFT가 0번)에 위치하는 $LogFile에 대하여 알아보자. 추후에 학습할 $UsnJrnl이 변경 로그라면 $LogFile은 트랜젝션 로그이다. 이 역시 각 볼륨마다 하나씩 존재하며 만약 NTFS가 정전이나 기타 오류로 인해 갑작스럽게 중단되면 운영체제는 $LogFile에 저장된 로그를 바탕으로 현재 진행되는 작업의 이전 상태로 파일 시스템을 복구한다. 파일이나 디렉터리의 생성, 삭제, 데이터 작성, 파일명 변경 등 트랜잭션 작업 내용은 레코드 단위로 기록되며, $LogFile의 작업 레코드에 저장된다. 각 작업 레코드는 고유의 LSN($LogFile Sequence Number)를 가지며 이는 순차적..
2016.01.13
no image
NTFS & Python - $MFT Acquisition
1. 개요 포렌식을 공부하면서 점차 데이터 복구나 수집한 증거를 분석하는 방법에 대하여 점차 관심이 많아지기 시작하였다. 이를 위해선 공통적으로 파일 시스템에 대한 이해가 필요하다고 생각하였고, 그렇기에 현재 사용하고 있는 NTFS에 대하여 먼저 학습해보자 생각하였다. 파일 시스템이나 NTFS에 대하여 이론적으로 더 잘 정리된 많은 문서들이 있으므로, 나는 Python을 통해 접근을 하기 위함을 목적으로 학습을 진행하였다. 이렇게 접근을 한 다음 최종적으로는 $MFT 수집 도구를 만드는 것이 목적이다. 학습을 위한 준비사항은 아래와 같다. 도구 이름도구 버전다운로드Python2.7https://www.python.org/HxD.http://mh-nexus.de/en/hxd/Py2exe.http://www..
2016.01.07
no image
Windows USB Autorn 설정
USB 자동실행 방지 USB가 대중화된 시점에 USB를 꽂으면 자동적으로 실행되는 AutoRun을 통해 악성코드가 유포되기도 한다. 이러한 USB 자동실행을 방지하기 위하여 설정하는 방법에 대하여 간략히 알아보자. 윈도우 + R을 통해 'gpedit.msc'를 입력해주자. 그렇다면 아래와 같은 창이 뜨는 것을 확인할 수가 있다. 여기서 우리가 찾아 들어가야 할 곳은 'Administrative Templatres'이다. 해당 부분에 들어가 윈도우 구성 요소인 'Windows Components'에 들어가 'AutoPlay Policies'에 들어가보자. 위의 그림과 같이 Turn off Autoplay이 항목이 존재하고 있는 것을 확인할 수가 있다. 저 부분이 바로 AutoRun의 실행 여부를 담당하고 ..
2016.01.04
no image
노트북 하드 컴퓨터 연결
개요컴퓨터를 살 때 많이 고민하는 사항 중 하나가 데스크탑을 살지, 노트북을 살지에 대하여 많은 고민들을 하기도 한다. 이번 포스팅은 필자도 노트북을 쓰는 입장이므로 이에 대해 지식을 함양시키고자 직접 해보았다. 상황은 아래와 같다.- 기존에 쓰던 노트북이 어떠한 이유에서인지 부팅이 되지 않는다.- 고치러 가기엔 디스크에서 특정 파일을 빨리 사용해야 한다.이러한 상황에 있을 때 혹은 유사한 사항에 있을 때 할 수 있는 방법에 대하여 알아보자. 준비물이 몇 가지 필요하다.준비물 : 대상 노트북, 외장하드, 복구 또는 추출을 하기 위한 정상적인 PC 실습 필자는 아래와 같이 준비하였다. 노트북은 LG의 XNOTE를 준비하였으며 우측의 외장하드는 엠지텍의 MG25-TERRAN2+COUP을 준비하였다. 외장하드..
2016.01.03
no image
NTFS File System (7) INDEX
NTFS 인덱스 NTFS에서는 자료들을 빠르게 검색할 수 있도록 인덱스 구조로 관리하고 있다. 이의 대표적인 예가 바로 디렉터리이며 이러한 인덱스의 구조에 대하여 알아보자. NTFS가 인덱스로 관리하는 데이터는 아래의 표와 같다. 이러한 인덱스 관리 방법으로는 트리를 사용하는데 NTFS에서 사용하는 B 트리의 형태는 아래의 그림과 같다. 루트 노드는 최상위에 존재하며 시작점이 되는 노드이며 하위의 자식 노드를 가질 때 자신보다 왼쪽은 작은 값, 오른쪽은 자신보다 큰 값이 위치한다. 이를 통해 자신보다 낮은 노드를 찾기 위해선 왼쪽으로 가면 되고 높다면 오른쪽으로 가면 되는 편의성을 갖는다. 위의 그림과 같이 NTFS의 Index Node는 마지막에 노드의 끝을 알려주는 End of Node가 포함되어 있..
2016.01.02

볼륨 섀도우 카피 ( Volume Shadow Copy )


  시스템 복원 지점은 윈도우 비스타 이후로 넘어오면서 '복원지점' 대신 '볼륨 섀도우 카피(Volume Shadow Copy)를 사용하고 있다. 시스템 복원 지점은 운영체제 재설치 없이 시스템을 백업한 과거의 특정 시점으로 복원하는 기능으로 운영체제 설치 시 기본으로 활성화되어 있다. 시스템 복원 지점은 아래와 같은 방법으로 설정할 수가 있다.

  위의 그림과 같이 System에서 좌측의 Advanced system settings를 클릭하여 들어가면 아래와 같은 창을 볼 수가 있다. 여기서 "System Protection"이라는 탭에 해당 항목들이 존재한다. Create...를 통하여 새로운 복원 지점을 형성할 수가 있으며, 사안의 "System Restore..."를 통해 이전에 설정된 복원지점으로 복원할 수가 있다.


접근 방법


  VSC에 접근하는 방법에 대하여 알아보자. 접근하기 위해선 해당 경로를 아는 것이 우선이므로 관리자권한으로 CMD를 열고 vssadmin list shadows 를 입력해주자. 그러면 현재 가지고 있는 VSC 만큼 그 결과가 출력될 것이다. 아래의 그림을 보자.

  2개의 VSC가 출력되고 있는 것을 확인할 수가 있다. 출력 결과를 통해 해당 섀도우 카피가 생성된 시점을 확인할 수가 있으며 해당 폴더에 접근하고자 할때 중요한 "Shadow Copy Volume"을 확인할 수가 있다. 위에 드래그 한 부분과 같이 해당 경로를 복사해놓자. 그 후 아래의 그림과 같이 mklink 명령어를 통해 링크폴더를 생성한다.

  그러면 해당 폴더에 접근 할 수 있는 것을 확인할 수가 있고, 필자는 C:\vsc에 링크를 걸었다. 링크를 설정한 후 해당 디렉터리로 이동하면 카피되어 있는 이전의 C:\의 모습이 보이는 것을 확인할 수가 있다.

 

복원 지점 생성 시점

  위에선 복원 지점을 직접 생성하는 방법에 대하여 알아보았다. 하지만 매번 직접 생성해야한다면 불편함이 있다. 따라서 기본적으로 시스템 복원지점이 생성되는 경우는 아래와 같이 나열할 수가 있다.

- 초기 시스템 검사 시 : 운영체제를 설치하고 처음 시작할 때, 시스템 검사와 함께 생성한다.

- 주기적인 생성 : 시스템이 켜져 있는 경우 24시간 마다 생성하며, 24시간 이상 꺼져 있는 경우에는 다음 부팅 시 생성한다.

- 프로그램 설치 및 제거 시 : 윈도우 설치 관리자(Windows Installer)에 의해 시스템을 설치하거나 제가할 때 생성한다.

- 자동 업데이트 시 : 자동 업데이트를 통해 다운 받은 업데이트 파일이 설치되기 전 자동으로 생성한다.

- 시스템 복원 전 : 시스템 복원 작업은 시스템을 변경시키므로 복원 작업 전에 생성한다.

- 사용자가 수동으로 생성 : 시스템 복원 마법사를 통해 사용자가 수동으로 생성한다.

  복원 지점은 한번 생성되면 다음 복원지점이 생성될 때까지 시스템을 모니터링하며 관련된 내용을 계속 추가한다. 다음은 3개의 복원 지점이 생성된 경우이다. 첫 번째 복원 지점(RP1)이 생성된 이후, 각 이벤트가 발생할때마다 관련된 백업 내용이 RP1 폴더에 계속 추가된다. 추가는 두번째 복원지점(RP2)이 생성될 때까지 계속된다. 현재는 3번 째 복원 지점이 생성된 이후에 관련 이벤트가 발생하는 중이다. 이때, 두번째 복원 지점(RP2)로 시스템을 복원했다면 "EVENT #1-3"이 적용된 이후의 상태로 복원 된다.


복원 지점에 백업되는 정보

  각 복원 지점 폴더에 추가되는 이벤트 관련 내용이라는 것은 이벤트가 발생할 때마다 관련된 내용이 폴더에 백업된다. 복원 지점 간의 발생하는 시스템의 모든 행위를 백업하기는 어렵다. 그러기 위해선 백업용 저장매체를 추가적으로 장착해야할 뿐 아니라 시스템 행위를 RAID 1과 같이 미러링 하는 것이므로 성능 하락의 원인이 될 것이다. 따라서, 윈도우는 기본적으로 복원에 가장 필요한 정보만 백업한다.

복원가능 : - 레지스트리    - 사용자 프로파일    - COM+DB    -WFP.dll캐시    - WMI DB    - IIS Metabase    - filelist.xml:<Include>설정항목

복원불가 : - DRM 설정    - SAM Hive의 password    - WPA 설정    - 사용자 프로파일에 저장되는 사용자가 생성한 데이터

HKLM\SYSTEM\ControlSet001\Control\BackupRestore\FileNotToSnapshot에 설정된 항목

HKLM\SYSTEM\ControlSet001\Control\BackupRestore\FilesNotToBackup 에 설정된 항목

- HKLM\SYSTEM\ControlSet001\Control\BackupRestore\KeysNotToRestore에 설정된 항목

filelist.xml에 <Include>가 설정되지 않은 항목


* 레지스트리에 설정된 복원 제외 항목

  복원 가능한 정보 중 가장 중요한 레지스트리와 filelist.xml에 대해 살펴보자. 우선 레지스트리는 복원 지점이 생성된 순간, 스냅샷 형태로 백업된다. 최초 복원지점 생성 시에는 레지스트리 전체가 백업된 다음, 복원지점이 추가될 때마다 변경된 부분이 백업된다. 이렇게 백업된 스냅샷은 레지스트리 분석 도구로 분석이 가능하다. filelist.xml은 모니터링할 목록을 설정하는 파일로 위치는 다음과 같다.

- %SystemRoot%\System32\Restore\filelist.xml

  Filelist.xml에서 확인할 수 있는 내용은 크게 3가지로 구분되어 있다. <FILES>는 모니터링할 파일이 설정되어 있으며, <DIRECTORIES>는 모니터링할 디렉터리가 설정되어 있고, 마지막으로 <EXTENSIONS>는 모니터링할 확장자가 설정되어 있다.

  이러한 각 노드는 다시 <Exclude>와 <Include>로 나뉘어 지는데 각 각 제외할 목록과 포함할 목록을 가지고 있다. 즉, 복원 지점에 백업하기 위해 모니터링할 파일, 디렉터리, 확장자에 대한 포함/제외 여부를 설정할 수 있다. 이렇게 세분화되는 이유는 백업에 따른 우선순위 때문이다. <FILE>가 우선 순위가 가장 높고 <EXTENSIONS>가 가장 낮기 때문에, 두 부분에서 각 각 포함/제외가 다르다면 우선순위에 따라 결정이 되는 것이다.

  이와 같이 filelist.xml에 설정된 파일들은 생성, 변경, 삭제 이벤트가 발생할 때마다 이벤트 내역, 경로, 파일의 복사본 등이 백업된다. 하지만 파일을 삭제할 때 Shift+Del과 같이 휴지통을 거치지 않고 삭제하게 되면 파일의 복사본은 백업되지 않고 삭제한 기록만 남게된다. 파일/ 폴더에 대한 모니터링은 시스템 복원 필터 드라이버(%SystemRoot%\System32\drivers\sr.sys)에 의해 추적 감시 된다. 해당 드라이버는 시스템 복원 기능에 의해 설정된 파일들이 변경이 일어날 때마다, 변경에 대한 로그를 기록하고 복사본을 생성한다.


복원 과정

  한번 직접 복원을 해보자. 해당 설정에 들어가 복원을 클릭하면 아래와 같이 나타난다. 여기서 영향을 받는 프로그램 검색을 클릭하면 복구를 하므로 사라지는 프로그램과 복구되는 프로그램의 목록을 볼 수가 있다. 이를 확인한 뒤 다음을 클릭하여 계속 진행하자.


  아래와 같이 마지막 화면 창이 나타난다. 이에 대해 경고문을 읽고 조심하여야한다. 복구를 통해 오히려 손실되는 프로그램이 있을 수도 있으므로 테스트는 VM환경에서 진행하는 것이 좋다.


  마침을 누르면 복원이 진행되는 것을 확인할 수가 있다. 여기서부턴 되돌릴 수 없으므로 유념하여야 한다. 복구가 완료되면 부팅 되는 것을 확인할 수가 있으며 설정에 따라 지정된 디렉터리 및 파일들이 남게 된다. 이렇게 쉽게 복원을 진행할 수가 있다.


활용 방안


삭제된 피알 복구

  filelist.xml에 <Include>되어 있는 파일들은 삭제될 경우 복사본인 백업 파일이 생성된다. 휴지통을 거치지 않고 Shift+Del 키를 이용한 경우 복사본이 남지 않지만, 삭제한 흔적은 확인할 수 있다. 따라서, 용의자 혹은 공격자가 악의적인 파일을 생성/실해한 후 흔적을 지우기 위해 파일을 삭제했다면 복원지점에서 관련된 흔적을 찾을 수 있다. 실제로 최근의 악성코드와 관련된 침해 사고는 자신의 흔적을 은폐하기 위해 관련 파일을 모두 삭제한다. 이 경우, 사건을 인지하고 초기 대응이 빠르다면 삭제된 흔적을 쉽게 발견할 수 있지만, 늦은 대응이라면 발견할 수 없는 삭제 흔적을 복원지점을 통해 발견할 수 있다.


설치/제거된 프로그램

  삭제된 파일과 마찬가지로 윈도우 설치관리자에 의해 설치/삭제된 프로그램 목록도 확인가능하다. 따라서, 윈도우 설치가 필요한 프로그램을 분석 시스템에 설치한 후 삭제하였더라고 복원지점을 확인하면 해당 흔적을 확인할 수 있다.


악의적인 드라이버 설치 흔적

  WHQL에 의해 인증되지 않은 드라이버를 설치 할 때도 복원지점이 생성된다. 따라서 커널 루트킷을 만들기 위해 설치하는 악의적인 드라이버의 흔적도 발견할 수가 있다.


악성코드 삭제 흔적

  PE 파일은 기본적으로 filelist.xml에 <Include> 되어 있다. 따라서, <Exclude>된 디렉터리가 아닌 곳에서 실행하고 삭제했다면 악성코드 복사본이 복원지점에 저장되어 있다. 따라서, 악성코드를 삭제하여 해당 파일을 찾을 수 없는 경우에도 타임라인 분석을 이용하다보면 복원지점에서 복사본이 발견되는 경우가 자주 있다.



참고

http://www.forensicswiki.org/wiki/Windows_Shadow_Volumes

http://forensic-proof.com/archives/2854

https://technet.microsoft.com/en-us/library/ee923636(v=ws.10).aspx

http://blogs.msdn.com/b/adioltean/archive/2008/02/28/a-simple-way-to-access-shadow-copies-in-vista.aspx

쓰기 방지


  외부 장치를 연결하여 해당 장치를 분석하고자 할 경우 해당 볼륨에 파일이나 디렉터리를 생성, 변경, 삭제 하지 않는 이상 흔적이 남지 않는 줄 알았다. 하지만 직접 해본 결과, 연결 후 몇 가지 읽기 작업만 했을 뿐인데, $MFT, $LogFile, $UsnJrnl 등을 통해 확인할 수가 있었다. 따라서 외부 장치를 연결하여 분석하고자 할 때 무결성을 최대한 유지하기 위하여 쓰기 방지 작업을 선행하여야 한다.

  쓰기 방지를 위한 툴들이 존재하지만 간단한 방법을 통해 쓰기 방지를 설정하는 방법에 대하여 알아보자. 여기서 사용할 방법은 레지스트리를 이용한 방법이다. 레지스트리 편집을 위해 Win+R에 regedit를 입력하여 레지스트리 편집기를 실행하자.

  위 그림의 경로 HKLM\System\CurrrentControlSet\Control\StorageDevicePolicies 를 확인해보자. 위와 같이 WriteProtect라는 항목이 존재하고 있는 것을 확인할 수가 있다. 현재 값이 0으로 설정되어 있는 것을 확인할 수가 있다. 만약 값이 1일 경우 외부 장치를 연결하였을 때 쓰기 방지를 통하여 쓰기 작업을 할 수가 없다.

  만약 위의 그림과 같이 "StorageDevicePolicies"라는 항목이 없을 경우 명령어를 통해 추가해주어야한다. 관리자 권한으로 CMD를 실행 시킨 뒤, 다음과 같은 명령어를 입력해주면 된다.

Admin>reg add "HKLM\System\CurrentControlSet\Control\StorageDevicePolicies" /t Reg_dword /v WriteProtect /f /d 1


  값이 1로 설정되면 외부 장치 쓰기 방지가 설정된 것으로 기존과는 다르게 파일의 복사하여 외부 장치에 옮기려 할 경우 아래와 같이 출력되는 것을 확인할 수가 있다. "The disk is write-protected"라는 문구를 확인할 수가 있다.



'O / S > Window' 카테고리의 다른 글

Windows Boot Process (Vista 이상ver 부팅 과정)  (0) 2016.04.13
CSIDL 값  (0) 2016.02.20
Windows USB Autorn 설정  (0) 2016.01.04
Windows 10 _HANDLES_TABLE, _HADNLES_TABLE_ENTRY  (0) 2015.11.09
Control registers - wiki  (0) 2015.11.07

$UsnJrnl


  응용 프로그램이 특정 파일의 변경 여부를 파악하기 위해 사용한다. 기본적으로 Windows 7부터 활성화가 되어 있으며 비활성화 되어 있을 경우, Fsutil로 활성화 시 킬 수 있다. UsnJrnl은 $Max 속성과 $J 속성으로 구성되는데 $MAX는 변경 로그의 기본 메타 데이터를 저장하며 $J속성은 실제 변경 로그 레코드를 저장하고 있다.

  여기서 $J의 각 레코드들은 USN(Updata Sequence Number)정보를 가지며, 이러한 USN 정보를 통해 각 레코드들의 순서를 구분한다. 실제 USN 값은 $J 속성 내에서의 레코드의 Offset 값을 가지고 있으며, USN 값은 MFT 엔트리의 $STANDARD_INFORMATION 속성에도 저장되어 있다. UsnJrnl은 MFT 엔트리의 10번째인 $Extend 디렉터리 안에 존재하고 있다. /$Extend/$UsnJrnl 와 같은 경로를 가지고 있다.

 기록 되는 로그 데이터의 양은 일반적으로 컴퓨터를 계속 사용할 경우 1~2일 정도의 로그가 남으며, 규칙적(하루 8시간)으로 사용할 경우 4~5일 정도의 로그가 남는다.


$UsnJrnl 구조


$Max 속성의 구조

  $Max 속성은 32 Byte의 고정된 크기를 가지며 해당 속성에 저장되는 정보는 아래와 같이 로그 데이터의 최대 크기, 그리고 $UsnJrnl 파일의 생성시간, 마지막으로 현재 저장된 레코드 중 가장 작은 USN 값을 갖으며, 해당 값을 통해 $J 속성 내 첫 번째 레코드로 바로 이동이 가능하다.


$J 속성의 구조

  $J 속성은 가변적은 크기를 가지며, 로그 레코드들이 연속적으로 나열된다. 또한 속성의 앞 부분은 0으로 채워진 "Sparse Area"를 가지고 있다. 아래의 그림은 내 PC의 $UsnJrnl:$J를 나타낸 것으로 0부터 0x57800000 전 까지는 모두 0으로 채워져 있는 것을 확인할 수가 있다. 이러한 구조를 가지는 이유는 운영체제가 $J 속성에 저장되는 로그 데이터의 크기를 일정하게 유지하려고 하기 때문이다.

  $J 속성은 새로운 로그 레코드들이 할당 될 때마다 속성 끝에 추가되며, 추가된 레코드들의 총 크기가 "Allocation Size"를 넘으면 추가 레코드들을 포함하여 전체 로그 데이터의 크기가 "Maximum Size"를 넘는지 확인한다. 만약 전체 로그 데이터의 크기가 "Maximum Size"를 넘는다면 로그 데이터의 앞 부분을 "Allocation Size" 만큼 0으로 채워 "Sparse Area"로 만든다.

  따라서 $J 속성의 논리적인 크기는 계속 커지지만 실제 데이터가 할당된 영역은 일정하게 유지되며, 일반적으로 0x2000000~0x23FFFFF의 로그 데이터를 저장한다.

  MFT Reference Numbr 대신 Parent MFT Reference Number를 사용하는 이유는 전자를 사용할 경우, 해당 파일이 삭제되었을 때 전체 경로를 못 얻을 수도 있기 떄문이다. 

<Reason Flag>

<Source Information>

<File Attribute>



출처 및 참고

F-INSIGHT-NTFS-Log-TrackerKorean.pdf

개요


$LogFile?

  지금까지의 과정은 $MFT를 위주로 진행되어왔다. 이제 MFT Entry 2번($MFT가 0번)에 위치하는 $LogFile에 대하여 알아보자. 추후에 학습할 $UsnJrnl이 변경 로그라면 $LogFile은 트랜젝션 로그이다. 이 역시 각 볼륨마다 하나씩 존재하며 만약 NTFS가 정전이나 기타 오류로 인해 갑작스럽게 중단되면 운영체제는 $LogFile에 저장된 로그를 바탕으로 현재 진행되는 작업의 이전 상태로 파일 시스템을 복구한다.


  파일이나 디렉터리의 생성, 삭제, 데이터 작성, 파일명 변경 등 트랜잭션 작업 내용은 레코드 단위로 기록되며, $LogFile의 작업 레코드에 저장된다. 각 작업 레코드는 고유의 LSN($LogFile Sequence Number)를 가지며 이는 순차적으로 증가한다. 이러한 각 레코드는 복구를 위해 작업 데이터(Redo)와 작업 전 데이터(Undo)를 갖는다.


$LogFile Size



  일반적인 하드 디스크 볼륨에서는 64MB인것을 알 수가 있으며 볼륨 용량에 따라 크기가 달라질 수는 있지만 기본적으로는 최대 64 MB 이하이다. 만약 이러한 $LogFile의 크기를 변경하고자 할 때는 chkdsk 명령의 /L 옵션에 따라 크기 조절이 가능하며 '/L:파일크기(KB 단위)' 형식의 옵션을 주면 $LogFile의 크기를 변경할 수 있으며 크기를 지정하지 않는다면 위의 그림과 같이 현재 크기를 나타낸다.




구조


$LogFile의 전체적인 구조

  $LogFile은 아래의 그림과 같이 재시작영역(Restart Area)과 로깅 영역(Logging Area)으로 나뉘어진다. 각 영역의 구성 단위는 0x1000(4096)바이트 크기의 페이지이다. 재시작 영역은 파일의 가장 첫 두 페이지(0x0000~0x20000)에 해당하고 가장 마지막 작업에 대한 정보를 가지고 있다.


  로깅 영역은 재시작 영역 외의 영역(0x2000~)을 말하며 실제 작업 레코드들이 기록된다. 로깅 영역은 다시 버퍼 페이지 영역과 일반 페이지 영역으로 구성된다. 이에 대한 건 좀 더 뒤에서 이야기할 것이다.



$LogFile 재시작 영역 구조



  위에서 말한 바와 같이 재시작 영역은 가장 마지막 작업 레코드를 가리키며 이는 현재 작업 중인 내용으로 0x0000부터 두 페이지(0x2000)로 구성이 된다. 여기서 두 번째 페이지는 백업용으로 사용되며 각 페이지는 매직넘버(RSTR)로 시작한다. 운영체제는 이 영역에서 마지막 레코드에 대한 정보를 가져와서 파일 시스템을 복구하는 것이다. 위의 그림은 재시작 영역의 페이지 헤더 구조이며 Cuurent LSN 필드에 마지막 작업 레코드의 LSN 정보를 저장하고 있다.



  위 그림은 실제 $LogFile을 Hex Editor로 열어서 확인한 것으로 상단의 그림은 첫 번째 페이지 영역으로 매직넘버 RSTR로 시작하는 것을 확인할 수가 있다. 하단의 그림은 두 번째 페이지 영역(0x1000~0x2000)의 시작 부분으로 위와 같은 구조를 가지고 있으며 백업을 위한 공간임을 알 수가 있다.


* 재시작 영역은 운영체제가 어떠한 파일 시스템의 정리를 수행할 경우 어떠한 트랜잭션을 참고해야 하는지 판단하는데 도움을 주는 구조체이며, 성공적인 마지막 트랜잭션을 위한 어떤 로깅 영역을 가리키는 포인터를 포함한다.



$LogFile 로깅 영역 구조


  로깅 영역에는 실제 작업 레코드들이 기록되며 버퍼 페이지 영역과 일반 페이지 영역으로 나뉘어진다. 여기서 버퍼 페이지 영역은 첫 두 페이지(0x2000~0x4000)가 존재하고 두 번째 페이지는 위와 같이 백업용이며 순차적으로 레코드가 기록된다. 여기서 만약 버퍼 페이지가 레코드로 가득 차게 되면 페이지 내용을 일반 페이지 영역으로 기록을 넘기는 형식으로 작업이 진행된다. 따라서 가장 최근의 작업 레코드들은 버퍼 페이지 영역에 남게 된다.


  일반페이지 영역은 버퍼 페이지를 제외한 나머지 영역(0x4000~)을 말하며 버퍼 페이지가 모두 채워지면 기록된 내용을 받는 역할을 한다. 만약 작업 레코드들이 파일 끝까지 가득 차게 되면 위의 그림과 같이 일반 페이지 영역 시작부분부터 다시 덮어쓰는 방식으로 진행된다.


* Redo 필드는 어떤 동작이었는지에 대한 정보를 저장하며, Undo 필드는 어떤 동작을 어떻게 원래대로 되돌리는지 설명하는 정보를 저장한다.



Page 구조



  페이지는 $LogFile의 기본 구성 단위이며 크기는 0x1000(4096 Bytes)로 고정되어 있다. 페이지는 하나의 헤더와 다수의 작업 레코드들로 구성되어 있으며 마지막 레코드가 페이지를 넘어가면 다음 페이지에 이어서 기록이 된다. 위의 그림은 이 구조를 나타낸 것으로, 페이지 헤더에 매직 넘버('RCRD')가 나오는 것을 확인할 수가 있으며 Last LSN 필드의 정보를 통해 페이지 내에서 가장 나중에 기록된 작업 레코드의 LSN 정보를 획득할 수 있다. Next Record Offset 필드의 정보를 통해 페이지 내에서 가장 나중에 기록된 작업 레코드의 위치를 알 수가 있다.


 Magic Number

 "RCRD" 

 Last LSN 

 페이지를 넘어가는 레코드를 포함해서 가장 큰 LSN 

 Next Record Offset  

 Last LSN에 해당 하는 레코드의 페이지 내 Offset 

 Last End LSN 

 페이지를 넘어가지 않는 레코드들 중에 가장 큰 LSN 


  결국 운영체제는 재시작 영역의 Currsnt LSN 필드에서 가장 마지막에 기록된 LSN 정보를 가져와서 해당 LSN 정보를 Last LSN 값으로 가진 페이지를 찾고, 그 페이지의 Next Record Offset을 가져와 실제 마지막 기록된 레코드의 위치를 찾는다.



작업 레코드 구조



  작업 레코드에는 실제 트랜젝션 작업의 내용이 기록되며 위의 그림과 같이 여러 작업 레코드가 순차적으로 모여서 하나의 트랜젝션 작업을 이룬다. 가장 첫 레코드를 Checkpoint 레코드라 하며 마지막 레코드를 Commit 레코드라 한다. 그 외 중간에 있는 레코드들은 Update 레코드라 한다.


  Checkpoint 레코드 외의 레코드들은 자신의 이전 작업 레코드의 LSN 값을 가지고 있다. 따라서 파일 시스템 복구 시, 운영체제는 트랜젝션 작업을 구성하는 레코드들을 역추적하면서 각 레코드들의 Undo 데이터를 사용하여 복구할 수가 있다.


[이미지 출처 - zrungee Blog]


  작업 레코드는 레코드 헤더와 데이터 영역으로 구성된다. 레코드 헤더는 고정된 0x58 크기를 가지며 데이터 영역은 Redo와 Undo 데이터가 들어가기 때문에 크기가 가변적이다. 따라서 작업 레코드의 크기도 가변적이며 큰 레코드는 여러 개의 페이지를 사용하기도 한다. 그리고 하나의 작업 레코드가 끝나면 바로 이어서 다음 작업 레코드가 이어진다. 상세한 작업 레코드 헤더 구조는 위의 그림과 같으며 각 필드에 대한 설명은 아래의 표와 같다.



  Redo Op 필드와 Undo Op 필드는 실제 레코드가 어떠한 작업을 수행하였는지에 대한 정보를 가진다. 각 Op가 가지는 연산 코드의 의미는 아래와 같다.




출처 및 참고

http://www.ahnlab.com/kr/site/securityinfo/secunews/secuNewsView.do?curPage=1&menu_dist=2&seq=19518

http://zrungee.tistory.com/206

'Forensic > Theory' 카테고리의 다른 글

Volume Shadow Copy 분석  (1) 2016.01.18
NTFS FIle System (9) $UsnJrnl  (0) 2016.01.16
NTFS File System (7) INDEX  (0) 2016.01.02
Cluster Run 직접 확인해보기 - MFT엔트리찾기  (0) 2015.12.31
NTFS File System (6) MFT $SIA & $FN $DATA  (0) 2015.12.31

  포렌식을 공부하면서 점차 데이터 복구나 수집한 증거를 분석하는 방법에 대하여 점차 관심이 많아지기 시작하였다. 이를 위해선 공통적으로 파일 시스템에 대한 이해가 필요하다고 생각하였고, 그렇기에 현재 사용하고 있는 NTFS에 대하여 먼저 학습해보자 생각하였다.

  파일 시스템이나 NTFS에 대하여 이론적으로 더 잘 정리된 많은 문서들이 있으므로, 나는 Python을 통해 접근을 하기 위함을 목적으로 학습을 진행하였다. 이렇게 접근을 한 다음 최종적으로는 $MFT 수집 도구를 만드는 것이 목적이다. 학습을 위한 준비사항은 아래와 같다.

도구 이름

도구 버전

다운로드

Python

2.7

https://www.python.org/

HxD

.

http://mh-nexus.de/en/hxd/

Py2exe

.

http://www.py2exe.org/

표 1. 사용한 도구

  학습은 윈도우 10을 통해 진행하였으며 전체적으로 학습을 하면서 Windows7이나 XP와의 별 차이를 느끼지 못하였다. Prefetch나 Web Artifact에 있어선 좀 상이한 부분이 있지만, 이번 문서에서 다루는 내용에 한해서는 큰 차이가 없었다.


그림 1. 부팅 과정

  컴퓨터의 전원을 누른 순간부터 사용자 모드로의 부팅 과정은 위의 그림과 같다. 여기서 BIOS는 ROM에 적재가 되어 있으므로 우리는 MBR부터의 과정을 구체적으로 확인할 수가 있다. 이를 토대로 학습을 진행해보자.



2. 디스크 접근


2.1 HxD 디스크 열기

  전체적인 진행을 하기 전에 직접 자신의 디스크를 확인해보자. HxD를 관리자 권한으로 실행을 한 다음, 아래의 버튼과 같이 디스크 열기를 누르면 대개 '논리 디스크'와 '물리 디스크'라 나뉘어 있는 것을 확인할 수가 있다.

그림 2. HxD 디스크 열기

  이 중 어떠한 것을 열어야 할 지 모른다면 직접 둘 다 열어서 확인해보자. 어떠한 차이가 있는지는 아래의 그림과 같다. '물리 디스크'를 먼저 확인해보면 알 수 있는 것이 아무것도 없다. 반면에 '논리 디스크'로 연다면 시작과 함께 NTFS라는 문자열이 있다.

그림 3. HxD 디스크 확인

  이는 기본적인 디스크를 어떻게 구분하느냐에 따른 것이다. 물리 디스크는 하나의 장치 그 자체를 말하는 것이며 논리 디스크는 하나의 파티션이나 볼륨과 같은 논리적인 부분을 말하는 것이다.


2.2 Python 디스크 열기

  Python을 통해 이러한 물리 디스크나 논리 디스크에 접근하는 방법에 대하여 알아보자. Python에는 기본적으로 open(filename, type) 함수가 존재하고 있다. 그렇다면 어떻게 이러한 시스템적인 부분에 접근하는가? 아래의 그림을 보자.

그림 4. Python – open()

* 여기서 CMD를 열 때Administrator 권한으로 열어야 권한 거부가 생기지 않는다.

 

  이렇게 Python에서 Drive에 접근하고자 할 땐 '\\\\.\\Drive'와 같이 나타내어야 한다. 이는 원래 \\.\Drive 인 것을 나타내기 위해 \를 두 번씩 표기하여 주는 것이다. 만약 두 번씩 하지 않으면 하나는 생략된 결과로 Python은 인식하게 된다. 접근 모드는 'rb'로 바이너리를 읽기 모드로 여는 것이다.

그림 5. Python – read()

  제대로 물리 드라이브를 읽는 것을 확인할 수가 있다. 그렇다면 물리드라이브엔 어떻게 접근을 해야 할까? 의문을 가질 수가 있다. 결국 최종적인 목표는 $MFT를 수집하는 것임을 잊지 말자. NTFS에서 부팅 가능한 영역을 MBR에서 찾아서 가는 것이 어찌 보면 부팅 과정처럼 정도의 길이라 할 수가 있다.

 

그림 6. Python – 논리 디스크 열기

  하지만 바로 논리 디스크로 접근하는 방법이 있다면 굳이 MBR에서부터 부팅 가능한 영역을 찾는 번거로움을 감수하고 싶지는 않을 것이다. 위의 그림과 같이 \\\\.\\ 뒷 부분에 열고자 하는 논리 디스크 'C:'와 같이 입력을 해주면 된다. 읽은 부분에서 NTFS 라는 그림 3에서 확인했던 문자열이 올바르게 출력되는 것을 확인할 수가 있다.


2.3 MBR 구조

  물리 디스크 영역은 앞 부분에 MBR(Mater Boot Record)가 있다. 코드 영역엔 부팅을 하기 위한 코드들이 포함되어 있으며, 붉게 표시한 부분은 바로 파티션 테이블로 64 Byte를 차지하고 있는 것을 확인할 수가 있다. 전체적인 구조는 아래와 같이 나타난다.

 

그림 7. MBR

  코드 영역은 별도의 구조가 없이 코드들로 이루어져 있지만 파티션 테이블의 경우에는 구조가 있기 때문에 그 구조에 맞게 해석을 할 수가 있어야 한다. 파티션 테이블은 부팅 가능한 디스크를 나타내기 위한 부분으로 아래의 구조와 같다.

그림 8. Partition Table

  여기서 중요한 것은 바로 앞 부분의 1바이트이다. Boot Flag로 부팅이 가능한 파티션인지를 나타내는 값으로 0x80은 부팅이 가능하다는 것을 뜻하며 0x00은 부팅이 불가능함을 뜻한다. 파티션 타입의 경우 어떤 타입(FAT, Unix, NTFS 등)을 나타낸다.

  그렇다면 부팅 가능한(Boot Flag = 0x80) 파티션이 있다면 그 위치는 어떻게 알 수 있을까? 예전엔 CHS Address를 사용했지만 점차 용량이 커지므로 표현의 한계가 있기에 현재는 LBA를 통해 해당 운영체제의 시작 지점을 알 수가 있다. 여기서 LBA란 Local Black Area의 약자로 흔히 섹터라 표현할 수가 있다. 위 그림 8의 Starting LBA Address란 결국 몇 번째 섹터에 운영체제가 시작하는 지 포함되어 있음을 의미한다. 이를 직접 확인해보자.

 

그림 9. HxD Partition Table

  위의 그림은 실제 내 PC의 파티션 테이블이다. 각 색에 맞게 4개의 파티션이 나타나 있는 것을 확인할 수가 있다. 세 번째 파란색 부분을 보면 부팅 플래그가 0x80으로 부팅이 가능함을 나타내며 7912000 LBA에 운영체제가 시작함을 나타낸다.

* 참고 : 섹터의 크기는 512 Bytes이므로 해당 LBA에 512를 곱해 Offset을 알 수 있다.

  단, 윈도우 7부턴 윈도우를 설치할 때 시스템 예약 파티션이 나뉘어 지는데, 해당 파티션은 BitLocker 암호화를 위한 예약된 공간이다. 특이한 점은 이전 XP와는 다르게 부팅 플래그가 바로 이 시스템 예약 파티션에서 설정이 되어 있다는 점이다. 다시 말해 위 그림 9의 부팅 플래그 0x80으로 되어 있는 부분이 시스템 예약 파티션이란 것이다. 정확한 이유는 알 수가 없지만, BitLocker 암호화는 지정된 보호 기능을 위해 동작하는 것으로, 해당 부분을 보호하기 위하여 먼저 이 곳으로 부팅이 되는 것이 어찌 보면 당연한 것이다. 컴퓨터의 전원을 켰을 때 장치에 이상이 없는 것을 POST에서 확인하는 것과 유사하다고 생각하자.

  그렇다면 그림9에서 NTFS는 어디에 있는 것일까? 바로 네 번째 부분에 존재하고 있다. 파티션 타입번호(0x07)을 통해 확인하거나 해당 LBA로 직접 가서 확인하는 방법이 있다. 물론 시스템 예약 파티션을 없애면 바로 NTFS로 부팅 플래그가 설정 될 것이다. 만약 파티션이 5개 이상이라면 MBR에 더해 EBR로 관리를 하는데 이는 파티션 테이블 부분에 EBR로 가는 16 Bytes 구조가 생기며 해당 LBA로 이동하면 다음 EBR과 자신이 가리키는 파티션의 LBA를 가지고 있다.

 

 

 3. NTFS


  2장의 과정을 통해 MBR을 통해 부팅 가능한 파티션과 해당 파티션의 위치를 찾아가는 방법에 대하여 알아보았다. HxD로 '물리 디스크'로 디스크를 열었지만 이 방법을 통해 NTFS가 있는 '논리 디스크' C:와 같은 부분을 찾을 수가 있다.

그림 10. 논리디스크 찾기

  이제 본격적으로 NTFS에 대하여 알아보자. Python을 통해선 2장의 과정이 없이 바로 C:와 같은 논리 디스크를 열 수 있음을 다시 한번 기억하자. 이제부터 다룰 내용은 NTFS의 구조에 대한 것으로 필수적으로 알아야 할 내용들을 주로 다룰 것이다.

 

그림 11. NTFS 구조

  위 그림은 NTFS에 대한 전체적인 구조를 나타낸 것이다. VBR을 시작으로 MFT가 존재하고 있으며 그 후 각 파일에 대한 Data가 존재하고 있는 Data Area가 있다. 이들에 대하여 알아보기 전에 클러스터(Cluster)에 대하여 간략히 설명하고자 한다.

   디스크는 기록을 할 때 Sector 단위로 한다. 하지만 NTFS 운영체제는 Cluster 단위로 기록을 하는 것으로 이 두 사이에 차이가 난다. 이러한 Cluster Size는 볼륨의 크기에 따라 주로 결정되며 기본적으로 2GB이상이라면 Cluster Size는 4 KB이다.

  

3.1 VBR

  VBR은 Volume Boot Record의 약자로 해당 볼륨의 부팅을 위한 영역이다. 여기서 우리가 주로 보아야 할 부분은 바로 보라색으로 나타나있는 BPB 부분이다. 해당 부분엔 많은 시스템에 대한 많은 정보들이 포함되어 있다. VBR의 구조는 아래의 그림과 같다.

그림 12. VBR 구조

 

  BPB엔 섹터의 크기나 클러스터의 크기를 포함하고 있으며 이 문서에서 가장 중요하게 다루는 MFT의 시작 위치가 있다. 그렇기에 이 부분의 몇 가지 항목만 올바르게 해석할 수 있다면 된다.

그림 13. BPB 구조

 

  우선 Bytes Per Sector와 sec per Clus라 되어 있는 부분은 각 각 섹터의 크기와 클러스터의 크기를 나타낸다. 만약 사용자가 그 값을 윈도우를 설치할 때 지정해주었다며 다를 수 있으므로 반드시 저 부분의 값도 확인을 해야 한다.

 그 다음 확인해야 할 중요한 사항은 바로 0x30에 위치한 Start Cluster for $MFT로 MFT의 첫 번째 Entry가 시작되는 클러스터의 번호를 담고 있다. 아래 예에선 MFT의 시작 위치가 C0000 Cluster임을 확인할 수가 있다. 따라서 해당 오프셋은 클러스터의 크기인 8 섹터와 섹터의 크기 512Bytes를 곱해주면 된다. 따라서 0xC0000000이 해당 오프셋이라는 것을 알 수가 있다.

그림 14. Start Cluster for $MFT

  해당 오프셋으로 이동하면 MFT의 Signature인 'FILE' 문자열을 확인할 수가 있다. 따라서 올바르게 값을 해석했다는 것을 알 수가 있다.

그림 15. $MFT Signature


3.2 VBR – Python

  그렇다면 Python을 통해서 VBR을 접근해보자. 그 뒤 필요한 항목을 어떻게 설정해야 하는지 확인해보자. 우선 '논리 디스크' C:를 위 그림 6에서의 방법과 동일하게 열어보자.

그림 16. Python – open C:

  여기서부턴 해당 디스크를 Bytearray를 통해서 읽을 것이다. 아까와 같이 올바르게 NTFS 문자열이 출력되는 것을 확인할 수가 있다. 이에 더해 한 가지 함수를 먼저 만들어보자. 만들고자 하는 함수는 Little Endian으로 되어있는 16진수 값을 10진수로 읽어 값을 반환해주는 함수로 이후에 계속 사용될 것이다.

그림 17. Python – LtoI()

 

  VBR에서 우리가 알아야 할 값은 총 3개이다. 섹터의 크기, 클러스터의 크기, 그리고 마지막으로 MFT Entry의 시작위치이다. 이 3개를 알아야 이후에 MFT에 대하여 Python을 통해 분석을 올바르게 할 수가 있다.

  섹터의 크기는 VBR에서 0x0B~0x0C에 위치해 있으며, 클러스터의 크기는 0x0D에 있는 것을 BPB구조에서 확인할 수가 있었고 MFT는 0x30에 해당 클러스터의 값이 있다. 이제 이를 Python으로 입력해보자.

그림 18. Python – Sector

  위의 그림과 같이 섹터의 크기는 512 Bytes(0x200)이며 클러스터의 크기는 8 섹터(4KB)임을 알 수가 있다. 이제 이 값을 가지고 MFT의 위치를 알맞게 해석할 수 있다. 아래의 그림을 보자.

그림 19. Python – MFT Offset

  MFT의 첫 번째 Entry의 Offset이 0xC0000000임을 Python을 통해 해석할 수가 있었다. 이제 VBR에서 우리가 더 확인해야 할 항목은 없으므로 이제 MFT에 대하여 학습해보자.



4. MFT


  VBR을 통해 MFT의 위치를 찾을 수가 있었다. MFR는 Master File Table의 약자로 NTFS에선 파일이나 디렉터리, 메타 정보들을 모두 파일의 형태로 관리하고 있다. 이러한 각 파일들의 위치나 속성, 이름, 크기 등의 메타 정보가 MFT Entry에 저장된다.

  따라서 이러한 많은 정보들이 저장된 MFT를 통해 Forensic 조사에 있어서도 많은 유용한 정보들을 제공한다. 그렇기에 MFT에 대하여 이해 한다는 것은 많은 이점을 갖게 되는 것과 같다. MFT가 갖는 각 Entry에 대한 설명은 아래와 같다.

그림 20. MFT Entry 정보

  많은 유용한 Entry들이 존재하지만, 모두 다루기엔 많은 분량이 나오므로 이 문서는 $MFT에 한정하여 설명할 것이며 추가적으로 필요한 내용에 한해서만 다룰 것이다. MFT Entry의 구조는 아래의 그림과 같다.

그림 21. MFT Entry 구조

    MFT Entry 헤더가 오고 그 다음 Fixup Array가 나온다. 그 다음 가장 중요한 속성이 나오고 End Marker와 함께 뒤 부분은 사용되지 않는다. 이에 대하여 알아보자.

  

4.1 MFT Entry Header

  MFT Entry 헤더는 Signature('FILE')로 시작하여 많은 정보들을 담고 있다. 이 문서는 MFT 수집 툴을 만드는 것이 목적이므로 많은 내용은 다루지 않을 것이다. 전체적인 구조는 아래의 그림과 같다.

그림 22. MFT Entry Header 구조

  여기서 우리가 알아야 할 항목은 0x14에 위치한 'Offset to File Attribute' 항목이다. 이 항목은 속성이 시작하는 위치를 나타내주는 값으로 MFT 수집 툴을 만들기 위해선 이러한 속성 중 $DATA에 접근하여야 한다. 이에 대해선 좀 더 뒤에서 다룰 것이다.

그림 23. HxD - MFT Entry Header

  위의 그림과 같이 0x14에 있는 값이 현재 0x38로 나타나는 것을 확인할 수 있다. 이는 0x38의 위치부터 속성이 시작된다는 것으로 그림에선 0x10이 존재하고 있다. 이는 $STANDARD_INFORMATION(이후 $SIA라 하자.)의 속성 ID 값으로 4.6에서 알아보자.

  

4.2 MFT Entry – Python

  MFT Entry 헤더의 구조에 대하여 알아보았다. 이제 이를 Python을 통해 접근하는 방법에 대하여 살펴보자. 우선 우리는 그림 19에서와 같이 VBR을 통해 MFT의 첫 번째 Entry 주소를 알 수가 있었다. 이제 이를 통해 포인터를 이동시켜보자.

그림 24. Seek(MFT_Offset)

  Seek()함수를 통해 파일을 읽을 위치를 이동 시킬 수가 있다. 우리는 현재 MFT Entry 정보를 읽을 것이므로 이전에 선언했던 mft_off 또는 그 위치 값인 0xc0000000으로 이동을 한 후 해당 부분을 512 Bytes 읽은 것이다.

 

그림 25. Attribute Offset

  512 Byte를 읽은 다음 속성이 위치한 곳의 주소를 얻기 위하여 mft_attribute_off를 선언해주고 0x14-0x15의 값을 읽는다. 또 MFT Entry의 크기를 확인하므로 속성의 시작과 끝을 알 수가 있고, 이러한 속성의 데이터를 attr_off로 지정해놓은 것이다.

  이제 속성의 시작 위치를 알 수가 있으므로 우리는 $DATA를 찾아야 한다. 이를 찾기 위해선 각 속성의 식별 값을 확인을 할 것이며 만약 $DATA의 식별 값인 0x80이 아니라면 해당 속성의 크기를 통해 다음 속성으로 넘어 갈 수가 있다.

그림 26. Find $DATA

  여기서 3번째 라인을 보면 속성 값이 아닌0x0000(NULL)이나 0xFFFF(EndMarker)가 읽히면 해당 루프를 빠져 나오는 것을 확인할 수가 있다. 속성 식별 값이 0x80이 아니라면 해당 속성의 size를 구해 그 만큼을 건너 띄는 것을 아래의 2줄을 통해 확인할 수가 있다. 만약 0x80($DATA)이라면 아직 지정하지 않은 Data_parse()라는 함수를 호출해 $DATA 속성을 분석할 것이다. 이에 대해선 속성에 대하여 알아본 뒤에 다시 해보자.

  

4.3 Attributes

  하나의 MFT Entry는 여러 개의 속성을 포함하고 있다. 이러한 속성엔 각 항목에 따라 유용한 정보들을 가지고 있으므로 이를 해석할 수 있어야 한다. 이러한 속성에 대한 설명은 아래의 그림과 같다.

그림 27. 속성 정보

  많은 속성 항목들이 있지만 모두가 중요한 것은 아니다. 크게 가장 많이 사용되는 항목은 $SIA와 $FILE_NAME(이후 $FN), 그리고 $DATA 항목이다. 우선 이러한 속성의 공통적인 구조 먼저 알아보자.

그림 28. 공통 속성 헤더

  속성의 구조는 거주 속성과 비거주 속성으로 나뉘어 지는데, 이에 대해 알기 전에 공통적을 포함되는 공통 속성 헤더에 대하여 알아보자. 구조는 위의 그림 25와 같이 되어 있다. 공통 속성헤더를 통해 어떠한 속성타입인지, 해당 속성의 길이가 얼마나 되는지, 만약 속성이 이름을 갖는다면 그 이름이 무엇인지 등이 있다. 여기서 속성 이름이란 $SIA나 파일 이름이 아닌, 속성 자체에 부여되는 이름을 뜻하는 것이다. 이러한 공통 속성 헤더 다음엔 거주 속성, 비거주 속성인지에 따라 다른 구조를 갖는다.

  

4.4 거주 속성 (Resident Attribute)

  거주 속성은 해당 속성의 내용이 크지 않기에 MFT Entry 구조에 모두 담을 수 있을 때의 갖는 상태이다. 속성 내용을 모두 담을 수 있기에 다른 곳을 보지 않아도 되며, 그 내용은 거주 속성 헤더 뒤에 나타난다. 이러한 거주 속성의 구조는 아래의 그림과 같다.

그림 29. 거주 속성 헤더

  속성 내용의 크기와 속성 내용의 위치, 인덱스 플래그, 마지막으로 속성의 이름이 있다면 그 속성의 이름이 나오며 없을 경우 바로 속성 내용이 나온다. 아래의 그림은 $MFT의 속성 부분을 나타낸 것이다.

그림 30. HxD - 거주 속성

  공통 속성 헤더를 제외하고 0x48부터 거주 속성 헤더가 존재하는 것을 확인할 수가 있으며 해당 속성은 이름이 존재하지 않기 때문에 바로 뒤에 속성내용이 따라오는 것을 확인할 수가 있다. 이렇게 거주 속성의 구조에 대하여 확인할 수가 있으며, 이러한 거주 속성은 대부분의 $SIA와 $FN에서 나타난다.

  

4.5 비거주 속성 (Non-Resident Attribute)

  속성 내용이 너무 커진다면 그것을 한곳에 모두 담을 수가 없다. 이러한 상태가 바로 비거주 상태라 하게 되며 이 경우 별도의 클러스터를 할당하여 그 곳에 내용을 담아 놓는다. 아래의 그림을 통해 구조를 확인해보자.

그림 31. 비거주 속성 구조

  공통 속성 헤더가 나온 뒤 VCN이나 런리스트, 속성 내용의 크기, 속성 이름과 속성내용 등 관련된 내용들이 기록되어 있다. 이 항목들 중 자세히 알아볼 내용은 런리스트에 관한 내용이다.

  비거주 속성은 속성 내용이 크기 때문에 외부 클러스터에 해당 내용들을 담고 있다. 하지만 이러한 클러스터들이 모두 연속적으로 존재할 수는 없기에 이러한 클러스터들에 대한 정보를 담고 있는 런리스트가 필요하다. 즉, 런리스트는 속성 내용을 담은 클러스터가 어디에 위치하였는지를 알려주기 위한 것이라 할 수 있다.

 

그림 32. Run List

  런리스트를 해석하는 방법의 위의 그림과 같다. 첫 바이트를 읽어 일의 자리 수와 십의 자리수로 나눈다. 그 다음 일의 자리 수만큼 뒤의 바이트를 읽고 이것이 해당 클러스터의 길이가 된다. 십의 자리 수만큼 바이트를 이어 읽으면 해당 클러스터의 위치 값을 알 수가 있다. 이해하기 쉽게 직접 해석해보자.

그림 33. Run List

  위의 그림은 내 PC의 MFT Entry 중 비거주 속성의 런리스트를 나타낸 부분이다. 검은색 동그라미가 첫 바이트이며, 붉은 색은 런의 길이, 파란 색은 런의 위치를 나타내기 위해 표시해놓은 것이다.

  첫 번째 런의 첫 바이트는 '33'이다. 이를 십의 자리와 일의 자리로 나누면 십의 자리는 각 각 '3'이 된다. 따라서 둘 다 3바이트씩 읽은 것이다. 이를 해석하면 C00000 클러스터에서부터 C820개의 클러스터가 할당되어 있음을 나타내는 것이다.

  두 번째 런은 앞과 유사하므로 생략하고 세 번째 런을 보자. 십의 자리가 '4' 일의 자리가 '2'임을 알 수가 있다. 따라서 런 길이는 2바이트를 읽어 0x308이며 런 위치는 4바이트를 읽어 124727B 클러스터이다. 이렇게 런리스트를 해석하면 비연속적으로 저장된 데이터를 올바르게 찾아갈 수가 있다.

  이를 찾아갈 때 고려해야 할 것은 2번째 런부턴 앞의 이전의 런위치를 더해야 한다는 것이다. 2번째 런을 예로 들면 런 위치가 57E23D 번째 클러스터에 있음을 알 수가 있는데, 정작 57E23D 클러스터를 확인해보면 올바르지 않게 되어 있다. 올바르게 찾아가기 위해선 57E23D에 C0000을 더해야 한다. 따라서 63E23D 클러스터에 올바른 속성 내용이 위치하고 있다는 것이다.

  이러한 비거주 속성은 보통 파일의 크기가700Bytes 보다 더 클 경우에 속하게 되며 이보다 작을 경우엔 거주 속성이 된다. 주로 $DATA의 경우 비거주 속성을 띄는 경우가 많으며 우리가 목적으로 하는 $MFT 또한 이러한 비거주 상태에 속하므로 클러스터 런을 올바르게 해석할 수 있어야 한다

  

4.6 Attribute - $SIA, $FN, $DATA

 

$STANDARD_INFORMATION

  $SIA는 $FN과 같이 모든 MFT Entry에 기본적으로 포함되는 속성으로 파일의 시간 정보와 파일에 대한 정보 등이 기록되어 있다. 전체적인 구조는 아래와 같다.

그림 34. $SIA 구조

 

$FILE_NAME

  $FN은 해당 MFT Entry가 가리키고 있는 파일에 대한 이름을 포함하여 $SIA에도 있었던 시간 정보들이 존재한다. 하지만 $SIA의 시간정보에 비해 상대적을 변경 되는 경우가 적다. 이에 대해선 나중에 더 자세히 학습하자. $FN의 구조는 아래와 같다.

그림 35. $FN 구조

 

$DATA

  마지막으로 알아볼 $DATA 속성에 대해선 조금 더 자세히 알아보자. 위의 두 가지 항목은 파일에 대한 정보를 나타내는 것이었다면 $DATA는 해당 파일의 실제 내용으로 앞의 두 개와 마찬가지로 중요한 속성이다. 우선 구조를 먼저 살펴보자.

그림 36. $DATA 구조

  구조가 상대적으로 매우 단조로워 보인다. 만약 $DATA 속성의 크기가 작다면 속성 헤더(공통헤더와 거주속성헤더) 뒤에 바로 속성 내용이 나오게 된다. 하지만 만약 속성의 크기가 커지면 비거주 상태가 되어 위에서 살펴본 바와 같이 클러스터 런을 통해 속성 내용을 관리한다.

 만약 $DATA 속성이 2개라면 어떻게 될까? 이것이 바로 ADS다. 기존의 메인 스트림 외에 대체 스트림이 하나 더 주어지는 것으로 이 경우 반드시 속성 이름이 주어진다. 이를 통해 추후에 $UsnJrnl:$J를 분석할 때 참고할 수가 있을 것이다.

  이번 문서의 목적은 Python을 통해 $MFT를 수집하는 것이므로 일반적으로 크기가 큰 $MFT가 많기 때문에 대부분 비거주 상태에 있다. 따라서 이러한 $DATA의 클러스터 런을 잘 해석할 수가 있어야 할 것이다.

  

4.7 $DATA - Python

  올바르게 속성 식별 값 0x80($DATA)를 찾았다면 이제 해당 부분을 분석하여 정보를 추출을 위한 정보를 알아내야 한다. 우선 Runlist의 위치와 해당 버퍼를 담아보자. 아래의 그림에서와 같이 $DATA의 구조를 읽어 런리스트의 위치와 런리스트부터의 버퍼를 담고 있는 것을 확인할 수가 있다.

그림 37. $DATA 분석 – Python

  $MFT의 $DATA 속성의 경우 비거주 속성을 가질 수 밖에 없다. $MFT가 700바이트 이하의 크기를 갖기는 많이 어렵기 때문이다. 런리스트를 반복문을 통해 분석하기 전에 필요한 변수들을 먼저 선언해주자.

그림 38. 변수 선언

  Count와 tmp, calc, add_offset 등은 반복문에서 대부분 첫 번째 런을 위하여 존재하는 것이며 clu_size와 clu_off, tmp_size와 tmp_offset은 런을 해석한 결과를 담기 위해 미리 리스트(배열)을 선언해놓은 것이다. 이제 반복문을 통해 분석을 진행해보자.

그림 39. 반복문 – 분석

  2번째와 3번째 라인은 이전에 선언해놓은 tmp='00'을 십의 자리와 일의 자리로 나누어 계산을 진행하는 것으로 이후에 tmp가 런의 첫 바이트를 읽어 다시금 자리 수를 나누기 위함이다.

  6번째 라인이 런의 첫 바이트틑 읽는 것으로 이후에 clu_size와 clu_off를 위해 몇 바이트씩 읽어야 하는지 나타내기 위해 존재한다. 그 후 tmp_들로 인하여 해당 바이트의 값을 읽고 있는 것이다. 그리고 add_offset을 통해 4.5에서 살펴본 것과 같이 클러스터 런의 오프셋을 더하기 위한 부분이다. 이렇게 반복문이 0x00을 만나 빠져나오면 tmp_에 담겨있는 값을 다시 정리하여야 한다. 이를 위한 코드는 아래와 같다.

그림 40. Tmp 정리

  이전에 tmp에 담겨있는 것을 정리하기 위해 각각 size와 offset을 선언해준다. 그 후 반복문을 통해 클러스터 단위가 아닌 바이트 단위로 나타내기 위하여 tmp의 값에 초반에 구했던 sec과 clu를 곱해준다.

  이렇게 얻어진 값을 통해 기록하고자 하는 파일을 연다. Seek() 함수를 통해 해당 클러스터의 오프셋으로 이동해 사이즈만큼 읽고 이를 기록한다. 이렇게 런의 수만큼 반복이 된다. 최종적으로 완성된 코드를 실행하면 결과는 아래의 그림과 같다.

그림 41. 실행 결과

 

 

 

5. 정리


간단하게 $MFT 수집 도구를 만들고 싶었지만, $MFT를 수집하기 위해선 결코 간단한 지식을 가지고는 수집할 수 없겠다는 것을 여러 번 느끼는 계기가 되었다. 이해했다고 생각했던 것들이 코드를 통해 직접 해보려 하니 낯설기도 하고 더 어렵게 느껴지기도 하였다.

 

그래도 직접 NTFS를 공부하면서 만들어보고자 했고, 결국 만들었음에 매우 흡족하다. 이후엔 $LogFile과 $Usnjrnl:$J까지 한번에 수집해주는 도구를 제작해보고자 한다. 이를 위해선 더 많은 것을 공부해야겠지만 분명 재미있는 공부가 될 것이라 생각한다.

 

 

 

 

참고 자료


해킹대회문제로 배우는 파일시스템.pdf

humanistcpu.blogspot.kr/2013/10/hxd-mbrmaster-boot-record.html ; HxD MBR 구조 분석

cappleblog.co.kr/40; MBR 구조

cappleblog.co.kr/590; MBR 해석

forensic-proof.com/archives/2975 ; 시스템 예약 파티션 관련 내용

forensic-proof.com/archives/357

forensic-proof.com/archives/431

http://home.sogang.ac.kr/sites/gsinfotech/study/study1702/Lists/b10/Attachments/17/20131212_%EC%B9%A8%ED%95%B4%EC%8B%9C%EC%8A%A4%ED%85%9C%EB%B6%84%EC%84%9D.pdf

http://ntfs.com/ntfs-partition-boot-sector.htm

(FP) NTFS.pdf

forensic-proof.com/archives/584



'Forensic > Analysis' 카테고리의 다른 글

문서파일 복사,복사 여부 확인  (3) 2016.01.23
노트북 하드 컴퓨터 연결  (2) 2016.01.03
Tigger Memory Analysis  (0) 2015.12.26
Black Energy 메모리 분석  (0) 2015.12.17
Memory Analysis - CoreFlood  (0) 2015.12.05

USB 자동실행 방지


 USB가 대중화된 시점에 USB를 꽂으면 자동적으로 실행되는 AutoRun을 통해 악성코드가 유포되기도 한다. 이러한 USB 자동실행을 방지하기 위하여 설정하는 방법에 대하여 간략히 알아보자.

 윈도우 + R을 통해 'gpedit.msc'를 입력해주자. 그렇다면 아래와 같은 창이 뜨는 것을 확인할 수가 있다. 여기서 우리가 찾아 들어가야 할 곳은 'Administrative Templatres'이다. 해당 부분에 들어가 윈도우 구성 요소인 'Windows Components'에 들어가 'AutoPlay Policies'에 들어가보자.

 위의 그림과 같이 Turn off Autoplay이 항목이 존재하고 있는 것을 확인할 수가 있다. 저 부분이 바로 AutoRun의 실행 여부를 담당하고 있는 정책 항목이다. 따라서 현재 No라고 설정이 되어 있는 것을 확인할 수가 있으므로 이 부분을 변경해주면 된다.

Not Configured를 Enabled로 변경해주면 USB를 꽂았을때 자동실행이 되는 일은 없게 된다.


'O / S > Window' 카테고리의 다른 글

CSIDL 값  (0) 2016.02.20
Write Protection - Registry Setting  (0) 2016.01.17
Windows 10 _HANDLES_TABLE, _HADNLES_TABLE_ENTRY  (0) 2015.11.09
Control registers - wiki  (0) 2015.11.07
_TEB, _PEB Windows 10  (0) 2015.11.05

개요


컴퓨터를 살 때 많이 고민하는 사항 중 하나가 데스크탑을 살지, 노트북을 살지에 대하여 많은 고민들을 하기도 한다. 이번 포스팅은 필자도 노트북을 쓰는 입장이므로 이에 대해 지식을 함양시키고자 직접 해보았다. 상황은 아래와 같다.

- 기존에 쓰던 노트북이 어떠한 이유에서인지 부팅이 되지 않는다.

- 고치러 가기엔 디스크에서 특정 파일을 빨리 사용해야 한다.

이러한 상황에 있을 때 혹은 유사한 사항에 있을 때 할 수 있는 방법에 대하여 알아보자. 준비물이 몇 가지 필요하다.

준비물 : 대상 노트북, 외장하드, 복구 또는 추출을 하기 위한 정상적인 PC


실습


 필자는 아래와 같이 준비하였다. 노트북은 LG의 XNOTE를 준비하였으며 우측의 외장하드는 엠지텍의 MG25-TERRAN2+COUP을 준비하였다. 외장하드가 필요한 이유는 노트북의 하드 디스크와 크기가 같기에 이를 통해서 연결할 수기 때문이다. 준비된 장치들을 이제 분해하여 보자.

         

 위와 같이 우선 분석 또는 복구를 하고자 하는 노트북의 하드를 먼저 분리 한다. 그리고 아래의 좌측 그림과 같이 외장하드도 분리를 해준다. 여기서 두 하드의 크기가 얼추 맞는지 확인을 간단하게 해준다. 만약 크기가 다를 경우 해당 단자에 꽂히나 한번 해보고 안된다면 해당 포스팅에선 능력 밖이므로 다른 문서를 찾아보자.

         


 아래 좌측의 그림은 엠지텍의 하드를 빼낸 후 남은 본체의 모습이다. 이제 이 곳에 노트북의 하드(TOSHIBA)를 꽂자. 꽂을 때 너무 과하게 힘은 주지 말자 괜히 멀쩡하던 곳도 손상될 수가 있으므로 조심하자. 연결 한 후의 모습은 원래 외장하드를 열었을 때의 모습과 다를 바가 없다.

         


 이렇게 조립한 외장하드를 이제 외장하드의 USB 단자를 통해 분석 또는 복구를 하고자 하는 PC에 연결해보자. 필자는 노트북이 2대이므로 정상적인 노트북 LG그램에 연결을 진행하였다.


 우선 연결이 잘 되었는지 해당 디스크 F:가 생성되는 것을 아래의 그림과 같이 확인할 수가 있었다. 또한 우측의 그림을 통해서 기존의 Disk 0 이 아닌 새로운 Disk 1이 생성된 것을 확인할 수가 있다. 만약 정상적으로 장치 인식이 되지 않는다면 연결 단자나 하드를 조립할 때 제대로 하였는지 다시 한번 확인해보자.

          


연결된 하드를 HxD나 WinHex, FTK Imager 등을 통해 다양한 작업을 할 수도 있으며 실제 외장하드와 같이 디렉터리 안으로 들어가 파일을 가져올 수도 있다. 이러한 방법이 언젠가는 쓸모가 있을 것 같기에 이렇게 포스팅을 해보았다.





'Forensic > Analysis' 카테고리의 다른 글

문서파일 복사,복사 여부 확인  (3) 2016.01.23
NTFS & Python - $MFT Acquisition  (0) 2016.01.07
Tigger Memory Analysis  (0) 2015.12.26
Black Energy 메모리 분석  (0) 2015.12.17
Memory Analysis - CoreFlood  (0) 2015.12.05

NTFS 인덱스


 NTFS에서는 자료들을 빠르게 검색할 수 있도록 인덱스 구조로 관리하고 있다. 이의 대표적인 예가 바로 디렉터리이며 이러한 인덱스의 구조에 대하여 알아보자. NTFS가 인덱스로 관리하는 데이터는 아래의 표와 같다.

 이러한 인덱스 관리 방법으로는 트리를 사용하는데 NTFS에서 사용하는 B 트리의 형태는 아래의 그림과 같다. 루트 노드는 최상위에 존재하며 시작점이 되는 노드이며 하위의 자식 노드를 가질 때 자신보다 왼쪽은 작은 값, 오른쪽은 자신보다 큰 값이 위치한다. 이를 통해 자신보다 낮은 노드를 찾기 위해선 왼쪽으로 가면 되고 높다면 오른쪽으로 가면 되는 편의성을 갖는다.

 위의 그림과 같이 NTFS의 Index Node는 마지막에 노드의 끝을 알려주는 End of Node가 포함되어 있다. 이러한 End of Node를 제외하고 n개의 Index 엔트리를 담는 인덱스 노드가 가질 수 있는 자식의 노드 수는 n+1개가 되며, 위 그림에선 Root Index Node가 담고 있는 Index Entry는 3개 인 것을 알 수가 있다.

 Index Node는 크게 Index Node Header와 Index Entry로 나눌 수가 있다. 인덱스 엔트리의 크기는 가변적이기에 마지막에 End of Node가 필요한 것이다. 이러한 인덱스 노드는 독립적으로 존재하지 않으며 반드시 $INDEX_ROOT속성이나 $INDEX_ALLOCATION 속성에 속해야 한다. 어떤 노드가 $INDEX_ROOT에 속한다면 그 노드는 index의 최상위 노드(Root Index Node)가 되는 것이다. 최상위 노드를 제외하면 다른 모든 노드들은 $INDEX_ALLOCATION 속성에 속하게 된다.

 인덱스 노드가 $INDEX_ROOT 속성에 존재하는 경우 $INDEX_ROOT 헤더가 index node header 앞에 붙고, $INDEX_ALLOCATION 속성에 존재할 경우 Index Record 헤더가 앞에 붙게 된다. 아래의 그림에서 이를 확인할 수가 있다. $INDEX_ROOT에 속한 경우 $INDEX_ROOT 헤더가 붙는 것을 확인할 수가 있으며 그 자식 인덱스 노드들은 $INDEX_ALLOCATION 속성에 속하기 때문에 Index Record 헤더가 붙는 것을 확인할 수가 있다.


구조


 우선 아래의 첫번째 사진은 $INDEX_ROOT에 속한 경우의 구조이며, 아래의 경우 $INDEX_ALLOCATION 속성에 속했을 때의 구조를 나타내고 있다. 두 그림에서와 같이 공통적으로 Index Node Header를 포함하고 있으며 해당 헤더 앞에 각 각 Index Root Header와 Index Record Header가 오는 것을 확인할 수가 있다. 우선 공통적으로 나타나는 Index Node Header의 구조와 Index Entry의 구조에 대하여 먼저 살펴보자.


INDEX NODE HEADER

• Offset to Start of index entry list : 인덱스 엔트리 목록의 시작 위치(첫번째 Index Entry가 있는 위치 값)

• Offset to Endof used portion of index entry list: 인덱스 엔트리의 실제 크기(인덱스 노드 헤더 포함)

• Offset to end of Allocated index entry list buffer : 인덱스 엔트리의 할당 크기(인덱스 노드 헤더 포함)

• Flags

0x00: 인덱스 노드의 자식노드가 없음        0x01: 인덱스 노드의 자식노드가 있음

 Flag를 제외하고 어떤 크기나 위치를 담는 항목으로 해당 인덱스 노드가 담고 있는 Index Entry 중 하나라도 자식을 가진다면 Flags 항목 값은 1로 설정이 된다. 이와 똑같은 의미를 갖는 Flag가 각각의 Index Entry에도 존재하고 있다. 위 4개의 항목 중 2번째와 3번째 항목의 값을 통해 Index Node에서 삭제된 Index Entry의 정보를 조사할 수 있다. 아래의 그림과 같이 실제 크기와 할당된 크기의 차이를 통해서 확인할 수가 있다.


INDEX ENTRY

•File Reference Address for filename : 해당 파일 및 디렉터리의 파일 참조 주소

•Length of this entry : 해당 인덱스 엔트리의 총 크기

•Length of content : 해당 인덱스 엔트리가 담고있는 $FINE_NAME 속성의 크기

•Flags 

0x01: 자식 노드가 존재         0x02: 노드의 마지막 엔트리(End of Node)

•VCN of child node in $INDEX_ALLOCATION 

해당 인덱스 엔트리가 자식노드를 가지는경우 $INDEX_ALLOCATION 속성에 위치한 자식 인덱스 노드의 위치

 위에서 $FILE_NAME Attribute가 되어 있는 이유는 해당 크기가 가변적이기도 하며 End of Node에선 이 항목이 생략되어 있기 때문이다. 마지막 항목의 경우 해당 인덱스 엔트리가 자식 노드를 가질 경우에 이 항목이 존재하는 것으로 이 항목의 위치를 알아내는 방법은 2번째 항목인 'Length of this entry'에서 -8을 하면 된다. 이를 통해 얻은 VCN 값은 $INDEX_ALLOCATION 속성에 담겨 있는 자식 Index Node의 위치 값이다.


INDEX_ROOT Header

•Type of attribute in index : 인덱스 엔트리가 담고 있는 속성 식별값(디렉터리의 경우0x30, $FILE_NAME)

•Collation sorting rule : 인덱스 엔트리가 담고 있는 형식(형식에맞게정렬됨)

0x00: Binary / 0x01: File Name / 0x02: Unicode String / 0x10: Unsigned Long /

0x11: SID / 0x12: Security Hash / 0x13 : Multiple Unsigned Logs

•Size of each index record in bytes : $INDEX_ALLOCATION 속성이 가지는 인덱스 레코드의 바이트 크기

•Size of each index record in Clusters : $INDEX_ALLOCATION 속성이 가지는 인덱스 레코드의 클러스터 크기

 해당 속성은 인덱스의 최상위인 루트에 해당하는 인덱스 노드를 담는 속성으로 인덱스 크기가 작으면 $INDEX_ROOT만으로 인덱스를 구성하고자 한다. 이 경우 거주(Resident) 형식이기 때문에 많은 Index Entry를 담지 못한다. 크기가 점차 커지므로 모두 담지 못할 경우 $INDEX_ALLOCATION 속성을 만들어 커진 인덱스를 관리한다. $INDEX_ALLOCATION 속성이 생기면 Index Record의 할당을 관리하기 위한 $BITMAP 속성도 같이 생긴다.


INDEX RECORD HEADER

•Signature : $INDEX_ALLOCATION의 시그니처(“INDX”)

•Offset to Fixuparray : Fixuparray의 위치

•Number of entries in Fixuparray : Fixuparray에 저장된 항목의 수

•$LogFileSequence Number (LSN) : $LogFile에 존재하는 해당 파일의 트랜잭션 위치 값

•The VCN of this record in the full index stream : $INDEX_ALLOCATION에서 해당 인덱스 레코드가 저장된 위치- Index Record의 시작 VCN

 최상위 인덱스 노드를 제외한 모든 인덱스 노들들은 이 속성에 담기게 된다. 이 속성의 내용은 Index Record라는 구조체들로 구성되며 하나의 Index Record는 하나의 Index Node를 담고 있다. 아래의 그림과 같이 Index Node의 구조는 $INDEX_ROOT의 속성안에 담기는 것과 동일하며 Index Node가 $INDEX_ALLOCATION 속성에 존재할 경우 Index Record라는 구조 안에 존재하게 된다는 것이다.

 마지막 항목의 시작 VCN은 해당 Index record가 $INDEX_ALLOCATION 속성 데이터 내에서 어느 부분에 존재하는지를 알 수 있도록 해주는 항목이다. VCN과 관련하여 아래의 그림을 참고하자.


$BITMAP

 인덱스 레코드의 할당 상태를 관리하기 위한 속성으로 위와 같은 할당 정보를 표현한다. 할당 정보를 관리하는 데이터로는 $MFT와 $INDEX_ALLOCATION이 있으며 위의 그림과 같은 구조를 지닌다. 아래의 그림과 같이 되어있을 경우 1번째와 3번째 MFT Entry가 현재 사용중임을 나타낸다.




정리


 NTFS가 인덱스를 관리할 때 3가지 속성을 사용한다고 이야기 하였다. $INDEX_ROOT 속성은 최상위 Index Node를 담고 있는 속성으로 이 속성만으로 구성이 될 수 있는데 이는 '작은 인덱스'라 한다. Index Entry가 너무 적어서 $INDEX_ROOT 속성만으로 충분하기 때문이다. 작은 인덱스의 구조는 아래의 그림과 같다.

 이에 반해 $INDEX_ROOT 뿐만이 아니라 $INDEX_ALLOCATION, $BITMAP 모두 갖춘 인덱스를 큰 인덱스라 하며, 일반적으로 볼륨에 담겨 있는 대부분의 인덱스가 이러한 형태이다. 위의 작은 인덱스 구조에 다른 파일들이 추가되었을 경우에 대하여 알아보자.

우선 $INDEX_ROOT 속성에 있던 BBB.TXT 파일의 Index Entry가 자식 노드인 것을 알 수가 있으며, $INDEX_ALLOCATION, $BITMAP 속성이 추가된 것을 확인할 수가 있다. $INDEX_ALLOCATION 속성이 관리하는 Index Record 2개가 클러스터를 할당 받아 새로 생성되어 그 안에 Root Index Entry를 가지고 있게 된다. EEEEE.TXT 부분을 보게 되면 파일의 Index Entry 2개가 존재하는데 DOS 형식의 이름을 가지지 않은 파일들은 2개의 Index Entry를 가지고 있게 된다. $Bitmap 속성의 경우 각각의 bit들은 Index Record들과 1대 1로 대응한다.


출처 및 참고

http://blog.naver.com/PostView.nhn?blogId=bitnang&logNo=70184788707&parentCategoryNo=&categoryNo=&viewDate=&isShowPopularPosts=false&from=postView

(FP) NTFS.pdf