과거의 windows나 linux에 fdisk라는 툴이 있었는데, 단위 Harddisk에서 파티션 관련 Operation을 수행하는 툴이였습니다. 보통 일반 유저는 쉽게 다가설 수 없는 내용들로 구성되어 있는데, 왜냐하면 Partition이라는 이론을 알아야 했고, 잘못 설정하는 경우 Disk를 날릴 수 있기 때문에 쉽지 않았습니다.
최근 window에서는 diskpart 혹은 '디스크 관리자'를 통해 fdisk 시절 보다 쉽게 접근할 수 있으며, linux에서는 보통 gparted 툴을 이용해 손쉽게 접근할 수 있습니다.
C:\Windows\system32>diskpart Microsoft DiskPart 버전 6.1.7601 DISKPART> help Microsoft DiskPart 버전 6.1.7601 ACTIVE - 선택한 파티션을 활성으로 표시합니다. DISKPART> |
- 디스크 관리자 실행 화면 (내컴퓨터->오른쪽 클릭->관리->디스크 관리)
- linux의 gparted 실행 화면 ($ sudo gparted) 만일 없는 경우 ($ sudo apt-get install gparted)로 설치 필요
포렌식(위키)은 보통 IT 장치의 정보를 기반으로 수집된 정보를 가지고 사법 기관등에 사건의 증거로 제출하는 과정으로 정의될거 같습니다. 법정에서 증거로 채택되기 위해서는 몇가지 제약사항들이 있습니다. (변경되지 않았음을 보장, 등등등). 일반적으로 보통 디스크의 문제가 되는 PC의 하드 디스크를 Imaging 백업한뒤 해당 File system을 분석하는 과정이 주를 이룰 수 있습니다. 그러기 위해서는 일반적인 OS 제공의 File 접근법이 아니라 Raw Level의 접근법을 따라야 할 때가 있는데, 그 첫번째 단계가 Disk의 Partition 논리를 알아야 하는 것입니다. 혹시나 범죄자가 Disk Partition을 변경/삭제할 수 있으니깐요. Partition에 대한 논리가 이해된 다음 NTFS등 일반적인 File system의 이론으로 진행해야 할거 같습니다.
[ CCL license 조항을 주의하세요. No commercial only 이므로 상업적 용도를 금지합니다.
상업적 용도 사용시 저에게 사전에 알려주세요.]
내부 코드는 class가 있는 C++이지만, 모두 class의 static 함수로 이뤄져 있습니다. 즉, C++이지만 c 형태의 코드로 이뤄져 있습니다. 그러니 조금만 수정하면 c로 porting 가능할 것이므로, driver등에서 쉽게 적용할 수 있습니다.
PartitionInfo는 fdisk 같이 Disk 경로를 입력받아 Partition 정보를 출력합니다. 물론 Read-only로 수행되므로 Partition 정보 설정은 제공되지 않습니다. 그리고, PartitionInfo.sln과 Makefile이 동시에 제공되는데, 이는 하나의 소스 코드로 Windows와 Linux를 모두 지원한다는 뜻입니다. 포렌식 작업 특징상 Linux로 부팅하여 분석해야 할 경우가 발생할 수 도 있는데, 그때를 위해서 Multi-platform/multi-compiler를 지원하게 되었습니다. Linux의 compile은 다음과 같습니다.
# make clean rm PartHelper.o PartitionInfo.o rm PartitionInfo # make g++ -c -O -I/usr/local/include -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -c -o PartHelper.o PartHelper.cpp g++ -c -O -I/usr/local/include -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -c -o PartitionInfo.o PartitionInfo.cpp gcc -o PartitionInfo PartHelper.o PartitionInfo.o # |
실행 Argument는 다음과 같습니다. (windows에서도 동일하게 동작합니다.)
# ./PartitionInfo Usage : PartitionInfo <device> [/d [startsector sectorsize]] <device> Windows : \\.\PhysicalDrive2 Linux : /dev/sda /d : Dump disk to stdout startsector : Begin Sector sectorsize : Dump Sector Length |
즉, HKLM\SYSTEM\CurrentControlSet\services\Disk\Enum에 그 정보가 있습니다.
Linux에서는 /dev/xdx와 같은 형태인데 다음과 같이 그 정보를 가져올 수 있습니다.
$ ls /dev/?d? /dev/fd0 /dev/sda /dev/sdb /dev/sdc /dev/sdd /dev/sde |
다음과 같이 0번 디스크의 파티션 정보를 가져와 보겠습니다.(window)
(cmd.exe를 반드시 마우스 오른쪽 클릭한뒤 '관리자 권한으로 실행'으로 하시기 바랍니다.)
E:\....\>PartitionInfo.exe \\.\PhysicalDrive0 ******* * MBR * ******* > Disk : \\.\PhysicalDrive0 ------------------ * Partition no : 0 ------------------ Boot Type : 1 (ENUM_BOOT_TYPE) Type : 4 (ENUM_PART_TYPE) Seek Pos : 1048576 (Sector : 2048) Size : 31.25 GB (33554432000 Bytes) (Sector : 65536000) ------------------ * Partition no : 1 ------------------ Boot Type : 2 (ENUM_BOOT_TYPE) Type : 4 (ENUM_PART_TYPE) Seek Pos : 33555480576 (Sector : 65538048) Size : 28.37 GB (30465327104 Bytes) (Sector : 59502592) |
Linux에서는 다음과 같습니다.
$ sudo /tmp/PartitionInfo /dev/sdb [Extend] |
그리고, 끝에 /d 옵션을 사용할 수 있습니다. 이는 Disk의 전체 내용을 Hex로 볼 수 있도록 해줍니다. (stdout)
일부만 보고 싶으면, /d 0 1과 같이 하여, 0번 Sector부터 1개의 Sector만 표시하도록 해 줍니다.
만일 linux 환경이라면, # PartitionInfo /dev/sda | gzip -c > /tmp/sda.txt와 같이 압축할 수 있습니다.
Code에 있는 자세한 내용은 이후를 참고하시기 바랍니다.
참고) - Disk도 하나의 '파일'임. 즉, Read/Write/Seek가 가능함 (단, 그 단위는 Sector 크기(512)의 배수여야 함) - Disk 상의 위치를 지정하기 위해서 다음의 정보가 활용됨(Seek) ; CHS 표기법 : C(cylinder)H(header)S(sector) (wiki) ; LBA 표기법 : Logical Block Addressing (wiki) ; CHS <--> LBA 가능. - Disk 상의 논리적 위치 : LBA * Sector의 크기 - Sector의 크기 ; 일반적으로 512bytes ; 2009년 12월부터 Harddisk 제조사는 4KByte Sector의 하드 디스크 소개시작 (wiki, wiki) ; 512byte의 가정이 워낙 오래되어 있어 (BIOS, 부팅 로더, ...) 4KByte로 되어 있는 경우 부팅 불가일 수 있음 ; Harddisk firmware로 부터 512byte로 emulate가능 (wiki) ; 본 블로그 포스트는 Sector의 크기를 512로 가정하고 작업함 |
위 (참고)에 따르면, Disk도 하나의 파일이기 때문에 readme.txt 같은 파일의 Data를 저장할 수 있습니다. 다만, 예를 들어, 200GB가 넘는 저장 공간을 작은 크기의 .txt 하나만 저장하기는 무척이나 아쉽죠. 그래서, 하나의 큰 저장 공간을 여러개의 파일 영역으로 나눠 저장하는 기능을 File system이 담당해 주는데 주로 NTFS나 FAT 그리고 ext등이 있습니다. 그래서, File system은 큰 공간을 파일 갯수만큼 조각을 만들어 처리하는 과정이 있을 것인데, 여기서 중요한 것은, File system은 Disk에 바로 올라가는 것이 아니라 Partition에서 올라간다는 것입니다. 즉, Disk는 몇개의 Partition으로 분리되고 하나의 Partition에 하나의 File system이 올라가게 됩니다. 이를 표시하면 다음과 같습니다.
즉, Partition이 4개로 나눠져 있다면, 각 Partition의 정보(타입/시작위치/크기/...)가 저장된 공간이 필요한데 그것이 바로 MBR입니다. MBR에 대해서는 다음(Wiki)를 참조하시기 바랍니다. 간략히 정리하면 다음과 같습니다.
- 1983년 IBM 호환 PC 시절때 제안되었다.
- Disk의 첫 Sector(512Byte)에 위치함
- BIOS에 의해 부팅될 때 로드되는 Boot strap 코드가 포함됨
- 주(Primary) Partition의 정보 포함(Partition Table)
- Boot signature (0x55 0xaa)
그리고 Patition Table은 다음의 4개의 Primary Partition 정보를 가지고 있습니다.
(이말은 한 Disk에는 4개의 Primary Partition만 가능하다는 뜻입니다.)
- 상태 (부팅 가능한지/활성화 되어 있는지/비 활성화 되어 있는지)
- 시작 위치 (CHS 값, LBA 값)
- Partition Type (NTFS냐? FAT냐? Linux Ext냐? ...)
- 종료 위치 (CHS 값, LBA 값)
- 길이 (Sector 개수)
앞서서 표시된 /dev/sdb Disk의 MBR을 확인하면 다음과 같습니다.
# ./PartitionInfo /dev/sdb /d 0 1 [0000000000] 33 c0 8e d0 bc 00 7c fb 50 07 50 1f fc be 1b 7c 3.....|.P.P....| [0000000016] bf 1b 06 50 57 b9 e5 01 f3 a4 cb bd be 07 b1 04 ...PW........... [0000000032] 38 6e 00 7c 09 75 13 83 c5 10 e2 f4 cd 18 8b f5 8n.|.u.......... [0000000048] 83 c6 10 49 74 19 38 2c 74 f6 a0 b5 07 b4 07 8b ...It.8,t....... [0000000064] f0 ac 3c 00 74 fc bb 07 00 b4 0e cd 10 eb f2 88 ..<.t........... [0000000080] 4e 10 e8 46 00 73 2a fe 46 10 80 7e 04 0b 74 0b N..F.s*.F..~..t. [0000000096] 80 7e 04 0c 74 05 a0 b6 07 75 d2 80 46 02 06 83 .~..t....u..F... [0000000112] 46 08 06 83 56 0a 00 e8 21 00 73 05 a0 b6 07 eb F...V...!.s..... [0000000128] bc 81 3e fe 7d 55 aa 74 0b 80 7e 10 00 74 c8 a0 ..>.}U.t..~..t.. [0000000144] b7 07 eb a9 8b fc 1e 57 8b f5 cb bf 05 00 8a 56 .......W.......V [0000000160] 00 b4 08 cd 13 72 23 8a c1 24 3f 98 8a de 8a fc .....r#..$?..... [0000000176] 43 f7 e3 8b d1 86 d6 b1 06 d2 ee 42 f7 e2 39 56 C..........B..9V [0000000192] 0a 77 23 72 05 39 46 08 73 1c b8 01 02 bb 00 7c .w#r.9F.s......| [0000000208] 8b 4e 02 8b 56 00 cd 13 73 51 4f 74 4e 32 e4 8a .N..V...sQOtN2.. [0000000224] 56 00 cd 13 eb e4 8a 56 00 60 bb aa 55 b4 41 cd V......V.`..U.A. [0000000240] 13 72 36 81 fb 55 aa 75 30 f6 c1 01 74 2b 61 60 .r6..U.u0...t+a` [0000000256] 6a 00 6a 00 ff 76 0a ff 76 08 6a 00 68 00 7c 6a j.j..v..v.j.h.|j [0000000272] 01 6a 10 b4 42 8b f4 cd 13 61 61 73 0e 4f 74 0b .j..B....aas.Ot. [0000000288] 32 e4 8a 56 00 cd 13 eb d6 61 f9 c3 49 6e 76 61 2..V.....a..Inva [0000000304] 6c 69 64 20 70 61 72 74 69 74 69 6f 6e 20 74 61 lid partition ta [0000000320] 62 6c 65 00 45 72 72 6f 72 20 6c 6f 61 64 69 6e ble.Error loadin [0000000336] 67 20 6f 70 65 72 61 74 69 6e 67 20 73 79 73 74 g operating syst [0000000352] 65 6d 00 4d 69 73 73 69 6e 67 20 6f 70 65 72 61 em.Missing opera [0000000368] 74 69 6e 67 20 73 79 73 74 65 6d 00 00 00 00 00 ting system..... [0000000384] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000400] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000416] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000432] 00 00 00 00 00 2c 44 63 32 73 d0 58 00 00 00 01 .....,Dc2s.X.... [0000000448] 01 00 07 cc bd 65 3f 00 00 00 57 76 96 00 00 d2 .....e?...Wv.... [0000000464] ac 65 05 fe ff ff fe 77 96 00 02 80 69 04 00 00 .e.....w....i... [0000000480] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000496] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa ..............U. # |
이러한 전통적인 MBR 방식을 사용하다보면 다음의 한계에 직면하게 됩니다.
- 2 TB 이상의 크기 ==> GPT(wiki)로 해결
; Partition Table에서 개당 Partition 크기에 사용되는 값은 4byte로 주어지는데, 이는 4GB 숫자만큼의 LBA 위치 지정이 가능하다는 뜻임. 4GB * 512 = 2TB, 즉 2TB 만큼의 Paritition 크기가 최대값이 됨. GPT는 기존 MBR 정보를 지원하면서, 수백(주로 128)개의 Paritition을 지원하고, LBA 단위가 8byte이므로 2TB 한계를 극복하게 된다. 단, BIOS에서 지원하지 않는 경우 부팅이 이뤄지지 않을 수 있으며, OS 마다 지원 범위가 다를 수 있다. - 4개 이상의 Paritition 나누기 ==> Extended Partition 혹은 GPT로 해결
; 전통적인 Primary Partition 대신, 확장(Extended) Partition으로 확장하고, 개별 Logical Paritition을 관리한다.
우선 GPT(GUID Partition Table)을 확인하기 전에 Extended Partition 부터 확인해 보도록 하겠습니다.
참고) Disk의 Partition을 실험 작업하다 보면, Disk의 내용을 쉽게 날릴 수 있기 때문에, 되도록이면 VMWare등에서 테스트하는 것을 권장합니다. 혹은 Window같은 경우에는 vhd를 이용하면 보다 쉽게 테스트 할 수 있습니다. (단, 모든 Windows OS에서 지원되지는 않습니다. 저는 Windows 7 Professional K 입니다.) 를 실행하고 "디스크 관리"를 실행합니다. 그리고 기타 작업을 선택하여 "VHD 만들기"를 실행합니다. 와 새로운 .vhd 경로를 선택하여 확인하면, 새로운 볼륨 Disk를 생성할 수 있습니다. 그 안을 보면 _attach.bat와 _detach.bat가 있으며, 이는 mount와 unmount를 의미합니다. 그리고 각각 4개의 파일을 열어서 절대 경로를 입력하도록 합니다. 그다음 .bat를 오른쪽 클릭하여 "관리자 권한 실행"하면 손쇱게 mount와 unmount를 사용할 수 있습니다. |
그럼 다음과 같이 됩니다.
즉, 4번째 Partition 부터는 Logical Partition으로 적용됩니다.
그리고 남아있는 206MB를 다시 아래와 같이 분리합니다.
그리고 PartitionInfo를 실행하여 동일한 결과를 비교해 봅니다.
E:\....>PartitionInfo.exe \\.\PhysicalDrive2 [Extend] E:\....> |
Linux에서는 gparted를 이용하여 구성할 수 있습니다. gparted가 없다면 $ sudo apt-get install gparted로 설치할 수 있습니다. gparted는 처음부터 Extended Partition으로 설정 가능하더군요.
그럼 다음과 같이 Extended Partition이 생성됩니다.
그럼 그 안쪽에 다음과 같이 Partition을 설정할 수 있습니다. (Partition 추가시 File system을 unformatted로 합니다). 그리고 마지막으로 툴바에 있는 v 버튼을 누르면 다음과 같이 적용 됩니다.
$ sudo ./PartitionInfo /dev/sdd [Extend] |
그럼 gparted에서 해당 항목을 더블클릭하면 다음과 같은 정보를 알려줍니다.
First sector에 145408이라고 나오는데, 이는 PartitionInfo에서 "* Absolute Seek Pos : 74448896 (Sector : 145408)"과 동일합니다. 즉, PartitionInfo의 절대값 계산이 올바르다는 것이 확인됩니다.
$ sudo ./PartitionInfo /dev/sdd /d 2048 1 [0000000000] eb 52 90 4e 54 46 53 20 20 20 20 00 02 08 00 00 .R.NTFS ..... [0000000016] 00 00 00 00 00 f8 00 00 20 00 40 00 00 08 00 00 ........ .@..... [0000000032] 00 00 00 00 80 00 80 00 ff 07 01 00 00 00 00 00 ................ [0000000048] 04 00 00 00 00 00 00 00 7f 10 00 00 00 00 00 00 ............... [0000000064] f6 00 00 00 01 00 00 00 3e 7c 22 0f 1b 78 6c 1c ........>|"..xl. [0000000080] 00 00 00 00 fa 33 c0 8e d0 bc 00 7c fb 68 c0 07 .....3.....|.h.. [0000000096] 1f 1e 68 66 00 cb 88 16 0e 00 66 81 3e 03 00 4e ..hf......f.>..N [0000000112] 54 46 53 75 15 b4 41 bb aa 55 cd 13 72 0c 81 fb TFSu..A..U..r... [0000000128] 55 aa 75 06 f7 c1 01 00 75 03 e9 d2 00 1e 83 ec U.u.....u....... [0000000144] 18 68 1a 00 b4 48 8a 16 0e 00 8b f4 16 1f cd 13 .h...H.......... [0000000160] 9f 83 c4 18 9e 58 1f 72 e1 3b 06 0b 00 75 db a3 .....X.r.;...u.. [0000000176] 0f 00 c1 2e 0f 00 04 1e 5a 33 db b9 00 20 2b c8 ........Z3... +. [0000000192] 66 ff 06 11 00 03 16 0f 00 8e c2 ff 06 16 00 e8 f............... [0000000208] 40 00 2b c8 77 ef b8 00 bb cd 1a 66 23 c0 75 2d @.+.w......f#.u- [0000000224] 66 81 fb 54 43 50 41 75 24 81 f9 02 01 72 1e 16 f..TCPAu$....r.. [0000000240] 68 07 bb 16 68 70 0e 16 68 09 00 66 53 66 53 66 h...hp..h..fSfSf [0000000256] 55 16 16 16 68 b8 01 66 61 0e 07 cd 1a e9 6a 01 U...h..fa.....j. [0000000272] 90 90 66 60 1e 06 66 a1 11 00 66 03 06 1c 00 1e ..f`..f...f..... [0000000288] 66 68 00 00 00 00 66 50 06 53 68 01 00 68 10 00 fh....fP.Sh..h.. [0000000304] b4 42 8a 16 0e 00 16 1f 8b f4 cd 13 66 59 5b 5a .B..........fY[Z [0000000320] 66 59 66 59 1f 0f 82 16 00 66 ff 06 11 00 03 16 fYfY.....f...... [0000000336] 0f 00 8e c2 ff 0e 16 00 75 bc 07 1f 66 61 c3 a0 ........u...fa.. [0000000352] f8 01 e8 08 00 a0 fb 01 e8 02 00 eb fe b4 01 8b ................ [0000000368] f0 ac 3c 00 74 09 b4 0e bb 07 00 cd 10 eb f2 c3 ..<.t........... [0000000384] 0d 0a 41 20 64 69 73 6b 20 72 65 61 64 20 65 72 ..A disk read er [0000000400] 72 6f 72 20 6f 63 63 75 72 72 65 64 00 0d 0a 42 ror occurred...B [0000000416] 4f 4f 54 4d 47 52 20 69 73 20 6d 69 73 73 69 6e OOTMGR is missin [0000000432] 67 00 0d 0a 42 4f 4f 54 4d 47 52 20 69 73 00 41 g...BOOTMGR is.A [0000000448] 02 00 83 a7 26 01 00 08 00 00 00 58 00 00 00 a7 ....&......X.... [0000000464] 27 01 05 96 12 04 00 60 00 00 00 b8 00 00 00 00 '......`........ [0000000480] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000496] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa ..............U. $ |
(관련 부분은 PartitionInfo::CPartHelper::GetMbrExtPartInfoAlloc(...) 함수를 참고하시기 바랍니다.)
주요한 정보를 구하는 방법은 다음과 같습니다.
- 다음 EBR의 절대 위치 : 첫 EBR의 위치 + 두번째 Partition 정보의 시작 LBA
- Logical Partition의 절대 위치 : 첫번째 Partition 정보의 시작 LBA + 첫 EBR의 위치
- Linked List의 종료 조건 : 두번째 Partition 정보의 시작 LBA와 크기가 0
위 예에서, ... 00 60 00 00 ... 를 통해 두번째 Partition 정보의 시작 LBA가 0x6000임을 알 수 있습니다. 그리고 첫 EBR의 위치가 0x800(=2048)이기 때문에 0x6800(=26624)로 Jump하면 다음과 같이 또 하나의 다음 EBR이 등장합니다.
$ sudo ./PartitionInfo /dev/sdd /d 26624 1 [0000000000] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000016] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000032] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000048] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000064] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000080] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000096] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000112] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000128] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000144] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000160] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000176] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000192] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000208] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000224] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000240] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000256] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000272] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000288] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000304] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000320] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000336] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000352] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000368] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000384] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000400] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000416] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000432] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c8 ................ [0000000448] 08 01 83 96 12 04 00 08 00 00 00 b0 00 00 00 96 ................ [0000000464] 13 04 05 eb 23 08 00 18 01 00 00 10 01 00 00 00 ....#........... [0000000480] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [0000000496] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa ..............U. $ |
즉, 각 EBR의 첫번째 Partition 정보를 분홍색 화살표, 두번째 Partition 정보를 녹색 화살표로 생각하면, 첫번째 Partition 정보는 해당 Logical Partition의 위치를 알려주며, 두번째 Partition의 정보는 다음 EBR의 위치를 첫 EBR의 상대 위치로 표시한 값입니다. 이를 통해 Logical Partition의 Linked List를 Traverse할 수 있습니다.
GPT는 다음과 같이 MBR에서 부터 전환할 수 있습니다.
즉 "디스크 관리자"에서 "GPT 디스크로 변환"을 실행하면 됩니다.
혹은 아래와 같이 gparted에서도 GPT로 변환할 수 있습니다.
Create Partition Table을 실행합니다.
gpt를 선택하고 Apply하면 바로 적용됩니다.
앞선 디스크 관리자를 통해 5개의 partition으로 나눠진 모습입니다. 더이상의 복잡하던 Extended Partition등은 보이지 않습니다.
gparted도 마찬가지로 다음과 같이 5개의 partition으로 나눌 수 있습니다.
그럼 위 /dev/sdd에 대한 PartitionInfo는 다음과 같습니다.
# ./PartitionInfo /dev/sdd ******* * GPT * ******* > Disk : /dev/sdd ------------------ * Partition no : 0 ------------------ Type : 6 (ENUM_GPT_PART_TYPE) Attrib : 1 (ENUM_PART_ATTRIB) Seek Pos : 1048576 (Sector : 2048) Size : 11.00 MB (11534336 Bytes) (Sector : 22528) ------------------ * Partition no : 1 ------------------ Type : 6 (ENUM_GPT_PART_TYPE) Attrib : 1 (ENUM_PART_ATTRIB) Seek Pos : 12582912 (Sector : 24576) Size : 22.00 MB (23068672 Bytes) (Sector : 45056) ------------------ * Partition no : 2 ------------------ Type : 6 (ENUM_GPT_PART_TYPE) Attrib : 1 (ENUM_PART_ATTRIB) Seek Pos : 35651584 (Sector : 69632) Size : 33.00 MB (34603008 Bytes) (Sector : 67584) ------------------ * Partition no : 3 ------------------ Type : 6 (ENUM_GPT_PART_TYPE) Attrib : 1 (ENUM_PART_ATTRIB) Seek Pos : 70254592 (Sector : 137216) Size : 44.00 MB (46137344 Bytes) (Sector : 90112) ------------------ * Partition no : 4 ------------------ Type : 6 (ENUM_GPT_PART_TYPE) Attrib : 1 (ENUM_PART_ATTRIB) Seek Pos : 116391936 (Sector : 227328) Size : 4.00 MB (4194304 Bytes) (Sector : 8192) # |
앞서 마지막의 4MB의 Partition의 정보를 보면, 227328 sector 부터 시작인데, 위 PartitionInfo에서도 4번 Partition의 Seek Pos도 동일함이 확인됩니다. 그 크기도 8192 sector로 동일합니다. 즉, PartitionInfo를 통해 각 Partition 영역 계산이 올바르게 수행되었음을 확인할 수 있습니다.
그럼 GPT를 그림을 통해 알아 보면 다음과 같습니다.
앞선 MBR이나 EBR과 비교해 단순해 보입니다. 우선, 위 그림의 하나의 사각형은 하나의 Sector입니다. 즉, GPT Header는 512 byte이며, Partition Information Entry 하나는 128 byte입니다. 즉, 과거 MBR의 Partition Table의 개당 정보인 16 byte와 비교해보면 몇배로 커짐을 알 수 있습니다. 그런 이유로, GPT에서 Partition의 크기 정보는 8Byte로 표현되는데, 이는 4GB*4GB가 되며 여기에 512까지 곱하게 되면, 사실상 무한대에 가까운 크기를 표현할 수 있게 되었습니다.
그리고 GPT Header에 Partition Entry 개수가 정의되어 있습니다. 보통은 128로 되어 있으니 총 32개의 Entry Block이 있을 것입니다. 그리고 아래쪽의 Secondary 영역이 있는데, 이는 GPT 정보의 복사본이라 생각하면 됩니다. PartitionInfo에서는 Primary와 Secondary의 각 Entry 정보를 비교하는 검증 코드가 들어 있습니다. 단, 두개의 GPT Header는 내용상 동일하지 않아 지원하지는 않습니다. (GPT Header에 CRC 정보등등이 포함되는데 Primary와 Secondary에서 각각의 값이 다르게 나왔습니다. 향후 해당 CRC 값을 검증하는 코드가 들어가면 좋을 듯 합니다.)
PartitionInfo에는 CPartHelper라는 class가 있는데 해당 class를 가지고 시스템의 Partition 정보를 gathering할 수 있습니다. class로 정의되어 C++일 듯 하지만, 실제로 class는 namespace 적인 용도로만 사용되었을 뿐, 모두 static 함수로 이뤄져 있습니다. 그렇기 때문에 class의 member 변수는 하나도 없습니다. 또한 malloc/free를 사용하였습니다. 결국, 손쉽게 C로 전환할 수 있다는 뜻이며, 이를 통해 시스템 Driver등으로 참조할 수 있음을 알려드립니다. 그리고 마지막으로 Windows Visual C와 Linux의 GCC 모두 Compile되도록 하였습니다.
CPartHelper::DUMP_DISK_INFO(...)를 보면 사용법을 쉽게 확인할 수 있습니다.
[ 기본 함수 군 ]
INT OpenDisk
; lpszDiskName : Disk의 경로 (\\.\PhysicalDrive0, /dev/sda)
; File Descriptor를 리턴함 (-1은 에러)
IN _OFF64_T offset
IN INT whence
; offset은 Sector 크기의 배수이여야 한다. 즉, 512의 배수이어야 한다.
; whence는 SEEK_SET과 같은 값이다.
; 성공 : TRUE / 실패 : FALSE
BOOL GetMbrPartInfo
OPTIONAL OUT LPST_MBR_PART_INFO pstArrInfoSize4
OPTIONAL OUT PBOOL pbGpt
; pstArrInfoSize4 : ST_MBR_PART_INFO의 4개 Array여야 한다. NULL 전달 가능하다.
; pbGpt : 해당 Disk가 GPT 타입인지 전달한다. NULL 전달 가능하다.
; 성공 : TRUE / 실패 : FALSE
OUT _OFF64_T* pnSeekPos
OUT _OFF64_T* pnSize
; ENUM_BOOT_TYPE은 /부트 가능/활성화/비활성화 등의 값을 가진다.
; ENUM_PART_TYPE은 /NTFS/FAT/EXTEND/... 등의 값을 가진다.
; 해당 Partition의 Disk로 부터의 절대 위치를 pnSeekPos로 받고, 그 크기를 pnSize로 구한다.
LPST_MBR_LOGICAL_PART_INFO GetMbrExtPartInfoAlloc
IN UBYTE4 nStartLBA
OUT PINT pnCount
; 해당 Extend Partition의 StartLBA를 전달한다.
; pnCount를 통해 Logical Partition 개수를 구한다.
; ST_MBR_LOGICAL_PART_INFO의 배열을 전달 받는다. 그 개수는 pnCount이다.
; ST_MBR_LOGICAL_PART_INFO는 Primary Partition 정보에서 Disk상 절대 위치 값이 하나만 추가됨.
LPST_GPT_PART_ENTRY GetGptPartAlloc
OUT PINT pnAllocCount
; pnAllocCount를 통해 GPT Partition의 개수를 전달 받는다.
; GPT Partition의 정보인 ST_GPT_PART_ENTRY의 배열을 전달 받는다.
OUT _OFF64_T* pnSeekPos
OUT _OFF64_T* pnSize
; GPT partition 정보를 가지고 Disk 상의 절대 위치와 크기를 구한다. (pnSeekPos, pnSize)
; GPT partition 정보를 가지고 속성을 구한다. (시스템/Bootable/Readonly/Hidden/No automount)
'Research > Forensic & NTFS' 카테고리의 다른 글
[ntfs forensic 강좌] 2. ntfs layout(개요) (0) | 2013.07.18 |
---|---|
[ntfs forensic 강좌] 1. ntfs 기본 (file, file record, inode, attribute) (0) | 2013.07.14 |
ntfs parser (ntfs parsing, analysis, c, c++) (ntfs 파싱, 분석, VC++ 9.0) (0) | 2013.06.03 |