第 16 章
为磁盘开发更多实用程序
简介
在本章中,我们将讨论如何使用 MBR、DBR、FAT 和根目录的信息来开发可以帮助我们管理数据、优化存储或进行磁盘故障排除任务的实用程序。
通常,这些程序是针对某些特定问题的解决方案。本章讨论了一些实用程序及其编程。
隐藏分区
通常,分区隐藏实用程序由在用户使用的此类计算机系统上工作的用户使用。如果同一台计算机有很多用户,则很有可能另一个用户的数据被读取、窃取或删除。
在这种情况下,如果用户在同一台计算机上有一些重要数据或一些机密信息,他可能愿意隐藏他拥有数据的分区,以使该分区不应该被操作人员访问。系统,以免其他用户访问。
当用户想要在系统上工作时,他可以通过取消隐藏分区来访问分区。这些类型的活动通常发生在专业机构,许多学生使用计算机,但高年级学生总是担心他们的重要数据或项目工作。由于缺乏知识,新学生可能会损害甚至删除他们的数据。
分区如何隐藏
下表表示MBR分区表中的分区格式:
Offset |
Meaning |
Size |
Description |
00H |
Boot Type Indicator Byte |
1 Byte |
If Byte is 00H, the Partition is Inactive and if Byte is 80H, The Partition is Active (or Bootable) |
01H |
Head Number of Beginning of the Partition |
1 Byte |
Starting Head number of the Partition in Hexadecimal System |
02H |
Sector and Cylinder Number of Beginning of the Partition |
2 Bytes |
6 Bits of First Byte make Starting Sector Number and Combination of remaining 2 Bits (as Two Most Significant Bits) plus 8 Bits of another Byte (Rest 8 least Significant Bits of the 10-Bit Number ) make the Starting Cylinder Number of the Partition |
04H |
File System indicator Byte |
1 Byte |
File System Indicator Byte in Hexadecimal system (for complete list of partition indicator bytes, refer the chapter “Logical Approach to Disks and OS” discussed earlier in this book) |
05H |
Head Number of End of the Partition |
1 Byte |
Ending Head Number of the Partition in Hexadecimal System |
06H |
Sector and Cylinder Number of End of the Partition |
2 Bytes |
6 Bits of First Byte make Ending Sector Number and Combination of remaining 2 Bits (as Two Most Significant Bits) plus 8 Bits of another Byte (Rest 8 least Significant Bits of the 10-Bit Number ) make the Ending Cylinder Number of the Partition |
08H |
Absolute Sector number of Beginning of the Partition |
4 Bytes |
Number of Sectors Between the MBR and the First Sector in the Partition |
0CH |
Absolute Sector number of End of the Partition |
4 Bytes |
Number of Sectors in the Partition |
|
|
Total = 16 Bytes |
|
在偏移量 04H 处,在每个分区条目中,都有一个文件系统指示字节。该指示字节表示该分区的文件系统类型。如果这个字节的值改变了,分区的标识就改变了。
例如,“DOS 12-Bit FAT”的分区指示字节的值为 0x01。如果此值更改为 0x11,则分区表条目中的文件系统标识更改为“隐藏的 DOS 12 位 FAT”(有关分区指示符字节的完整列表,请参阅“磁盘和操作系统的逻辑方法”一章讨论本书的前面部分)。
下面给出的表格显示了一些分区类型的文件系统指示字节的更多示例:
Partition type indicator Byte |
Description of File System of Partition |
0x01 |
DOS 12–bit FAT |
0x11 |
Hidden DOS 12–bit FAT |
0x04 |
DOS 16–bit FAT (<=32MB) |
0x14 |
Hidden DOS 16–bit FAT (<=32MB) |
0x05 |
DOS Extended |
0x15 |
Hidden DOS Extended |
0x06 |
DOS 16–bit big (> 32MB) |
0x16 |
Hidden DOS 16–bit big (> 32MB) |
0x07 |
NTFS |
0x17 |
Hidden NTFS |
0x0B |
Windows FAT32 |
0x1B |
Hidden Windows FAT32 |
0x0C |
Windows FAT32 (LBA) |
0x1C |
Hidden Windows FAT32 (LBA) |
0x0E |
Windows FAT16 (LBA) |
0x1E |
Hidden Windows FAT16 (LBA) |
0x0F |
Windows Extended |
0x1F |
Hidden Windows Extended |
在这里,我们看到任何文件系统的相应隐藏分区都是通过将值 0x10 添加到其系统指示符字节来找到的。
虽然隐藏分区并不是硬性规定,但它甚至适用于大多数文件系统。其背后的原因是,当我们改变分区指示字节的值时,分区表条目中文件系统的标识就改变了。并且很少有新的文件系统也被同一个操作系统支持。
编写程序隐藏分区
接下来给出的程序用于使用该分区的分区条目从 MBR 的分区表中隐藏该分区。如果你想隐藏扩展卷中的其他逻辑分区,你应该访问扩展 MBR。
下面给出了程序的编码:
/* 使用该分区的分区表条目从 MBR 隐藏分区的程序 */
#include <bios.h>
#include <stdio.h>
int main(void)
{
struct diskinfo_t dinfo;
int result, tohide;
int i;
static char dbuf[512];/* Data Buffer to read-Write the
Sector information */
clrscr();
dinfo.drive = 0x80; /* drive number for First
Hard Disk */
dinfo.head = 0; /* disk head number */
dinfo.track = 0; /* track number */
dinfo.sector = 1; /* sector number */
dinfo.nsectors = 1; /* sector count */
dinfo.buffer = dbuf; /* data buffer */
/* 读取磁盘的第一个扇区 */
result = _bios_disk(_DISK_READ, &dinfo);
if ((result & 0xff00) == 0)
{
printf("The Partition Codes of Four Partition Entries are,
0x%02x, 0x%02x, 0x%02x And 0x%02x.\n",
dbuf[450] & 0xff, dbuf[466] & 0xff,
dbuf[482] & 0xff, dbuf[498] & 0xff);
textcolor(15);
gotoxy(5,5);cprintf("Partition Entry in MBR is as
follows:");
gotoxy(10,7);cprintf("1. "); showtype(dbuf[450] & 0xff);
gotoxy(10,8);cprintf("2. "); showtype(dbuf[466] & 0xff);
gotoxy(10,9);cprintf("3. "); showtype(dbuf[482] & 0xff);
gotoxy(10,10);cprintf("4. "); showtype(dbuf[498] & 0xff);
/* 获取隐藏分区的用户输入 */
gotoxy(1,15);
printf("Enter The partition no. you want to hide,
Or Press any other key to Exit... ");
tohide=getche();
switch(tohide)
{
case '1': /* Hide First Partition in partition Table */
dbuf[450] = dbuf[450] +16;
result = _bios_disk(_DISK_WRITE, &dinfo);
break;
case '2': /* Hide second Partition in partition Table */
dbuf[466] = dbuf[466]+16;
result = _bios_disk(_DISK_WRITE, &dinfo);
break;
case '3': /* Hide third Partition in partition Table */
dbuf[482] = dbuf[482] +16;
result = _bios_disk(_DISK_WRITE, &dinfo);
break;
case '4': /* Hide Fourth Partition in partition Table */
dbuf[498] = dbuf[498]+16;
result = _bios_disk(_DISK_WRITE, &dinfo);
break;
default:
exit(0);
}
if ((result & 0xff00) == 0)
{
printf("\n\nThe New Partition Codes of Four Partition
Entries are, 0x%02x, 0x%02x, 0x%02x And 0x%02x.\n",
dbuf[450] & 0xff, dbuf[466] & 0xff,
dbuf[482] & 0xff, dbuf[498] & 0xff);
getch();
}
else
{
printf("Cannot Change the Byte, status = 0x%02x\n",
result);
getch();
}
}
return 0;
}
编码评论:
程序读取 MBR 分区表中所有四个分区条目的文件系统指示符字节。函数showtype( )用于显示文件系统的名称,对应文件系统指示字节的值。
用户从屏幕上显示的菜单中选择要隐藏的分区,然后将16(0x10)添加到该分区的文件系统指示字节的值以隐藏它。
函数showtype()的编码如下:
/* 显示文件系统名称对应文件系统指示字节值的函数 */
showtype(i)
{
switch (i)
{
case 0x00 :cprintf("Empty"); break;
case 0x01 :cprintf("DOS 12-bit FAT"); break;
case 0x02 :cprintf("XENIX root"); break;
case 0x03 :cprintf("XENIX usr"); break;
case 0x04 :cprintf("DOS 16-bit <32M"); break;
case 0x05 :cprintf("Extended"); break;
case 0x06 :cprintf("DOS 16-bit >=32M"); break;
case 0x07 :cprintf("OS/2 HPFS"); break;
case 0x08 :cprintf("AIX"); break;
case 0x09 :cprintf("AIX bootable"); break;
case 0xa :cprintf("OS/2 Boot Manag"); break;
case 0xb :cprintf("Win95/98/ME FAT32"); break;
case 0xc :cprintf("Win95/98/ME FAT32 (LBA)"); break;
case 0xd :cprintf("Win95 FAT16"); break;
case 0xe :cprintf("Win95 FAT16 (LBA)"); break;
case 0xf :cprintf("Win95 Extended"); break;
case 0x11 :cprintf("Hidden FAT-12");break;
case 0x12 :cprintf("Compaq Diagnostics");break;
case 0x14 :cprintf("Hidden FAT-16 (<32)");break;
case 0x15 :cprintf("Hidden Extended");break;
case 0x16 :cprintf("Hidden FAT-16");break;
case 0x17 :cprintf("NTFS"); break;
case 0x40 :cprintf("Venix 80286"); break;
case 0x51 :cprintf("Novell?"); break;
case 0x52 :cprintf("Microport"); break;
case 0x63 :cprintf("GNU HURD"); break;
case 0x64 :
case 0x65 :cprintf("Novell Netware"); break;
case 0x75 :cprintf("PC/IX"); break;
case 0x80 :cprintf("Old MINIX"); break;
case 0x81 :cprintf("Linux/MINIX"); break;
case 0x82 :cprintf("Linux swap"); break;
case 0x83 :cprintf("Linux native"); break;
case 0x85 :cprintf("Linux Extended"); break;
case 0x93 :cprintf("Amoeba"); break;
case 0x94 :cprintf("Amoeba BBT"); break;
case 0xa5 :cprintf("BSD/386"); break;
case 0xa6 :cprintf("OpenBSD"); break;
case 0xa7 :cprintf("NEXTSTEP"); break;
case 0xb7 :cprintf("BSDI fs"); break;
case 0xb8 :cprintf("BSDI swap"); break;
case 0xc7 :cprintf("Syrinx"); break;
case 0xdb :cprintf("CP/M"); break;
case 0xe1 :cprintf("DOS access"); break;
case 0xe3 :cprintf("DOS R/O"); break;
case 0xf2 :cprintf("DOS secondary"); break;
case 0xff :cprintf("BBT"); break;
default :cprintf("UNKOWN");
}
return 0;
}
编写程序来取消隐藏分区
取消隐藏隐藏分区的程序与隐藏程序的程序正好相反。在这个程序中,我们从隐藏分区的文件系统指示字节的值中减去 16 (0x10)。
程序的编码如下:
/* 取消隐藏被上一个程序隐藏的分区的程序 */
#include <bios.h>
#include <stdio.h>
int main(void)
{
struct diskinfo_t dinfo;
int result, tohide;
int i;
static char dbuf[512];/* Data buffer */
clrscr();
dinfo.drive = 0x80; /* drive number for
First Hard Disk */
dinfo.head = 0; /* disk head number */
dinfo.track = 0; /* track number */
dinfo.sector = 1; /* sector number */
dinfo.nsectors = 1; /* sector count */
dinfo.buffer = dbuf; /* data buffer */
result = _bios_disk(_DISK_READ, &dinfo);
if ((result & 0xff00) == 0)
{
printf("The Partition Codes of Four Partition
Entries are, 0x%02x, 0x%02x, 0x%02x And 0x%02x.\n",
dbuf[450] & 0xff, dbuf[466] & 0xff,
dbuf[482] & 0xff, dbuf[498] & 0xff);
textcolor(15);
gotoxy(5,5);
cprintf("Partition Entry in MBR is as follows:");
gotoxy(10,7);cprintf("1. "); showtype(dbuf[450] & 0xff);
gotoxy(10,8);cprintf("2. "); showtype(dbuf[466] & 0xff);
gotoxy(10,9);cprintf("3. "); showtype(dbuf[482] & 0xff);
gotoxy(10,10);cprintf("4. "); showtype(dbuf[498] & 0xff);
/* 获取使用输入以取消隐藏分区 */
gotoxy(1,15);printf("Enter The partition no., Which to
unhide, Or Press any other key to
Exit... ");
tohide=getche();
switch(tohide)
{
/* 取消隐藏分区表的第一个分区 */
case '1':
dbuf[450] = dbuf[450] -16;
result = _bios_disk(_DISK_WRITE, &dinfo);
break;
/* Unhide second partition of partition table */
case '2':
dbuf[466] = dbuf[466]-16;
result = _bios_disk(_DISK_WRITE, &dinfo);
break;
/* Unhide third partition of partition table */
case '3':
dbuf[482] = dbuf[482] -16;
result = _bios_disk(_DISK_WRITE, &dinfo);
break;
/* Unhide fourth partition of partition table */
case '4':
dbuf[498] = dbuf[498]-16;
result = _bios_disk(_DISK_WRITE, &dinfo);
break;
default:
exit(0);
}
if ((result & 0xff00) == 0)
{
printf("\n\nThe New Partition Codes of Four Partition
Entries are, 0x%02x, 0x%02x, 0x%02x And 0x%02x.\n",
dbuf[450] & 0xff, dbuf[466] & 0xff,
dbuf[482] & 0xff, dbuf[498] & 0xff);
getch();
}
else
{
printf("Cannot Change the Byte, status = 0x%02x\n",
result);
getch();
}
}
return 0;
}
节目评论
在指定要取消隐藏的分区号时要小心。如果错误地输入了分区号,该分区的文件系统信息将被更改,分区可能无法访问。但是,前面讨论的隐藏分区的程序可能会帮助您修复该分区的文件系统指示符字节。
编写程序删除分区
删除分区的程序用于故障排除。例如,假设您的磁盘中有 FAT32 文件系统分区。现在你决定在你的磁盘上同时安装 LINUX 操作系统。
如果有的话,操作系统的安装会在中间中断,在对 MBR 的分区表进行修改的阶段。在这种情况下,您要安装其他操作系统的分区很可能无法访问。
在这种情况下,丢失分区的磁盘空间由于无法访问而变得无用。但是,如果我们以任何方式从分区表中删除该分区的分区信息,我们可以再次使用 DOS 的 FDISK 命令使该空间可用。
下面给出了从MBR的分区表中删除分区条目的程序:
/* 程序从MBR的分区表中删除第二个分区条目 */
# include <bios.h>
/* structure to read the partition entry from partition table */
struct partition
{
/* Active Partition Byte */
unsigned char bootable ;
/* Starting Head */
unsigned char start_side ;
/* combination of Starting sector and cylinder number */
unsigned int start_sec_cyl ;
/* File system Indicator Byte */
unsigned char parttype ;
/* Ending Head */
unsigned char end_side ;
/* combination of Starting sector and cylinder number */
unsigned int end_sec_cyl ;
/* Relative Sector Number */
unsigned long part_beg ;
/* Partition length in sectors */
unsigned long plen ;
} ;
/* Structure to read-write MBR */
struct part
{
/* IPL (Initial Program Loader) */
unsigned char master_boot[446] ;
/* Partition table */
struct partition pt[4] ;
/* Magic Number */
int lasttwo ;
} ;
struct part p ;
void main()
{
unsigned int t1,t2;
clrscr();
biosdisk ( 2, 0x80, 0, 0, 1, 1, &p ) ;
display(); /* display the information of
Partition table */
getch();
p.pt[1].bootable = 0;
p.pt[1].start_side = 0 ;
p.pt[1].start_sec_cyl = 0 ;
p.pt[1].parttype = 0;
p.pt[1].end_side = 0;
p.pt[1].end_sec_cyl = 0;
p.pt[1].part_beg = 0;
p.pt[1].plen = 0;
printf("\n\n\n After Deleting the Second Partition
Entry From MBR Partition Table,");
printf("\n The Partition Table will Be Changed as
Follows: ");
/* To Delete Second Partition Information from partition
table of MBR Remove the forward slashes from the
biosdisk( ) function. Do not use Carelessly, Partition
information of Second Partition of Partition Table will
be Erased Completely. */
////// biosdisk ( 3, 0x80, 0, 0, 1, 1, &p ) ;
display(); /* Display the information of partition
table after modification */
getch();
}
节目评论:
取消注释 biosdisk ( 3, 0x80, 0, 0, 1, 1, &p ) 函数,从 MBR 的分区表中删除第二个分区。
要删除分区,它的所有参数在MBR的分区表条目中设置为0。永远记住,如果您删除扩展分区,该扩展分区的所有逻辑分区也将变得无法访问。
函数display()用于显示MBR的分区表。函数编码如下:
/* 显示MBR分区表的函数 */
display()
{
unsigned int s_sec, s_trk, e_sec, e_trk, i, t1, t2 ;
char type[20], boot[5] ;
printf("\n\nPart. Boot Starting location Ending Location
Relative Number of");
printf("\nType Side Cylinder Sector Side Cylinder
Sector Sectors Sectors\n");
for ( i = 0 ; i <= 3 ; i++ )
{
if ( p.pt[i].bootable == 0x80 )
strcpy ( boot, "Yes" ) ;
else
strcpy ( boot, "No" ) ;
switch ( p.pt[i].parttype )
{
case 0x00 :
strcpy ( type, "Unused" ) ; break ;
case 0x1 :
strcpy ( type, "FAT12" ) ; break ;
case 0x2 :
strcpy ( type, "Xenix" ) ; break ;
case 0x3 :
strcpy ( type, "Xenix:usr" ) ; break ;
case 0x4 :
strcpy ( type, "FAT16<32M" ) ; break ;
case 0x5 :
strcpy ( type, "DOS-Ext." ) ; break ;
case 0x6 :
strcpy ( type, "FAT16>32M" ) ; break ;
case 0x7 :
strcpy ( type, "NTFS" ) ; break ;
case 0x0b :
strcpy ( type, "FAT32" ) ; break ;
case 0x0c :
strcpy ( type, "FAT32-LBA" ) ; break ;
case 0x0d :
strcpy ( type, "VFAT16" ) ; break ;
case 0x0e :
strcpy ( type, "VFAT16-LBA" ) ; break ;
case 0x0f :
strcpy ( type, "FAT EXT" ) ; break ;
case 0x17 :
strcpy ( type, "HPFS" ) ; break ;
case 0x81 :
strcpy ( type, "Old LINUX" ) ; break ;
case 0x82 :
strcpy ( type, "LinuxSwap" ) ; break ;
case 0x83 :
strcpy ( type, "LinuxNative" ) ; break ;
case 0x85 :
strcpy ( type, "Linux Ext." ) ; break ;
default :
strcpy ( type, "Unknown" ) ; break ;
}
s_sec = ( p.pt[i].start_sec_cyl & 0x3f ) ;
t1 = ( p.pt[i].start_sec_cyl & 0xff00 ) >> 8 ;
t2 = ( p.pt[i].start_sec_cyl & 0x00c0 ) << 2 ;
s_trk = t1 | t2 ;
e_sec = ( p.pt[i].end_sec_cyl & 0x3f ) ;
t1 = ( p.pt[i].end_sec_cyl & 0xff00 ) >> 8 ;
t2 = ( p.pt[i].end_sec_cyl & 0x00c0 ) << 2 ;
e_trk = t1 | t2 ;
printf ( "\n%6s %3s", type, boot ) ;
printf ( "%4d %6d %8d", p.pt[i].start_side,
s_trk,s_sec ) ;
printf ( "%7d %6u %8u", p.pt[i].end_side, e_trk,
e_sec ) ;
printf ( " %10lu %10lu", p.pt[i].part_beg,
p.pt[i].plen ) ;
}
return 0;
}
格式化“Track 0 Bad”软盘
本程序用于格式化那些在磁道0 上有坏扇区的软盘,当用DOS 或windows 格式化时,会显示像“Track 0 BAD”这样的错误信息。不过你也可以用它来格式化普通软盘。
程序的编码已在本书随附的名为“TTFORMAT.C”的磁盘中给出。程序的工作逻辑与PCQUEST计算机杂志2003年2月版的程序相同。
在这个程序中,我们尝试通过格式化来使这种类型的软盘可重复使用。该程序听起来你可以处理软盘,即使上面有一些坏扇区。但是,如果磁盘的第一个扇区坏了,则无法格式化软盘。
程序重写所有 DBR、FAT 和根目录信息。如果磁盘表面有坏扇区,则在 FAT 中将它们标记为坏扇区。
在程序的编码中,结构体BPB用于写入DBR的BIOS Parameter Block。结构体 boot_sector 用于写入磁盘的 DBR。结构体 address_field 用于与每个磁道的柱面数、磁头数和扇区数以及扇区的大小进行交互。
程序编码中使用的不同函数及其描述已在下表中给出。
软盘的卷序号是DOS根据系统时钟的当前日期和时间计算出来的。
序列号的第一部分由时间(秒和百分之一秒)和日期(月和日)之和计算得出。序列号的第二部分等于时间(小时和分钟)和日期(年)之和。
所有计算均以十六进制系统进行。例如,假设您在 2003 年 10 月 23 日的 11:16:28:65 在 DOS 环境中格式化了软盘。现在让我们计算磁盘的序列号。
The time in (seconds and Hundredths of seconds) format is
= (28 and 65)
= (1CH and 41H)
Write it as 1C41
Similarly, date in (month and day) format is
= (10 and 23)
= (0AH and 17H)
Write it as 0A17
Similarly, time in (hours and minutes) format is,
= (11 and 16)
= (0BH and 10H)
Write it as 0B10
And the year will be
= 2003
= 07D3
现在,让我们根据前面的描述计算软盘的序列号。序列号的第一部分是 (1C41 + 0A17) = 2658,序列号的第二部分是 (0B10 + 07D3) = 12E3。
编写磁盘编辑工具
磁盘编辑程序的编码已在本书随附的磁盘中给出,文件名为“TTEDITOR.C”。你可以使用这个程序来分析硬盘或软盘的表面。甚至在编写本书时的大部分研究中,我都使用 TTEDITOR 来分析磁盘表面或执行磁盘修改。
此编辑程序可以执行的一些重要任务如下:
- 读取硬盘和软盘表面的扇区信息。
- 将任何扇区的备份写入文件。
- 从文件中恢复扇区的数据。
- 修改单个字节。
- 十六进制转十进制和二进制计算器。
程序使用 biosdisk( ) 和 _bios_disk( ) 函数来访问磁盘。如果要分析超过 8.4 GB 的磁盘,请使用 INT 13H 的 Extensions 修改程序。下表给出了程序中使用的函数的描述:
Function |
Description |
bkground( ) |
creates the back ground and frame of first screen |
clsline( ) |
Used to clear the complete row from the screen specified by row number. |
refresh( ) |
Function to recall all the display functions on the screen |
writetofile( ) |
Function to write the data of a sector to user defined file. |
writetosector( ) |
Function to restore the sector from specified file. |
msgdisp( ) |
Function to display messages on the screen. |
modify( ) |
Function to modify a single byte of any sector, specified by user. |
frame( ) |
Function to draw the frame structure of sector display |
dispmax( ) |
Display maximum CHS number of the disk (Valid Up to 8.4 GB Disk) |
display( ) |
Display the sector and information on the screen. |
hextodec( ) |
Function to Calculate hexadecimal number to corresponding decimal and binary numbers. |
Page Modified on: 18/01/2022