장 – 14
"원시 파일" 복구를 위한 프로그래밍
원시 파일 복구
파일의 시작과 끝 부분에 특정 시퀀스 또는 문자 조합이 기록된 특정 파일 유형이 많이 있습니다. 디스크 편집 프로그램을 사용하여 이러한 조합을 쉽게 분석할 수 있습니다. DOS의 EDIT 명령을 사용하여 ASCII 형식의 파일 구조를 연구할 수도 있습니다.
파일의 시작 부분에 있는 특정 시퀀스 또는 문자 조합을 일반적으로 헤더라고 하고 파일의 끝에 저장되는 문자의 시퀀스 또는 조합을 파일의 바닥글이라고 합니다.
데이터를 복구하는 데 사용할 수 있는 FAT 또는 루트 디렉터리 정보가 없는 디스크 충돌 유형으로 데이터가 손실된 경우 머리글과 바닥글을 사용하여 이러한 특정 파일 형식을 검색할 수 있습니다. 헤더는 특정 유형의 파일 시작을 나타내고 바닥글은 해당 특정 파일 유형의 파일 끝을 나타냅니다.
여기에서는 특정 파일 유형의 원시 구조를 사용하여 데이터를 복구하므로 복구 기술을 원시 파일 복구라고 합니다. 디스크의 표면을 섹터로 검색하여 헤더와 푸터 정보를 찾습니다.
원시 파일 복구는 적용 범위가 넓지만 많은 도움이 될 수 있는 특정 복구 사례가 있습니다. 예를 들어, 실수로 중요한 파일이 있는 디스크에서 데이터 삭제 프로그램을 실행했는데 프로그램을 중지할 때까지 운영 체제 파일을 포함한 MBR, DBR, FAT 및 루트 디렉터리의 모든 정보가 지워집니다.
이 경우 포맷 복구 프로그램을 사용해도 데이터 복구에 도움이 되지 않을 수 있습니다. 여기에서 원시 파일 복구를 사용하여 머리글과 바닥글을 검색하여 특정 파일 유형의 파일을 복구할 수 있습니다.
뿐만 아니라, 디스크의 모든 논리 파티션을 삭제하고 운영 체제를 설치하기 전과 다른 크기의 파티션을 재생성한 하드 디스크가 있는 경우에도 데이터를 복구할 수 있습니다. .
이제 디스크를 분할하고 포맷하기 전에 디스크에 몇 가지 중요한 데이터가 있었다는 것을 기억할 수 있습니다. 운영 체제를 방금 설치했다면 파일이 복구될 가능성이 많습니다.
원시 파일 복구의 성능에 영향을 미치는 요인은 조각화된 데이터와 다른 데이터가 덮어쓴 데이터의 양입니다. 그러나 원시 파일 복구를 위해 점점 더 많은 응용 분야를 찾을 수 있습니다.
원시 파일 복구 프로그램으로 파일을 검색하는 절차 또는 거의 규칙은 다음 조건을 고려합니다.
- 디스크 섹터에서 파일의 헤더 또는 여러 파일 유형을 동시에 검색합니다.
- 모든 파일 형식의 헤더가 있는 경우 파일에 데이터를 저장하고 다음 4가지 조건을 확인하여 파일을 닫고 저장합니다.
- 해당 파일 형식의 바닥글을 찾았습니다.
- 동일한 파일 형식의 다른 헤더를 찾았습니다.
- 다른 파일 형식의 헤더를 찾았습니다.
- 프로그램에서 정의된 파일 유형에 대한 다른 머리글이나 바닥글을 찾을 수 없으며 데이터를 저장하는 파일의 크기가 프로그램에서 파일 크기에 대해 정의한 최대 크기 제한에 도달했습니다.
정보는 파일 유형의 머리글과 바닥글을 찾은 섹터의 데이터를 포함하여 파일에 저장되어야 합니다.
일부 중요한 파일 형식의 머리글 및 바닥글
몇 가지 중요한 파일 형식의 머리글과 바닥글은 다음 표에 나와 있습니다. 표에 제공된 바닥글은 지정된 파일 유형의 파일 끝에 있거나 데이터를 복구하기 위한 바닥글로 사용할 수 있도록 파일의 끝 오프셋에 있습니다.
DOS의 EDIT 명령을 사용하거나 디스크 편집 도구를 사용하여 이러한 파일 형식과 다른 머리글과 바닥글을 검색할 수도 있습니다. 이해하기 쉽도록 정보를 나타내기 위해 16진수 체계를 사용했습니다.
Extension |
Header (Hex) |
Footer (Hex) |
DOC |
D0 CF 11 E0 A1 B1 1A E1 |
57 6F 72 64 2E 44 6F 63 75 6D 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 |
ZIP |
50 4B 03 04 14 |
50 4B 05 06 00 |
JPG |
FF D8 FF E0 00 10 4A 46 49 46 00 01 01 |
D9 (“Better To Use File size Check”) |
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 4F 46 |
원시 파일 복구를 위한 프로그램 작성
Microsoft Word 파일(.DOC 확장자)의 Raw 파일 복구를 위한 프로그램의 코딩은 다음과 같습니다. 프로그램은 디스크의 섹터에서 파일을 검색하고 파일 이름을 자동으로 생성하여 복구된 파일을 자동으로 저장합니다.
사용자가 파일을 저장하기 위해 지정한 경로는 복구된 데이터를 저장할 대상 경로로 사용됩니다. 대상 디렉터리가 존재하지 않는 경우 프로그램은 한 디렉터리 수준까지 대상을 만들 수 있습니다.
여기에 제공된 복구 프로그램은 대용량 디스크에서도 데이터를 검색하고 복구할 수 있도록 지원합니다. 프로그램은 두 번째 물리적 하드 디스크의 데이터를 검색하도록 작성되었습니다.
/* Microsoft Word 파일을 복구하는 원시 파일 복구 프로그램 */
#include<stdio.h>
#include<dos.h>
/* Structure to be used by getdrivegeometry function using INT 13H Extension, Function Number 0x48. */
struct geometry
{
unsigned int size ; /* (call) size of Buffer */
unsigned int flags ; /* Information Flags */
unsigned long cyl ; /* Number of Physical
Cylinders on Drive */
unsigned long heads ;/* Number of Physical
Heads on Drive */
unsigned long spt ; /* Number of Physical
Sectors Per Track */
unsigned long sectors[2] ; /* Total Number of
Sectors on Drive */
unsigned int bps ; /* Bytes Per Sector */
} ;
/* Structure of Disk Address packet format, to be used by the readabsolutesectors Function */
struct diskaddrpacket
{
char packetsize ; /* Size of Packet, generally 10H */
char reserved ; /* Reserved (0) */
int blockcount ; /* Number of Blocks to Transfer */
char far *bufferaddress ; /* address to Transfer
Buffer */
unsigned long blocknumber[2] ; /* Starting Absolute
Block Number */
} ;
///// 드라이브 매개변수를 가져오는 함수 \\\\\
unsigned long getdrivegeometry (int drive)
{
union REGS i, o ;
struct SREGS s ;
struct geometry g = { 26, 0, 0, 0, 0, 0, 0, 0 } ;
i.h.ah = 0x48 ; /* Function Number 0x48 */
i.h.dl = drive; /* Drive Number */
i.x.si = FP_OFF ( (void far*)&g ) ;
s.ds = FP_SEG ( (void far*)&g ) ;
/* Invoke the specified function number of INT 13H extension with Segment Register Values */
int86x ( 0x13, &i, &o, &s ) ;
printf("\n Head = %lu, Sectors Per Track = %lu, Cylinder = %lu\n",
g.heads,g.spt,g.cyl);
/* If get drive Geometry function Fails, Display Error Message and Exit */
if(g.spt==0)
{
printf("\n Get Drive Geometry Function Fails....");
printf("\n Extensions Not Supported, Press any Key to
Exit...");
getch();
exit(1);
}
return *g.sectors; /* Return The Number of
Sectors on Drive */
}
unsigned long file_size=0, i=0;
unsigned long start_file=0, end_file=0;
unsigned long Sectors_in_HDD2=0, loop=0;
char buffer[512], filename[80], temp[8];
char path[80];
unsigned int result,num=0;
/* Microsoft Word 파일의 헤더 */
char header[10] = {0xD0,0xCF,0x11,0xE0, 0xA1,0xB1,0x1A,0xE1};
/* Footer of Microsoft Word Files */
char DOC_footer[14] =
{0x57,0x6F,0x72,0x64, 0x2E,0x44,0x6F,0x63,
0x75,0x6D,0x65,0x6E,0x74};
/// Start Of main \\\
void main()
{
clrscr();
/* If total no. of hard disks attached is less
then two, Display Error Message and Exit. */
if(((char)peekb(0x0040, 0x0075))<2)
{
printf("\n\n You Must Have At least Two Hard Disks
Attached to your Computer To Run This");
printf("\n Program. This Program has been developed
to recover the Data of Second Hard Disk.");
printf("\n Press any Key to Exit... ");
getch();
exit(1);
}
Sectors_in_HDD2=getdrivegeometry (0x81);
printf("\n Total Sectors in second Hard Disk = %lu",
Sectors_in_HDD2);
printf("\n\n \"You must save the recovered files in
another Hard Disk, Not in the Same Disk,");
printf("\n in which you are searching the lost
data.\"");
printf("\n\n Enter The Destination Path to save the
Recovered Files...\n ");
gets(path);
/* check if destination directory exists or Not */
if(access(path, 0) != 0)
{
/* if Destination directory does not exist, create
the Directory up to one level */
if(mkdir(path)!=0)
{
printf("\n Could Not Create Directory \"%s\"",
path);
printf("\n Check Path..., Press any key to
exit...");
getch();
exit(1);
}
}
strcat(path,"\\Ptt");
/* 화면에 커서 숨기기(및 표시) 기능 */
show_hide_cursor ( 32,
gotoxy(15,18);cprintf("[ %d ] Files Recovered...",
num);
/* search for the data until the ending sector of the disk */
while(loop<Sectors_in_HDD2)
{
/* Read one Sector (Sector No. = loop) */
readabsolutesectors ( 0x81, loop, 1, buffer );
gotoxy(19,16);cprintf("Scanning Sector Number = % ld",
loop);
if(kbhit())
{
show_hide_cursor ( 6, 7 ); /* Retrieve the
cursor before
Exit the program
*/
exit(0);
}
/* if specified header is found */
if((memcmp ( buffer, header,7))==0)
{
/* logic to provide the file name to automatically
create the files to save the recovered data */
strcpy(filename, path);
itoa(num,temp,10);
strcat(filename, temp);
strcat(filename,".DOC");
start_file=loop; /* starting sector of file */
gotoxy(5,19);cprintf("File Found..., Saving As %s",
filename);
num++;
////////////// 파일 닫기 조건 \\\\\\\\\\\\\\\\
file_size=0;
while( file_size<5000000)
{
loop++;
file_size+=512;
readabsolutesectors ( 0x81, loop, 1, buffer );
gotoxy(19,16);cprintf("Scanning Sector Number = % ld" ,
loop);
/* if file size reaches up to maximum size of 5MB */
if(file_size>=5000000)
{
end_file=loop; /* Ending Sector of File */
Recover_the_file();/* write the data to file */
break;
}
/* if footer of DOC file is found */
for(i=0;i<512;i++)
{
if( memcmp(buffer+i,DOC_footer,12)==0 )
{
end_file=loop; /* Ending Sector of File */
Recover_the_file();/* write the data to file */
break;
}
}
/* if another header is found */
if( memcmp(buffer,header,7)==0 )
{
loop=loop-1;
end_file=loop; /* Ending Sector of File */
Recover_the_file();/* write the data to file */
break;
}
if(kbhit())
{
show_hide_cursor ( 6, 7 );
exit(0);
}
}
}
loop++;
}
////////루프가 여기서 끝나는 동안
/* display message for completion of search and recovery */ if(loop>=Sectors_in_HDD2 )
{
gotoxy(17,23);cprintf("The Saving of files in the Disk is
Completed !!");
gotoxy(17,24);cprintf("Press Any Key to Exit...");
show_hide_cursor ( 6, 7 );
getch();
}
}
구조 기하학은 디스크의 다양한 매개변수를 얻기 위해 INT 13H 확장, 기능 번호 0x48을 사용하는 getdrivegeometry 기능에서 사용됩니다.
diskaddrpacket 구조는 readabsolutesectors 함수에서 사용할 디스크 주소 패킷 형식입니다.
함수 getdrivegeometry(int drive)는 디스크에 지정된 물리적 드라이브 번호 드라이브의 드라이브 매개변수를 가져오는 것입니다.
(char) peekb(0x0040, 0x0075)는 세그먼트 0040H:offset 0075H로 표시되는 메모리 위치에 저장된 컴퓨터에 연결된 하드 디스크의 수를 찾는 데 사용됩니다. 연결된 총 하드 디스크 수가 2개 미만이면 오류 메시지를 표시하고 종료합니다.
Sectors_in_HDD2=getdrivegeometry(0x81); 두 번째 물리적 하드 디스크(0x81)의 다양한 매개변수를 찾아 디스크의 총 섹터 수를 반환합니다.
if(access(path, 0) != 0) 문은 사용자가 지정한 경로의 접근성을 확인합니다. 목적지 디렉토리가 존재하지 않을 경우 목적지는 한 단계까지 생성되며 if(mkdir(path)!=0) 조건으로 확인된 주어진 경로가 잘못된 경우 에러 메시지를 출력한다.
복구된 데이터를 저장하기 위해 자동으로 생성된 파일의 파일 이름은 파일의 처음 세 문자가 strcat(path,"\\Ptt"); 함수. 이는 대상 디렉토리에서 파일 이름이 중복되는 것을 피하기 위해 수행됩니다. 따라서 복구된 파일의 파일 이름은 "PTTxxxxx.DOC" 형식으로 제공됩니다.
기능 show_hide_cursor ( 32, 0 ); show_hide_cursor( 6, 7 )가 있는 화면에서 커서를 숨기는 데 사용됩니다. 커서를 화면으로 되돌립니다.
readabsolutesectors 함수(0x81, 루프, 1, 버퍼); 섹터 번호 루프로 지정된 두 번째 물리적 하드 디스크의 섹터 하나를 읽습니다.
파일의 헤더를 찾으면 start_file = loop; start_file을 복구할 파일의 시작 섹터 번호로 설정합니다. 프로그램은 파일의 끝 섹터를 찾기 위해 다음에 주어진 세 가지 조건을 따릅니다.
- 파일 크기가 최대 5MB에 도달하는 경우
- DOC 파일의 바닥글이 있는 경우
- 다른 헤더가 있는 경우
긴 정수 end_file은 end_file=loop에 의해 파일의 끝 섹터 번호로 설정됩니다. 3가지 중 1가지 조건이 충족되면. 이제 섹터 번호 start_file부터 섹터 번호 end_file까지의 섹터 데이터가 Recover_the_file() 함수를 사용하여 파일에 저장됩니다.
Recover_the_file() 함수의 코딩은 다음과 같습니다.
/* 섹터 번호 start_file부터 섹터 번호 end_file까지 섹터의 데이터를 저장하는 기능 */
Recover_the_file()
{
FILE *fp;
if((fp=fopen(filename, "wb"))==NULL)
{
gotoxy(10,23);printf("Error Opening File %s",
filename);
getch();
exit(1);
}
for(i=start_file;i<=end_file;i++)
{
gotoxy(19,16);cprintf("Scanning Sector Number =
%ld", i);
readabsolutesectors ( 0x81, i, 1, buffer );
fwrite(buffer,512,1, fp);
}
fclose(fp);
gotoxy(15,18);cprintf("[ %d ] Files Recovered...",num);
gotoxy(5,19);cprintf(" ");
return;
}
함수 readabsolutesectors의 코딩은 다음에 주어졌습니다. 이 기능은 INT 13H 확장 및 기능 번호 42H를 사용하여 섹터를 읽습니다.
기능에 대한 자세한 설명은 이 책의 앞부분에서 설명한 "백업 만들기" 장을 참조하십시오. 함수의 코딩은 다음과 같습니다.
//// 절대 섹터를 읽는 기능 \\\\
int readabsolutesectors ( int drive,
unsigned long sectornumber,
int numofsectors,
void *buffer )
{
union REGS i, o ;
struct SREGS s ;
struct diskaddrpacket pp ;
pp.packetsize = 16 ; /* packet size = 10H */
pp.reserved = 0 ; /* Reserved = 0 */
pp.blockcount = numofsectors ; /* Number of sectors
to read */
/* for Data buffer */
pp.bufferaddress = (char far*) MK_FP ( FP_SEG((void far*)buffer), FP_OFF((void far*)buffer));
pp.blocknumber[0] = sectornumber ; /* Sector number
to read */
pp.blocknumber[1] = 0 ; /* Block number */
i.h.ah = 0x42 ; /* Function Number*/
i.h.dl = drive ; /* Physical Drive Number */
/* ds:si for buffer Parameters */
i.x.si = FP_OFF ( (void far*)&pp ) ;
/* ds:si for buffer Parameters */
s.ds = FP_SEG ( (void far*)&pp ) ;
/* Invoke the specified Function of INT 13H with
segment register values */
int86x ( 0x13, &i, &o, &s ) ;
if ( o.x.cflag==1)
return 0 ; //failure
else
return 1 ; // success
}
다음 기능은 화면에서 커서를 숨기거나 표시하는 데 사용됩니다. 이 기능은 인터럽트 10H, 기능 01H를 사용하여 커서 유형을 설정합니다. 코딩은 다음과 같습니다.
show_hide_cursor( ssl, esl )
int ssl, esl ;
{
union REGS i, o ;
i.h.ah = 1 ;
i.h.ch = ssl ;
i.h.cl = esl ;
i.h.bh = 0 ;
int86 ( 16, &i, &o ) ;
return;
}
show_hide_cursor( 32, 0 ) 는 커서를 숨기고 show_hide_cursor( 6, 7 ) 는 커서를 다시 검색합니다. ssl은 커서의 시작 라인이고 esl은 커서의 끝 라인입니다.
INT 10H의 Function 01H에 대한 간략한 설명은 다음과 같습니다.
INT 10H (16 or 0x10)
Function 01H (or 0x01) --> Set Cursor Type
Call with: AH = 01H
CH bits 0-4 = starting line for cursor
CL bits 0-4 = ending line for cursor
Returns: Nothing.
Comments:
이 기능은 텍스트 표시 모드에서 깜박이는 하드웨어 커서의 시작 라인과 끝 라인을 선택하여 커서 유형을 설정하는 데 사용됩니다. 그래픽 모드에서는 하드웨어 커서를 사용할 수 없습니다.