장 - 14
원시 파일 복구를 위한 프로그래밍
원시 파일 복구
파일의 시작과 끝에 특정 순서나 문자 조합이 쓰여진 특정 파일 유형이 많이 있습니다. 디스크 편집 프로그램을 사용하면 이러한 조합을 쉽게 분석할 수 있습니다. EDIT DOS 명령을 사용하여 ASCII 파일의 구조를 조사할 수도 있습니다.
파일의 시작 부분에 나타나는 특정 문자 시퀀스나 조합을 일반적으로 헤더라고 하며, 파일 끝에 저장되는 문자 시퀀스나 조합을 파일의 푸터라고 합니다.
FAT 또는 루트 디렉토리 정보가 없어 데이터를 복구할 수 없는 디스크 오류로 인해 데이터가 손실된 경우 헤더와 푸터를 사용하여 이러한 특정 유형의 파일을 찾을 수 있습니다. 헤더는 특정 파일 유형의 파일의 시작을 나타내고, 푸터는 특정 파일 유형의 파일의 끝을 나타냅니다.
여기서는 특정 파일 유형의 원시 구조를 사용하여 데이터를 복구하므로 이 복구 방법을 원시 파일 복구라고 합니다. 디스크 표면을 섹터별로 스캔하여 헤더와 푸터 정보를 찾습니다.
원시 파일 복구는 다양한 용도로 사용할 수 있지만, 큰 도움이 될 수 있는 특수한 복구 사례도 있습니다. 예를 들어, 실수로 중요한 파일이 들어 있는 디스크에서 데이터 지우기 프로그램을 실행했다면, 프로그램을 중지하기 전까지 운영 체제 파일을 포함한 모든 MBR, DBR, FAT 및 루트 디렉터리 정보가 지워집니다.
이런 경우, 포맷 복구 프로그램으로도 데이터 복구가 불가능할 수 있습니다. 여기에서는 Raw 파일 복구를 사용하여 머리글과 바닥글을 검색하여 특정 파일 유형의 파일을 복구할 수 있습니다.
그뿐만 아니라, 드라이브의 모든 논리 파티션을 삭제하고 이전과 다른 크기의 파티션을 다시 만들거나 운영 체제를 설치한 경우에도 데이터를 복구할 수 있습니다.
이제 디스크가 분할되고 포맷되기 전에 해당 디스크에 중요한 데이터가 있었다는 기억이 납니다. 방금 운영 체제를 설치한 경우 파일이 복구될 가능성이 높습니다.
원시 파일 복구 성능에 영향을 미치는 요인으로는 조각화된 데이터와 다른 데이터가 덮어쓴 데이터의 양입니다. 하지만, 점점 더 많은 원시 파일 복구 애플리케이션을 직접 찾을 수 있습니다.
원시 파일 복구 소프트웨어를 사용하여 파일을 검색하는 절차 또는 규칙은 다음과 같은 조건을 고려합니다.
- 디스크 섹터에서 파일 헤더나 여러 파일 유형을 동시에 검색합니다.
- 파일 유형 헤더가 발견되면 파일에 있는 데이터를 저장하고 다음 네 가지 조건을 확인하여 파일을 닫고 저장합니다.
- 이 파일 유형의 바닥글을 찾았습니다.
- 동일한 파일 형식의 또 다른 헤더가 발견되었습니다.
- 다른 파일 유형의 헤더를 찾았습니다.
- 프로그램에서 특정 파일 유형에 대한 다른 머리글이나 바닥글을 찾을 수 없으며, 데이터를 저장하려는 파일 크기가 프로그램에서 정의한 파일 크기의 최대 제한에 도달했습니다.
파일 유형 헤더 및 푸터를 찾은 섹터 데이터를 포함하여 정보는 파일에 저장되어야 합니다.
일부 중요한 파일 유형의 헤더 및 바닥글
일부 중요한 파일 유형의 머리글과 바닥글은 아래 표에 나열되어 있습니다. 표에 나열된 바닥글은 지정된 파일 유형의 파일 끝이나 파일의 끝 오프셋에 있으므로, 데이터 복구를 위한 바닥글로 사용할 수 있습니다.
DOS EDIT 명령이나 디스크 편집 도구를 사용하여 이러한 파일 유형 외의 머리글과 바닥글을 직접 검색할 수도 있습니다. 정보를 더 이해하기 쉽게 표현하기 위해 16진법을 사용했습니다.
확대 |
헤더(16진수) |
바닥글(16진수) |
의사 |
D0 CF 11 E0 A1 B1 1A E1 |
57 6F 72 64 2E 44 6F 63 75 6G 65 6E 74 2E |
XLS |
D0 CF 11 E0 A1 B1 1A E1 |
FE FF FF FF 00 00 00 00 00 00 00 00 57 00 6F 00 72 00 6B 00 62 00 6F 00 6F 00 6B 00 |
PPT |
D0 CF 11 E0 A1 B1 1A E1 |
50 00 6F 00 77 00 65 00 72 00 50 00 6F 00 69 00 6E 00 74 00 20 00 44 00 6F 00 63 00 75 00 6D 00 65 00 6E 00 74 |
우편번호 |
50 4B 03 04 14 |
50 4B 05 06 00 |
사진 |
D8 E0 00 10 4A 46 49 46 00 01 01 |
D9("파일 크기 검사를 사용하는 것이 더 좋습니다") |
GIF |
47 49 46 38 39 61 4E 01 53 00 C4 |
21 00 00 3B 00 |
PDF |
25 50 44 46 2D 31 2E |
25 25 45 4층 46 |
원시 파일을 복구하는 프로그램 작성
아래는 Microsoft Word 파일(확장자 .DOC)의 원시 파일 복구 프로그램의 인코딩입니다. 이 프로그램은 디스크 섹터에서 파일을 검색하고 복구된 파일을 자동으로 저장하며 파일 이름을 자동으로 생성합니다.
사용자가 파일을 저장하기 위해 지정한 경로는 복구된 데이터를 저장하는 대상 경로로 사용됩니다. 대상 디렉토리가 존재하지 않으면 프로그램은 최대 1단계의 디렉토리를 생성할 수 있습니다.
여기에 제공된 복구 소프트웨어는 대용량 디스크에서도 데이터를 검색하고 복구할 수 있도록 지원합니다. 이 프로그램은 두 번째 실제 하드 드라이브에서 데이터를 검색하기 위해 작성되었습니다.
/* Microsoft Word RAW 파일 복구 소프트웨어 */
#include<stdio.h>
#include<dos.h>
/* INT 13H 확장을 사용하는 getdrivegeometry 함수에서 사용하는 구조체, 함수 번호 0x48. */
구조 기하학
{
부호 없는 int 크기; /* (호출) 버퍼 크기 */
부호 없는 int 플래그; /* 정보 플래그 */
부호 없는 긴 실린더; /* 물리적 숫자
드라이브의 실린더 */
unsigned long 헤더 ;/* 물리적 헤더 수
드라이브에 머리 */
부호 없는 long spt ; /* 물리적 숫자
트랙당 섹터 */
부호 없는 긴 섹터[2] ; /* 총 수량
디스크의 섹터 */
부호 없는 int bps; /* 섹터당 바이트 */
} ;
/* readabsolutesectors에서 사용하는 디스크 주소 패킷 형식 구조 */
diskaddrpacket 구조
{
char 패킷 크기; /* 패킷 크기, 일반적으로 10H */
기호는 예약됨; /* 예약됨 (0) */
int 블록 개수; /* 전송할 블록 수 */
char far *버퍼주소; /* 전송을 위한 주소
버퍼 */
부호 없는 긴 블록 번호[2] ; /* 초기 절대값
블록번호 */
} ;
///// 드라이브 매개변수를 얻기 위한 함수 \\\\\
unsigned long getdrivegeometry(intdrive)
{
노동조합 REGS i, o ;
구조 SREGS s;
구조 기하학 g = { 26, 0, 0, 0, 0, 0, 0, 0 } ;
이하 = 0x48 ; /* 함수 번호 0x48 */
ihdl = 드라이브; /* 디스크 번호 */
ixsi = FP_OFF ( (void far*)&g ) ;
s.ds = FP_SEG ( (void far*)&g ) ;
/* 세그먼트 레지스터 값으로 지정된 INT 13H 확장 기능 번호를 호출합니다. */
int86x(0x13, &i, &o, &s);
printf("\n Head = %lu, 트랙당 섹터 = %lu, Cylinder = %lu\n",
g.헤드, g.spc, g.cyl);
/* 디스크 지오메트리를 가져오는 함수가 실패하면 오류 메시지를 출력하고 종료합니다. */
if(g.spt==0)
{
printf("\n 드라이브 지오메트리를 가져오는 함수가 실행되지 않았습니다....");
printf("\n 확장이 지원되지 않습니다. 아무 키나 누르세요.
출구...");
getch();
출구(1);
}
return *g.sectors; /* 섹터 수를 반환합니다.
드라이브의 섹터 */
}
부호 없는 long 파일 크기=0, i=0;
unsigned long 시작 파일=0, 끝 파일=0;
부호 없는 long Sectors_in_HDD2=0, 루프=0;
char 버퍼[512], 파일 이름[80], 임시[8];
char 경로[80];
부호 없는 int 결과, 숫자=0;
/* Microsoft Word 파일의 헤더 */
char 헤더[10] = {0xD0,0xCF,0x11,0xE0, 0xA1,0xB1,0x1A,0xE1};
/* Microsoft Word 파일의 바닥글 */
char DOC_footer[14] =
{0x57,0x6F,0x72,0x64, 0x2E,0x44,0x6F,0x63,
0x75, 0x6D, 0x65, 0x6E, 0x74};
/// 메인 시작 \\\
void 메인()
{
영어: clrscr();
/* 연결된 하드 디스크의 총 수가 적으면
그 다음 두 개, 오류 메시지 표시 및 종료. */
if(((char)peekb(0x0040, 0x0075))<2)
{
printf("\n\n 최소한 두 개의 하드 디스크가 있어야 합니다.
이것을 실행하려면 컴퓨터에 연결하세요");
printf("\n 프로그램. 이 프로그램은 개발되었습니다.
두 번째 하드 디스크의 데이터를 복구합니다.");
printf("\n 종료하려면 아무 키나 누르세요...");
getch();
출구(1);
}
Sectors_in_HDD2=getdrivegeometry(0x81);
printf("\n 두 번째 하드 디스크의 총 섹터 = %lu",
HDD2의 섹터)
printf("\n\n \"복구된 파일을 저장해야 합니다.
다른 하드 디스크가 같은 디스크에 없습니다.");
printf("\n 당신이 잃어버린 것을 찾고 있는 곳
데이터.\"");
printf("\n\n 저장할 대상 경로를 입력하세요
복구된 파일...\n ");
경로를 가져옵니다.
/* 대상 디렉토리가 존재하는지 확인 */
접근 경로가 0이면 != 0입니다.
{
/* 대상 디렉토리가 존재하지 않으면 생성
디렉토리를 한 단계까지 */
if(mkdir(경로)!=0)
{
printf("\n 디렉토리 \"%s\"를 생성할 수 없습니다",
길);
printf("\n 경로 확인..., 아무 키나 누르세요
출구...");
getch();
출구(1);
}
}
strcat(경로, "\\Ptt");
/* 화면에서 커서를 숨기거나 표시하는 함수 */
커서 표시_숨기기( 32,
gotoxy(15,18);cprintf("[ %d ] 파일 복구됨...",
안에);
/* 디스크의 마지막 섹터까지 데이터 검색 */
while(루프<섹터_in_HDD2)
{
/* 한 섹터 읽기 (섹터 번호 = 루프) */
readabsolutesectors(0x81, 루프, 1, 버퍼);
gotoxy(19,16);cprintf("스캐닝 섹터 번호 = %ld",
고리);
if(kbhit())
{
show_hide_cursor(6, 7); /* 검색
커서가 앞에 있음
프로그램 종료
*/
종료(0);
}
/* 지정된 헤더가 발견된 경우 */
버퍼, 헤더, 7인 경우(memcmp())==0)
{
/* 파일 이름을 자동으로 제공하는 논리
복구된 데이터를 저장할 파일을 생성합니다. */
strcpy(파일이름, 경로);
itoa(숫자, 임시, 10);
strcat(파일명, 임시);
strcat(파일명, ".DOC");
start_file=loop; /* 파일의 시작 섹터 */
gotoxy(5,19);cprintf("파일을 찾았습니다... %s로 저장 중입니다",
파일 이름);
숫자++;
////////////// 파일 닫기 조건 \\\\\\\\\\\\\\\\\\
파일 크기=0;
while(파일_크기<5000000)
{
루프++;
파일 크기 +=512;
readabsolutesectors(0x81, 루프, 1, 버퍼);
gotoxy(19,16);cprintf("스캐닝 섹터 번호 = %ld" ,
고리);
/* 파일 크기가 최대 5MB에 도달한 경우 */
파일 크기가 5000000 이상인 경우
{
end_file=loop; /* 파일의 끝 섹터 */
Recover_the_file();/* 데이터를 파일에 씁니다. */
부서지다;
}
/* DOC 파일의 바닥글이 발견된 경우 */
i=0;i<512;i++에 대하여
{
if( memcmp(버퍼+i,DOC_footer,12)==0 )
{
end_file=loop; /* 파일의 끝 섹터 */
Recover_the_file();/* 데이터를 파일에 씁니다. */
부서지다;
}
}
/* 다른 헤더가 발견된 경우 */
if( memcmp(버퍼, 헤더, 7)==0 )
{
루프=루프-1;
end_file=loop; /* 파일의 끝 섹터 */
Recover_the_file();/* 데이터를 파일에 씁니다. */
부서지다;
}
if(kbhit())
{
커서 표시_숨기기( 6, 7 );
종료(0);
}
}
}
루프++;
}
/////////While 루프가 여기서 끝납니다
/* 검색 및 복구 완료에 대한 표시 메시지 */ if(loop>=Sectors_in_HDD2 )
{
gotoxy(17,23);cprintf("디스크에 파일을 저장하는 중입니다.
완전한 !!");
gotoxy(17,24);cprintf("종료하려면 아무 키나 누르세요...");
커서 표시_숨기기( 6, 7 );
getch();
}
}
구조 기하학은 INT 13H 확장, 함수 번호 0x48을 사용하는 getdrivegeometry 함수에서 디스크의 다양한 매개변수를 가져오는 데 사용됩니다.
구조 diskaddrpacket은 readabsolutesectors 함수에서 사용되는 디스크 주소 패킷 형식을 위한 것입니다.
getdrivegeometry(int drive) 함수는 지정된 물리적 드라이브 번호 drive의 디스크 드라이브 매개변수를 가져옵니다.
(char) peekb(0x0040, 0x0075)는 세그먼트 0040H:오프셋 0075H로 표현되는 메모리 위치에 저장된 컴퓨터에 연결된 하드 디스크의 수를 찾는 데 사용됩니다. 연결된 하드 디스크의 총 수가 2개보다 적으면 오류 메시지를 표시하고 종료합니다.
Sectors_in_HDD2=getdrivegeometry(0x81); 두 번째 물리적 하드 디스크(0x81)의 다양한 매개변수를 찾고 디스크의 총 섹터 수를 반환합니다.
if(access(path, 0) != 0) 문은 사용자가 제공한 경로의 접근성을 확인합니다. 대상 디렉토리가 없으면 대상은 한 단계까지 생성되고 if(mkdir(path)!=0) 조건으로 확인한 주어진 경로가 불법이면 오류 메시지가 표시됩니다.
복구된 데이터를 저장하기 위해 자동으로 생성된 파일의 파일 이름은 strcat(path,"\\Ptt"); 함수에 의해 파일의 처음 세 글자가 PTT로 주어지도록 생성됩니다. 이는 대상 디렉토리에 중복된 파일 이름이 생기지 않도록 하기 위해 수행됩니다. 따라서 복구된 파일의 파일 이름은 "PTTxxxxx.DOC" 형식으로 제공됩니다.
show_hide_cursor(32, 0); 함수는 화면에서 커서를 숨기는 데 사용되는 반면 show_hide_cursor(6, 7);는 커서를 화면으로 다시 가져옵니다.
함수 readabsolutesectors(0x81, loop, 1, buffer);는 섹터 번호 loop로 지정된 두 번째 물리적 하드 디스크의 한 섹터를 읽습니다.
파일의 헤더가 발견되면, start_file = loop;는 start_file을 복구할 파일의 시작 섹터 번호로 설정합니다. 프로그램은 다음에 주어진 세 가지 조건을 따라 파일의 끝 섹터를 찾습니다.
- 파일 크기가 최대 5MB에 도달하면
- DOC 파일의 바닥글이 발견된 경우
- 다른 헤더가 발견되면
긴 정수 end_file은 end_file=loop에 의해 파일의 끝 섹터 번호로 설정됩니다. 세 가지 조건 중 하나가 충족되면. 이제 섹터 번호 start_file에서 섹터 번호 end_file까지의 섹터 데이터가 Recover_the_file( ) 함수로 파일에 저장됩니다.
Recover_the_file( ) 함수의 코딩은 다음과 같습니다.
/* 섹터 번호 start_file부터 섹터 번호 end_file까지 섹터의 데이터를 저장하는 함수 */
파일_복구()
{
파일 *fp;
if((fp=fopen(파일명, "wb"))==NULL)
{
gotoxy(10,23);printf("파일 %s를 여는 중 오류 발생",
파일 이름);
getch();
출구(1);
}
for(i=시작파일;i<=끝파일;i++)
{
gotoxy(19,16);cprintf("스캐닝 섹터 번호 =
%ld", 나);
readabsolutesectors(0x81, i, 1, 버퍼);
fwrite(버퍼,512,1, fp);
}
fp를 닫습니다.
gotoxy(15,18);cprintf("[ %d ] 파일 복구됨...",num);
고톡시(5,19);cprintf(" ");
반품;
}
함수 readabsolutesectors의 코딩은 다음과 같습니다. 이 함수는 INT 13H 확장 및 함수 번호 42H를 사용하여 섹터를 읽습니다.
이 함수에 대한 자세한 설명은 이 책의 앞부분에서 논의한 "백업 만들기" 장을 참조하십시오. 함수의 코딩은 다음과 같습니다.
//// 절대 섹터를 읽는 함수 \\\\
int readabsolutesectors ( int 드라이브,
부호 없는 긴 섹터 번호,
int 섹터 수,
void *버퍼)
{
유니온 REGS i, o;
구조체 SREGS s;
구조체 diskaddrpacket pp;
pp.packetsize = 16 ; /* 패킷 크기 = 10H */
pp.reserved = 0 ; /* 예약됨 = 0 */
pp.blockcount = numofsectors ; /* 섹터 수
읽다 */
/* 데이터 버퍼용 */
pp.버퍼 주소 = (char far*) MK_FP ( FP_SEG((void far*)버퍼), FP_OFF((void far*)버퍼));
pp.blocknumber[0] = sectornumber ; /* 섹터 번호
읽다 */
pp.blocknumber[1] = 0 ; /* 블록 번호 */
ihah = 0x42 ; /* 함수 번호*/
ihdl = 드라이브; /* 물리적 드라이브 번호 */
/* 버퍼 매개변수에 대한 ds:si */
ixsi = FP_OFF ( (void far*)&pp ) ;
/* 버퍼 매개변수에 대한 ds:si */
s.ds = FP_SEG ( (void far*)&pp ) ;
/* INT 13H의 지정된 함수를 호출합니다.
세그먼트 레지스터 값 */
int86x(0x13, &i, &o, &s);
if ( oxcflag==1)
return 0 ; // 실패
또 다른
return 1 ; // 성공
}
다음 기능은 화면에서 커서를 숨기거나 표시하는 데 사용됩니다. 해당 함수는 인터럽트 10H, 함수 01H를 사용하여 커서 유형을 설정합니다. 인코딩은 다음과 같습니다.
커서 표시_숨기기(ssl, esl)
정수 ssl, esl;
{
노동조합 REGS i, o ;
증가 = 1 ;
ihch = ssl ;
ihcl = 영어;
ihbh = 0 ;
int86(16, &i, &o);
돌아와;
}
show_hide_cursor( 32, 0 )은 커서를 숨기고 show_hide_cursor( 6, 7 )은 커서를 다시 표시합니다. ssl은 커서의 시작 줄이고, esl은 커서의 끝 줄입니다.
01H INT 10H 함수에 대한 간략한 설명은 다음과 같습니다.
INT 10H(16 또는 0x10)
기능 01H(또는 0x01) --> 커서 유형 설정
전화 : AH = 01H
비트 0-4 CH = 커서 시작 라인
CL 비트 0-4 = 커서의 끝 줄
반환: 없음.
댓글:
이 기능은 텍스트 표시 모드에서 깜박이는 하드웨어 커서의 시작과 끝 줄을 선택하여 커서 유형을 설정하는 데 사용됩니다. 그래픽 모드에서는 하드웨어 커서를 사용할 수 없습니다.