第 14 章
原始文件恢复编程
恢复原始文件
有许多特定的文件类型,在文件的开头和结尾写有特定的字符序列或组合。我们可以使用任何磁盘编辑程序轻松分析这些组合。我们还可以使用 EDIT DOS 命令来检查 ASCII 文件的结构。
文件开头的特定字符序列或组合通常称为文件头,文件结尾的特定字符序列或组合称为文件页脚。
如果我们在这种类型的磁盘故障中丢失了数据,而没有 FAT 或根目录信息来恢复数据,我们可以使用页眉和页脚来查找这些特定类型的文件。文件头指示该特定文件类型的文件的开始,文件脚指示该特定文件类型的文件的结束。
这里我们使用某种文件类型的原始结构来恢复数据,因此这种恢复方法称为原始文件恢复。逐个扇区地扫描磁盘表面以查找页眉和页脚信息。
尽管原始文件恢复可能具有广泛的应用,但在某些特殊的恢复情况下它可以提供很大的帮助。例如,如果您错误地在包含一些重要文件的磁盘上运行任何数据擦除程序,但直到您停止该程序,所有 MBR、DBR、FAT 和根目录信息(包括操作系统文件)都将被擦除。
在这种情况下,即使格式恢复程序也可能无法帮助您恢复数据。在这里,您可以使用原始文件恢复通过在页眉和页脚中搜索来恢复这些特定文件类型的文件。
不仅如此,如果您的硬盘上的所有逻辑分区都被删除,重新创建了大小不同的分区,甚至安装了操作系统,您仍然可以恢复数据。
现在,您会记起在磁盘分区和格式化之前磁盘上有一些重要数据。如果您刚刚安装了操作系统,则该文件很有可能被恢复。
影响原始文件恢复性能的因素是碎片数据和被其他数据覆盖的数据量。不过,您可以自己找到越来越多的用于原始文件恢复的应用程序。
使用原始文件恢复软件搜索文件的程序或几乎规则考虑了以下条件:
- 在磁盘扇区中同时搜索文件头或多种文件类型。
- 如果发现任何文件类型头,则保存文件中的数据,并检查以下四个条件来关闭并保存文件。
- 找到此文件类型的页脚
- 发现了另一个相同文件类型的标题。
- 发现不同文件类型的标头
- 在程序中未找到某些文件类型的其他页眉或页脚,并且保存数据的文件大小达到了您在程序中为文件大小定义的最大大小限制。
该信息应保存在文件中,包括您找到文件类型页眉和页脚的扇区数据。
一些重要文件类型的页眉和页脚
下表列出了一些重要文件类型的页眉和页脚。表中列出的页脚要么位于指定文件类型的文件末尾,要么位于文件的结束偏移量,因此您可以将它们用作数据恢复的页脚。
您还可以使用 DOS EDIT 命令或任何磁盘编辑工具自己搜索除这些文件类型之外的页眉和页脚。我使用十六进制来表示信息,以使其更容易理解。
扩大 |
标头(十六进制) |
页脚(十六进制) |
文档 |
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 |
幻灯片 |
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 |
JPG |
FF D8 FF E0 00 10 4A 46 49 46 00 01 01 |
D9(“最好使用文件大小检查”) |
动态图片 |
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 RAW 文件恢复软件*/
#include<stdio.h>
#include<dos.h>
/* 使用 INT 13H 扩展的 getdrivegeometry 函数所使用的结构,功能编号 0x48。 */
结构几何
{
无符号整数大小; /*(调用)缓冲区大小*/
无符号整数标志; /* 信息标志 */
无符号长整型; /* 物理数量
驱动器上的气缸 */
无符号长头;/* 物理
驱动器上的磁头 */
无符号长整型 spt ; /* 物理数量
每磁道扇区数 */
无符号长整型扇区[2]; /* 总数量
磁盘上的扇区 */
无符号整数 bps; /* 每扇区字节数 */
};
/* readabsolutesectors使用的磁盘地址包格式结构*/
diskaddrpacket 结构
{
字符数据包大小; /* 数据包大小,通常为 10H */
符号保留; /* 保留 (0) */
int 块数; /* 要传输的块数 */
char far *缓冲区地址; /* 传输地址
缓冲 */
无符号长整型块号[2]; /* 初始绝对值
区块编号 */
};
///// 获取驱动器参数的函数\\\\\
无符号长整型 getdrivegeometry(intdrive)
{
工会规章 i, o ;
结构 SREGS s;
结构几何 g = { 26, 0, 0, 0, 0, 0, 0, 0 };
ihah = 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 磁头 = %lu, 每磁道扇区数 = %lu, 柱面数 = %lu\n",
g.头部, g.spc, g.圆柱体);
/* 如果获取磁盘几何形状的函数失败,则打印错误消息并退出 */
如果(g.spt==0)
{
printf("\n获取驱动器几何形状的函数未执行....");
printf("\n 扩展不支持,按任意键
出口...”);
获取();
退出(1);
}
返回 *g.sectors; /* 返回
驱动器上的扇区 */
}
无符号长整型文件大小=0,i=0;
无符号长整型起始文件=0,结束文件=0;
无符号长整型Sectors_in_HDD2=0,循环=0;
char 缓冲区[512],文件名[80],温度[8];
字符路径[80];
无符号整数结果,num=0;
/* Microsoft Word 文件的标题*/
字符头[10] = {0xD0,0xCF,0x11,0xE0, 0xA1,0xB1,0x1A,0xE1};
/* Microsoft Word 文件的页脚 */
字符 DOC_footer[14] =
{0x57,0x6F,0x72,0x64, 0x2E,0x44,0x6F,0x63,
0x75,0x6D,0x65,0x6E,0x74};
/// 主程序开始 \\\
空主()
{
clrscr();
/* 如果连接的硬盘总数小于
然后第二步,显示错误消息并退出。 */
如果(((char)peekb(0x0040,0x0075))<2)
{
printf("\n\n 您必须至少有两个硬盘
连接到您的计算机来运行此程序”);
printf("\n 程序。该程序已开发
恢复第二块硬盘的数据。”);
printf("\n按任意键退出... ");
获取();
退出(1);
}
Sectors_in_HDD2=获取驱动器几何形状 (0x81);
printf("\n 第二块硬盘的总扇区数 = %lu",
HDD2 中的扇区);
printf("\n\n \"您必须将恢复的文件保存在
另一个硬盘,不在同一个磁盘中,”);
printf("\n 你在其中搜索丢失的
数据。\””);
printf("\n\n 输入要保存的目标路径
已恢复文件...\n ");
获取(路径);
/* 检查目标目录是否存在 */
如果(访问(路径, 0)!= 0)
{
/* 如果目标目录不存在,则创建
目录向上一级 */
如果(mkdir(路径)!= 0)
{
printf("\n 无法创建目录 \"%s\"",
小路);
printf("\n 检查路径...,按任意键
出口...”);
获取();
退出(1);
}
}
strcat(路径,“\\Ptt”);
/*隐藏(和显示)屏幕上的光标的功能*/
显示隐藏光标 ( 32,
gotoxy(15,18);cprintf(“[ %d ] 个文件已恢复...",
在);
/* 搜索数据直到磁盘的结束扇区 */
while(循环<Sectors_in_HDD2)
{
/* 读取一个扇区 (扇区号 = 循环) */
读取绝对扇区(0x81,循环,1,缓冲区);
gotoxy(19,16);cprintf("扫描扇区数 = %ld",
环形);
如果(kbhit())
{
show_hide_cursor ( 6, 7 ); /* 检索
光标位于
退出程序
*/
退出(0);
}
/* 如果找到指定的标题 */
if((memcmp (缓冲区,标题,7))==0)
{
/* 逻辑提供文件名自动
创建文件来保存恢复的数据 */
strcpy(文件名,路径);
itoa(数字,温度,10);
strcat(文件名,温度);
strcat(文件名,“.DOC”);
start_file=loop; /* 文件的起始扇区 */
gotoxy(5,19);cprintf("找到文件...,另存为 %s",
文件名);
数字++;
////////////// 文件关闭条件 \\\\\\\\\\\\\\\\
文件大小=0;
while(文件大小<5000000)
{
循环++;
文件大小+=512;
读取绝对扇区(0x81,循环,1,缓冲区);
gotoxy(19,16);cprintf("扫描扇区号 = %ld",
环形);
/* 如果文件大小达到最大 5MB */
如果(文件大小>=5000000)
{
end_file=loop; /* 文件的结束扇区 */
Recover_the_file();/*将数据写入文件*/
休息;
}
/* 如果找到 DOC 文件的页脚 */
对于(i = 0;i < 512;i ++)
{
如果(memcmp(缓冲区+i,DOC_footer,12)==0)
{
end_file=loop; /* 文件的结束扇区 */
Recover_the_file();/*将数据写入文件*/
休息;
}
}
/* 如果发现另一个标头 */
如果(memcmp(缓冲区,标题,7)==0)
{
循环=循环-1;
end_file=loop; /* 文件的结束扇区 */
Recover_the_file();/*将数据写入文件*/
休息;
}
如果(kbhit())
{
显示隐藏光标(6,7);
退出(0);
}
}
}
循环++;
}
////////While 循环到此结束
/*显示搜索和恢复完成的消息*/if(loop>=Sectors_in_HDD2)
{
gotoxy(17,23);cprintf("文件在磁盘中的保存是
完全的 !!”);
gotoxy(17,24);cprintf("按任意键退出...");
显示隐藏光标(6,7);
获取();
}
}
结构 geometry 由 getdrivegeometry 函数使用 INT 13H 扩展、功能编号 0x48 来获取磁盘的各种参数。
结构 diskaddrpacket 用于磁盘地址包格式,供 readabsolutesectors 函数使用。
函数 getdrivegeometry(int drive) 用于获取磁盘指定物理驱动器号驱动器的驱动器参数。
(char) peekb(0x0040, 0x0075) 用于查找连接到计算机的硬盘数量,存储在由段 0040H:偏移量 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);读取扇区号loop指定的第二个物理硬盘的一个扇区。
如果找到文件头,start_file = loop; 将 start_file 设置为要恢复的文件的起始扇区号。程序遵循下面给出的三个条件来查找文件的结束扇区:
- 如果文件大小达到最大 5MB
- 如果发现 DOC 文件的页脚
- 如果发现另一个标头
如果满足三个条件中的任意一个,则通过 end_file=loop; 将长整数 end_file 设置为文件的结束扇区号。现在,使用函数 Recover_the_file() 将从扇区号 start_file 开始到扇区号 end_file 的扇区数据保存到文件中。
函数 Recover_the_file() 的代码如下所示:
/*函数用于保存从扇区号start_file开始到扇区号end_file的扇区的数据*/
恢复文件()
{
文件*fp;
如果((fp = fopen(文件名,“wb”))==NULL)
{
gotoxy(10,23);printf("打开文件 %s 时出错",
文件名);
获取();
退出(1);
}
对于(i = 起始文件;i <= 结束文件;i ++)
{
gotoxy(19,16);cprintf("扫描扇区数 =
%ld",一世);
读取绝对扇区(0x81,i,1,缓冲区);
fwrite(缓冲区,512,1,fp);
}
fclose(fp);
gotoxy(15,18);cprintf(“[ %d ] 个文件已恢复...",num);
gotoxy(5,19);cprintf(“ “);
返回;
}
接下来给出了 readabsolutesectors 函数的编码。该函数使用 INT 13H 扩展和功能号 42H 来读取扇区。
该函数的详细描述,请参考本书前面讨论过的“制作备份”一章。该函数的代码如下:
//// 读取绝对扇区的函数\\\\
int readabsolutesectors(int drive,
无符号长整型扇区号,
int 扇区数,
无效*缓冲区)
{
联合 REGS i,o;
结构 SREGS s;
结构磁盘地址包 pp;
pp.packetsize = 16 ; /* 数据包大小 = 10H */
pp.reserved = 0 ; /* 保留 = 0 */
pp.blockcount = numofsectors ; /* 扇区数
阅读 */
/* 用于数据缓冲区 */
pp.bufferaddress = (char far*) MK_FP ( FP_SEG((void far*)buffer), FP_OFF((void far*)buffer));
pp.blocknumber[0] = sectornumber ; /* 扇区号
阅读 */
pp.blocknumber[1] = 0 ; /* 块号 */
ihah = 0x42 ; /* 功能编号 */
ihdl = drive ; /* 物理驱动器号 */
/* ds:si 为缓冲区参数 */
ixsi = FP_OFF((void far*)&pp);
/* ds:si 为缓冲区参数 */
s.ds = FP_SEG((void far*)&pp);
/* 调用 INT 13H 的指定函数
段寄存器值 */
int86x ( 0x13,&i,&o,&s ) ;
如果(oxcflag==1)
返回 0 ; //失败
别的
返回 1 ; // 成功
}
以下函数用于隐藏或显示屏幕上的光标。该函数使用中断10H,功能01H来设置光标类型。编码如下:
显示隐藏光标(ssl,esl)
整数 ssl,esl;
{
工会规章 i, o ;
增加 = 1 ;
ihch = ssl;
ihcl=esl;
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 = 光标的结束行
返回:无。
评论:
该功能用于设置光标类型,通过选择文本显示模式下闪烁硬件光标的起始行和终止行。硬件光标在图形模式下不可用。