지난 번에는 섹터 위치를 입력받아서 해당 섹터를 출력하는 프로그램을 구현하였다. 이번에는 기존 코드를 조금 수정해서 사용자가 표시된 메뉴 중에서 원하는 것을 사용할 수 있도록 선택하도록 하였다.
New!) 파티션 보기 기능
옵션에는 1. 섹터 정보, 2. 파티션 보기 3. 종료가 있다.
파티션 보기를 가장 마지막에 추가하였는데, 저 부분에서 가장 애를 먹었다. (과제 하기 시러잉....)
파티션 테이블은 각각 16 바이트씩 4개의 엔트리를 가지고 있는데, 4번째 파티션이 확장 파티션이라면 LBA주소로 이동해서 다른 섹터에 있는 파티션을 읽어오는 것이다. 하나의 하드디스크에 파티션을 4개까지 생성할 수 있기 때문에, 4개 이상의 파티션을 사용하기 위해서는 확장 파티션에 논리 파티션을 생성하면 된다.
Partition Table Entry
Boot Strap Code와 Signature는 딱히 분석할 게 없기 때문에 파티션 테이블 부분을 분석할 것이다.
Boot Flag (1 byte) : 0x08 (부팅 가능), 0x00 (부팅 불가)
Starting CHS Address (3 byte) : CHS 시작 주소. CHS 주소 방식은 이제 사용되지 않음
Patition Type (1 byte) : 0x07 (NTFS), 0x0B, 0x0C (FAT32), 0x05 (Extended Partition)
Ending CHS Address (3 byte) : CHS 끝 주소. CHS 주소 방식은 이제 사용되지 않음
Starting LBA Address (4 byte) : LBA 시작 주소
TotalSector (4 byte) : 파티션의 총 섹터 개수
파티션 16바이트는 위와 같이 구성된다.
forensic.cpp
#pragma warning(disable:4996)
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
// 파티션 구조체
struct PartitionINFO {
unsigned char bootindi; //1
unsigned char startCHS[3]; //3
unsigned char partype; //1
unsigned char endCHS[3]; //3
int startLBA; //4
int totalsec; //4
};
struct PartitionINFO p[10];
// 그냥 파티션 출력
int Partition_Read(FILE *fp) {
unsigned char byte[16];
int i, j, ch;
int ADDR;
fseek(fp, 446, SEEK_SET);
int part_count = 3;
int ch2;
int first_arr;
int arr;
int LBA_extd;
for (i = 0; i < 3; i++) {
printf("partition%d : ", i + 1);
fread(byte, 1, 16, fp);
for (j = 0; j < 16; j++) {
printf("%02X ", byte[j]);
}
printf("\n");
memcpy(&p[i], byte, 16);
}
int lba_ch = 0;
int lba_ch2 = 0;
// 여기부터 4번째
while (1) {
fseek(fp, 4, SEEK_CUR);
ch2 = fgetc(fp);
//printf("ch : %02X\n",ch2);
fseek(fp, -5, SEEK_CUR);
// 확장 파티션인지 확인
if (ch2 == 05) {
// 확장 파티션이면 LBA 주소를 구해서 이동
part_count++;
fseek(fp, 8, SEEK_CUR);
fread(&arr, 1, 4, fp);
// printf("arr : %d\n\n",arr);
LBA_extd = arr;
if (lba_ch == 0) {
lba_ch = LBA_extd; //확장 파티션 LBA 주소
lba_ch2 = lba_ch;
}
else {
lba_ch2 = lba_ch + LBA_extd;
}
if (part_count == 4) {
first_arr = arr * 512;
arr = 0;
}
int LBAaddr = first_arr + (arr * 512) + 446;
// printf("LBAaddr : %d\n", LBAaddr);
fseek(fp, LBAaddr, SEEK_SET);
printf("partition %d : ", part_count);
fread(byte, 1, 16, fp);
for (int k = 0; k < 16; k++) {
printf("%02X ", byte[k]);
}
printf("\n");
memcpy(&p[i++], byte, 16);
p[i - 1].startLBA = lba_ch2 + p[i - 1].startLBA;
// p[i-1].startLBA += LBA_extd;
}
else {
printf("\n\n");
printf("섹터 출력 끝\n\n");
break;
}
}
for (int i = 0; i < 6; i++) {
printf("[partition %d]\n", i+1);
printf("bootindi : %02X\n", p[i].bootindi);
printf("startCHS : %X\n", p[i].startCHS);
printf("partype : %02X\n", p[i].partype);
printf("endCHS : %X\n", p[i].endCHS);
printf("startLBA : %d\n", p[i].startLBA);
printf("totalsec : %d\n", p[i].totalsec);
printf("\n\n");
}
return 0;
}
int main(void) {
FILE *fp=NULL;
int j, i, ch;
int offset = 0;
int s = 0;
char pp[20];
pp[19] = '\0';
int jump = 0;
int cur_sec = 0;
int size = 0;
int sector_num;
char filename[100];
int num;
while (1) {
printf(" 1. 파일 열기\n");
printf(" 2. 섹터 정보\n");
printf(" 3. 종료\n");
printf(" 4. 파티션 \n\n");
printf(" [ 이외의 키를 누르면 섹터출력으로 이동합니다 ]");
printf("\n\n");
printf(" 입력 : ");
scanf("%d", &num);
system("cls");
if (num == 1) {
printf(" 파일 경로 입력 : ");
scanf("%s", &filename);
if ((fp = fopen(filename, "rb")) == NULL) {
printf("File Open Error!");
}
else {
printf("\n");
printf(" 파일 오픈 성공!\n\n");
fseek(fp, 0, SEEK_END); // 파일 포인터를 파일의 끝으로 이동시킴
size = ftell(fp); // 파일 포인터의 현재 위치를 얻음
sector_num = (size / 512);
fseek(fp, 0, SEEK_SET);
}
} // num==1
else if (num == 2) {
if (sector_num < 1) {
printf(" 파일 오픈을 해주세요!\n\n");
continue;
}
else {
printf(" 섹터 개수 : %d\n", sector_num);
}
} // num==2 (섹터개수)
else if (num == 3) {
system("cls");
printf(" ㅂㅇ\n");
break;
} // num==3 (종료)
else if (num == 4) {
if (sector_num < 1) {
printf(" 파일오픈을 해주세요!\n\n");
continue;
}
else {
Partition_Read(fp);
}
} // num==4 (파티션)
else {
// 선택한 섹터 위치 512 바이트 출력
system("cls");
if (sector_num < 1) {
printf(" 파일 오픈을 해주세요!\n\n");
continue;
}
printf(" 섹터 위치(0~%d) : ", sector_num);
scanf("%d", &cur_sec);
for (int k = 0; k < cur_sec; k++) {
offset += 512;
}
fseek(fp, offset, SEEK_SET);
printf("offset(h) ");
for (s = 0; s < 16; s++) {
printf("%02X ", s);
}printf("\n\n");
for (i = 0; i < 32; i++) {
printf("%08X ", offset);
offset += 16;
for (j = 0; j < 16; j++) {
if ((ch = fgetc(fp)) != 'EOF') {
printf(" %02X", ch);
if (int(ch) <= 15 || int(ch) >= 127) {
pp[j] = '.';
}
else {
pp[j] = char(ch);
}
}
}printf(" %s\n", pp);
} // 바이트 출력 끝
printf("\n\n");
fclose(fp);
return 0;
}
}
}
프로그램 실행 화면
파일 경로를 입력하면 파일 오픈 성공 or 실패했다는 메세지가 뜬다. 파일 오픈에 실패 했을 경우 다시 옵션을 선택할 수 있다.
4번 옵션을 선택하면 다음과 같이 파티션 엔트리가 출력된다.
파티션을 구조체에 담아 출력해보았다.
'과제' 카테고리의 다른 글
[forensic] 디스크 이미지 분석 프로그램 (1) (0) | 2019.03.14 |
---|