第十四章
“原始文件”恢复编程
原始文件恢复
有许多特定的文件类型,它们在文件的开头和结尾有一些特定的字符序列或字符组合。我们可以借助任何磁盘编辑程序轻松分析这些组合。我们也可以使用DOS的EDIT命令来研究ASCII格式文件的结构。
出现在文件开头的特定字符序列或字符组合通常称为文件头,而存储在文件结尾的字符序列或字符组合称为文件页脚。
如果我们在这种类型的磁盘崩溃中丢失了数据,以至于没有 FAT 或根目录信息可用于恢复数据,我们可以使用页眉和页脚来搜索这些特定的文件类型。页眉指示该特定类型的文件的开始,页脚指示该特定文件类型的文件的结束。
这里我们使用特定文件类型的原始结构来恢复数据,因此恢复技术称为原始文件恢复。磁盘表面逐个扇区查找页眉和页脚信息。
虽然原始文件恢复可能有广泛的应用领域,但有一些特定的恢复案例可能会有很大帮助。例如,如果您错误地运行了磁盘中的任何数据擦除程序,其中包含一些重要文件,但直到您停止该程序,MBR,DBR,FAT,以及包括操作系统文件在内的根目录的所有信息都将被擦除。
在这种情况下,即使是格式恢复程序也可能无法帮助您恢复数据。在这里,您可以使用 Raw file Recovery 通过搜索页眉和页脚来恢复这些特定文件类型的文件。
不仅如此,即使您在这种情况下也可以恢复数据,在这种情况下,您拥有这样的硬盘,您已经删除了磁盘的所有逻辑分区,重新创建了不同大小的分区,甚至您已经安装了操作系统。
现在您会记得,在分区和格式化之前,您的磁盘中有一些重要数据。如果您刚刚安装了操作系统,则文件恢复的机会很大。
影响原始文件恢复性能的因素是碎片数据和被其他一些数据覆盖的数据量。但是,您可以自己找到越来越多的原始文件恢复应用领域。
使用原始文件恢复程序搜索文件的过程或几乎规则考虑以下条件:
- 在磁盘扇区中同时搜索文件头或多种文件类型。
- 如果找到任何文件类型的header,将数据保存到文件中,并检查以下四个条件关闭并保存文件
- 找到该文件类型的页脚
- 找到另一个相同文件类型的头
- 找到另一种文件类型的标题
- 没有找到程序中定义的文件类型的其他页眉或页脚,并且您存储数据的文件的大小达到了您在程序中为文件大小定义的最大大小限制。
信息应存储在文件中,包括您在其中找到文件类型的页眉和页脚的扇区的数据。
一些重要文件类型的页眉和页脚
一些重要文件类型的页眉和页脚已在下表中给出。表中给出的页脚要么位于指定文件类型的文件末尾,要么位于文件的末尾偏移中,以便您可以将它们用作页脚来恢复数据。
您还可以使用 DOS 的 EDIT 命令或使用任何磁盘编辑工具自行搜索与这些文件类型不同的页眉和页脚。为了便于理解,我使用了十六进制系统来表示信息。
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 扩展名)的原始文件恢复程序的编码。程序在磁盘的扇区中搜索文件,并通过自动创建文件名来自动保存恢复的文件。
用户指定的保存文件的路径被用作保存恢复数据的目标路径。如果目标目录不存在,程序最多可以创建一级目录。
这里给出的恢复程序甚至支持大容量磁盘来搜索和恢复数据。已编写程序搜索第二个物理硬盘中的数据。
/* 用于恢复 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++;
}
////////While 循环在这里结束
/* 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();
}
}
getdrivegeometry 函数使用 INT 13H 扩展,函数编号 0x48 来获取磁盘的各种参数。
结构diskaddrpacket用于磁盘地址数据包格式,供readabsolutesectors函数使用。
函数getdrivegeometry(int drive)是获取磁盘指定物理驱动号驱动器的驱动参数。
(char) peekb(0x0040, 0x0075) 用于查找连接到计算机的硬盘数量,存储在段 0040H:offset 0075H 表示的内存位置。如果连接的硬盘总数少于两个,则显示错误消息并退出。
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);读取由扇区号循环指定的第二个物理硬盘的一个扇区。
如果找到文件头,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的扇区数据的功能 */
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的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:
该功能用于在文本显示模式下通过选择闪烁硬件光标的起始行和结束行来设置光标类型。在图形模式下,硬件光标不可用。
Page Modified on: 17/01/2022