Глава – 15
ПРОГРАММИРОВАНИЕ ДЛЯ ОЧИСТИТЕЛЕЙ ДАННЫХ
Введение
Мы уже обсуждали, что при удалении любого файла с диска информация не стирается полностью с диска, но помечается как доступная для записи на нее новых данных.
Когда мы форматируем диск, вся информация о файлах и каталогах диска, такая как FAT и записи корневого каталога, стирается, но область данных остается неизменной, и ничего из области данных диска не стирается. Данные, которые удаляются или форматируются с помощью операционной системы, остаются в области данных как есть и могут быть восстановлены с помощью некоторых усилий по восстановлению данных и программного обеспечения для восстановления данных.
Поэтому необходимость полного удаления данных с диска приводит к потребности в такой программе, которая полностью стирает данные с диска. Для этого недостаточно просто удалить файлы или просто отформатировать диск, данные на диске должны быть перезаписаны другими данными.
Программы, которые используются для полного стирания данных с диска, известны как программы стирания данных. Эти программы записывают случайные символы в область данных, чтобы перезаписать данные и стереть всю информацию, ранее сохраненную на диске.
Когда данные становятся полностью невосстановимыми
Чтобы стереть данные, область данных на диске должна быть перезаписана другими данными, но проблема на этом не заканчивается. Чтобы еще больше все усложнить, тенденция магнитных дисков запоминать данные, которые были перезаписаны, требует, чтобы данные также были перезаписаны несколько раз случайными последовательностями данных, так что их невозможно будет восстановить даже с помощью сложных инструментов восстановления данных
Это связано с тем, что сегодня доступны технологии, позволяющие восстанавливать данные даже после использования некоторых простых средств удаления данных.
Некоторые продукты стирания данных выполняют перезапись данных двоичными нулями и двоичными единицами. Запись серии двоичных нулей и двоичных единиц обеспечивает самый глубокий эффект перезаписи, поскольку эти значения являются минимальными и максимальными магнитными значениями соответственно.
Хотя это теория идеальной программы стирания данных, но, как правило, перезапись данных случайным символом ASCII достаточна. Причина так говорить в том, что восстановление с помощью сложных инструментов и технологий восстановления не может быть использовано для восстановления данных любой организации для рутинного восстановления данных, поскольку эти технологии очень дороги и стоят миллионы даже для одного восстановления. Не только это, но и эти технологии доступны только в нескольких странах по всему миру.
Мы обсудим только простую перезапись данных для стирания данных с диска. Однако вы можете дополнительно модифицировать те же программы для записи только случайных символов, приложив некоторые небольшие усилия. Данные, стертые этой идеей, также не могут быть восстановлены никаким программным обеспечением для восстановления данных.
Почему удаление данных так важно
Когда мы обсуждаем методы восстановления данных, мы заверяем пользователя, что данные могут быть восстановлены с помощью некоторых общих или некоторых специальных усилий по восстановлению данных. Но восстановление данных не всегда является желаемой и ожидаемой функцией для всех.
Может быть много людей или организаций, которые всегда готовы стереть данные на своем диске таким образом, чтобы их невозможно было восстановить никаким образом. В таких случаях на диске могут быть ранее сохранены очень конфиденциальные данные, которые, попав в чужие руки, могут нанести вред организации или пользователю из-за неправильного использования информации.
Как мы знаем, потребность во все большем и большем пространстве на жестких дисках растет с каждым днем. В результате этого старые диски малой емкости заменяются новыми дисками большой емкости в больших масштабах каждый год почти в каждой организации. Если эти старые диски попадут в чужие руки, это может создать очень серьезную проблему для этой организации.
Согласно новостям, опубликованным CNET News.com 16 января 2003 года, студенты Массачусетского технологического института Саймон Гарфинкель и Эбби Шелат скупали старые жесткие диски в целях исследования в Интернете и на других распродажах подержанных дисков, чтобы получить доступ к огромным объемам личной информации, которую люди не удосуживаются стирать.
After buying 158 drives for around US$1000, they managed to collect over 5000 credit card number, medical records, detailed personal and corporate financial information and several gigabytes of e-mails, source codes and other information.
The pair of these students has compiled their findings into a report entitled "Remembrance of Data Passed: A Study of Disk Sanitation" published in the February edition of IEEE Security and Privacy.
The main points that have come out of the research are that the second-hand market for hard drives is filled with personal information making it very easy for a malicious buyer to assume the identity of someone else.
Writing program for Non–Destructive data wiper
The non-destructive data wiper is a kind of data wiping program by using which we can wipe out the entire “unallocated space” of the disk volume, without harming the data which is stored in disk, in any way.
The scope of such data wiper is in the cases, where you want to wipe out all the unallocated space of the disk volume while the allocated data stored in the volume should remain untouched. This type of data wiping program also wipes out the data area of deleted files.
The program coding for a type of non – destructive data wiping program has been given next:
///// Program for a Non Destructive Data Wiper \\\\\
#include <stdio.h>
unsigned int file_num=0; /* Provides File Number
During the Auto Creation
of Temporary Data files */
float status=0; /* How Much Disk space is
still Written */
static char dbuf[40000]; /* Data Buffer to write
Temporary Files with */
char file_extension[5]=".ptt";/* Unique Extensions for
Temporary Files */
char temp[5]; /* File Number converted to
String */
char filename[40]; /* Temporary File name */
void main()
{
unsigned int i=0;
clrscr();
while(i<40000)
{
dbuf[i] = ' ';
i++;
}
gotoxy(10,14);cprintf(" MB Still Written...");
while(1)
{
/* Logic to create temporary files automatically with unique name */
strcpy(filename,"TTPT");
itoa(file_num,temp,10);
strcat(filename,temp);
strcat(filename,file_extension);
file_num++;
write_to_temp(filename);
}
} //// End of Main \\\\
///// Function to write the data to temporary file \\\\\
write_to_temp(char *filename)
{
unsigned int i, count=1;
float buf_status=0;
FILE *tt;
if((tt=fopen(filename,"wb"))==NULL)
{
fclose(tt);
printf("\n Error occurred while creating temporary
file, ");
printf("\n Removing temporery Files After KEY BOARD
HIT");
getch();
remove_temp_file();/* Remove All temporary files */
}
while(1)
{
for(i=0;i<50;i++)
{
fprintf(tt,"%s",dbuf);
}
buf_status = (float)((40000*50*count)/512);
status= status+(40000*50);
count++;
gotoxy(10,14);
cprintf("%.0f",(float)(status/1000000));
if(kbhit())
{
fclose(tt);
printf("\n Removing Temporery Files, Please
Wait...");
remove_temp_file();
}
if(buf_status>=10000)
{
fclose(tt);
return;
}
}
}
/* Function to Delete the Temporary files automatically */
remove_temp_file()
{
int i=0;
for(i=0;i<=file_num;i++)
{
strcpy(filename,"TTPT");
itoa(i,temp,10);
strcat(filename,temp);
strcat(filename,file_extension);
remove(filename);
}
exit(1);
return 0;
}
Comments on logic and the coding of the program:
In this program basically we follow the following two steps to wipe the unallocated space of the disk:
- Create temporary data files automatically: First we create temporary files with unique names and having some data in them until the disk volume is full with these temporary data files. By doing this, all the unallocated data area of the logical drive is occupied by the data of the temporary files and all unallocated data is overwritten.
For doing this, I chose the names of temporary files in the TTPTxxxx.PTT format, which means, the first four characters of the temporary files are TTPT and the extension of the files is .PTT. It is done so to provide the temporary files the unique filenames.
I have set the maximum size of the single temporary file, equivalent to approximately 11,718 sectors data however you can define it according to you. I chose space character “ ” (ASCII character 32) to fill the data in temporary files. However random characters may also be used instead of space.
- Remove all temporary files: When the logical drive is full with temporary files, it indicates that all the unallocated data area is now overwritten. Now all the temporary files created by the program are removed automatically. And thus wiped out unallocated space is achieved.
In the coding of the program, the character array filename stores the file name to generate temporary files automatically, with different names.
The function write_to_temp(filename); fills the temporary file up to 11,718 sectors (because there is no occurrence of 10,000 sectors in specified group writing of buffer) equivalent data with help of data buffer dbuf of 40,000 bytes. 50 times data buffer is written at a time to speed up the writing.
The temporary files are created until the disk volume is full and file creation error occurs. The function remove_temp_file() removes all temporary file, created by the program.
In this way all the unallocated space is wiped out without harming the data of the disk volume.
Writing program for Destructive Data Wiper:
Destructive data wiping programs are those which write directly on the surface of the disk. This type of data wiping programs work on lower level than file system and operating system, which means that all the data and other logical information including OS, File systems, Directory entry and everything written on the disk is wiped out.
These data wiping programs directly wipe the sectors of the surface of the disk, and wipe out everything written on it. As all the data of the disk including operating system is lost, these programs as called destructive data wiping programs.
These types of wiping programs are preferred in such cases, where user is willing to overwrite everything on the disk, including Operating system and all the data on the disk.
However there are some more benefits of this type of data wiping programs. As these destructive data wiping programs work completely free from OS and File system and write directly on the surface of the disk, they are reasonably faster than the non-destructive data wipers.
Also, if any how logical bad sectors on the disk are created due to illegal storage of some random data, these logical bad sectors are also wiped out completely with the data of the disk.
The coding for a destructive data wiping program has been given next. The program has been written to support large size disks too. The program wipes the data of second physical hard disk connected to the computer.
///// Coding for a destructive data wiping program \\\\\
#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 writeabsolutesectors 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 */
} ;
///// Function to get Drive Parameters \\\\\
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 of INT 13H
Extensions */
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 */
}
void main()
{
unsigned long loop=0, Sectors_in_ HDD2=0;
unsigned char buffer[61440]; /* Data buffer of 61440
bytes Equivalent to
120 Sectors */
unsigned long i=0;
char choice;
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 Wipe the Data of Second Hard Disk.");
printf("\n Press any Key to Exit... ");
getch();
exit(1);
}
Sectors_in_HDD2 = getdrivegeometry (0x81);
printf(" Total Sectors in Second Hard Disk =
%lu\n\n",
Sectors_in_HDD2);
///// First Confirm, then Proceed \\\\\
printf("\n It is A Data Wiping Program, and Writes on
the Surface of the Disk,");
printf("\n After running this program, Data can not
be recovered by any Software,");
printf("\n All The Data in Second Hard Disk will be
lost !!!");
printf("\n Press \'Y\' to Continue, Else any key to
Exit... ");
choice = getche();
switch(choice)
{
case 'y':
case 'Y':
break;
default:
exit(0);
}
gotoxy(10,15);cprintf(" Initializing, Please Wait...");
for(i=0;i<61440;i++)
{
buffer[i]='\0';
}
gotoxy(10,15);cprintf(" ");
gotoxy(10,15);
printf("Currently Wiping Absolute Sector: ");
for(loop=0;loop<= Sectors_in_HDD2;loop=loop+120)
{
writeabsolutesectors (0x81, loop, 120, buffer);
gotoxy(44,15); printf("%ld",loop);
if(kbhit())
{
exit(0);
}
///// Display Message when completed \\\\\
printf("\n\n Data wiping is Now Completed, All the Data in
Second Hard Disk is now");
printf("\n Completely Erased, Press any Key to Exit...");
getch();
}
//// Function to Write Absolute Sector(s) \\\\
int writeabsolutesectors ( 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
be written */
/* 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 be written*/
pp.blocknumber[1] = 0 ; /* Block number = 0 */
i.h.ah = 0x43 ; /* Function Number */
i.h.al = 0x00 ; /* Write Flags */
i.h.dl = drive ; /* Physical Drive
number */
i.x.si = FP_OFF ( (void far*)&pp ) ; /* ds:si for
buffer Parameters */
s.ds = FP_SEG ( (void far*)&pp ) ; /* ds:si for
buffer Parameters */
/* 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
}
Comments on coding:
The structure geometry is used by getdrivegeometry function using INT 13H Extension, Function Number 0x48 to get the various parameters of the disk.
The structure diskaddrpacket is for Disk Address packet format, to be used by the writeabsolutesectors Function.
The Function getdrivegeometry (int drive) is to get Drive Parameters of the disk specified physical drive number drive. buffer [61440] is the data buffer of 61440 bytes, Equivalent to 120 Sectors.
(char) peekb(0x0040, 0x0075) is used to find the number of hard disks connected to the computer, stored at memory location represented by segment 0040H:offset 0075H. If total number of hard disks attached is less then two Display Error Message and Exit.
writeabsolutesectors ( 0x81, loop, 120, buffer ) function is used to write the data of data buffer on 120 sectors at a time starting from the absolute sector number specified by loop.
I chose ‘\0’ (NULL character, ASCII code 0) to write on the sectors to overwrite the data. However you can use random characters to overwrite the data.
For detailed description on Functions writeabsolutesectors and getdrivegeometry refer the chapters given earlier in this book.
Wiping Data Area of specific file
We discussed about the data wiping programs which wipe the data of unallocated space of the disk or wipe the entire disk. But if user is willing to wipe the data every time when he deletes the data, it may be a time taking process to wipe the entire unallocated space of the disk.
We need this type of data wiping programs to wipe the data area only occupied by that particular file. For doing this, we get the help from FAT and Root directory entries, to find the data area occupied by that particular files
Even in case of floppy, if the data is not fragmented, we can do so only with the help of Root directory information. The Following table shows the information stored by a root directory entry with 32 bytes, for any file:

As we see in the table of contents of root directory entry, we are capable to find the starting and ending cluster of the files. The first Byte of the filename may also contain some important information about file. The information given by this byte may be one of the given below:

Let us try this information to wipe the data of any file stored in 1.44Mb, 3 ½ inch floppy disk, with the help of root directory information. Assuming that the data in the floppy disk is not fragmented, the program given next wipes the data of specified file from its data area:
/* Program to wipe the data area of specified file in floppy disk */
#include<stdio.h>
#include<dos.h>
///// Structure to read 32 bytes of File Entry in Root Directory \\\\\
struct root
{
unsigned char filename[8]; /* File name Entry of
8 Bytes */
unsigned char extension[3]; /* Extension of File of
3 Bytes */
unsigned char attribute; /* File Attribute Byte */
unsigned char reserved[10]; /* Reserved Bytes 10 */
unsigned int time; /* Time, 2 Bytes */
unsigned int date; /* Date, 2 Bytes */
unsigned int starting_cluster;/* Starting Cluster of File,
2 Bytes */
unsigned long file_size; /* File Size in Bytes,
4 Bytes */
};
/* Should be taken this to read all Root Directory Entries */
//struct root entry[224];
/* Structure to read all 16 File entries in one Sector of Root Directory */
struct one_root_sector
{
struct root entry[16];
};
struct one_root_sector one;
void main()
{
int result, i, num_sectors,j;
char wipe_buf[512]; /* Data Buffer to be used to wipe
out the data Area of file */
clrscr();
result= absread(0x00, 1, 19, &one); /* Read Absolute Sector
19 (First Sector of Root Directory) */
if (result != 0)
{
perror("Error in Reading Sector, Press any key to
Exit...");
getch();
exit(1);
}
/* Display Files' Information after Reading from Root Directory */
printf(" FILE NO. FILENAME EXTENSION STARTING CLUSTER
FILESIZE \n\n");
for(i=1;i<16;i++)
{
printf("\n %5d %8.8s %3.3s %5u %10lu ",
i, one.entry[i].filename, one.entry[i].extension,
one.entry[i].starting_cluster, one.entry[i].file_size);
}
//// Get User Input To Delete The File \\\\
printf("\n\n Enter The File Number, you Want to Delete and
Wipe out Completely ");
scanf("%d", &i);
if(i<1 || i>15)
{
printf(" \"%d\" is an Invalid Choice..., Press any
Key to Exit...", i);
getch();
exit(1);
}
///// First Confirm, Then Continue \\\\\\
printf("\n You are About to wipe-out,
The File \"%.8s.%s\"",
one.entry[i].filename,
one.entry[i].extension);
printf("\n Do you Want to Continue...(Y/N) ");
switch(getche())
{
case 'y':
case 'Y':
break;
default:
exit(0);
}
///// Calculate The Size of File in Sectors \\\\\
num_sectors = one.entry[i].file_size/512;
if((one.entry[i].file_size%512)>0)
{
num_sectors = num_sectors+1;
}
/* Data buffer of 512 bytes with 512 NULL characters */
for(j=0;j<512;j++)
{
wipe_buf[j] = '\0';
}
///// Starting Sector of the File \\\\\
j= one.entry[i].starting_cluster+31;
/* Wipe out the data Area Until the Sectors of file End */
пока(j!=(one.entry[i].starting_cluster +
число_секторов+31) )
{
если((abswrite(0x00, 1, j, &wipe_buf))!=0)
{
printf("\n Ошибка записи в сектора диска");
получить();
выход(0);
}
j++;
}
printf("\n\n Файл \"%.8s.%.3s\" Удален !!!" ,
one.entry[i].имя_файла,
одна.запись[i].расширение);
one.entry[i].attribute = 0; /* Установка атрибута файла
до 0 */
one.entry[i].time = 0; /* Очищаем информацию о времени
файла */
one.entry[i].date = 0; /* Очищаем информацию о дате
файла */
one.entry[i].starting_cluster = 0; /* Устанавливаем начальный кластер на 0
*/
one.entry[i].file_size = 0; /* Устанавливаем размер файла на 0 */
one.entry[i].filename[0]=0xE5; /* Дать удаленные
Статус файла в файле */
///// Запишите вышеуказанную информацию в корневой каталог \\\\\\
результат = abswrite(0x00, 1, 19, &один);
если (результат != 0)
{
perror("Ошибка чтения сектора, нажмите любую клавишу для
Выход...");
получить();
выход(1);
}
}
Комментарии по логике и кодированию программы:
Структура root используется для чтения 32 байтов записи файла в корневом каталоге, а структура one_root_sector считывает все 16 записей файла в одном секторе корневого каталога.
Если вы хотите прочитать все секторы информации корневого каталога, вам следует взять ее как запись struct root[224]; однако я написал программу для анализа 16 записей только одного сектора корневого каталога.
Начальный сектор файла рассчитывается следующим образом:
j= один.запись[i].начальный_кластер+31;
Это сделано потому, что область данных дискеты 1,44 МБ, 3 ½ дюйма начинается после первых 32 секторов дискеты. А в дискете указанной емкости один кластер соответствует одному сектору.
В следующей таблице показана логическая карта дискеты размером 1,44 МБ и размером 3½ дюйма:

Результат работы программы отображается следующим образом:

Здесь мы удалили и стерли данные файла PARTBOOT.C. Когда мы видим содержимое дискеты с помощью команды DIR, файл PARTBOOT.C там не отображается. При дальнейшем выполнении программы запись удаленного файла отображается следующим образом:

Здесь символ «» (0xE5) означает, что файл был удален. (см. таблицу для первого символа имени файла).
Если вы хотите написать ту же программу для жесткого диска, вам также необходимо использовать FAT с корневым каталогом, чтобы получить информацию об области данных любого файла.
Это так, потому что скорость фрагментации данных на жестких дисках увеличивается со временем, поскольку старые файлы удаляются и создаются новые. Тогда нет необходимости, чтобы все кластеры данных любого файла на диске оставались один за другим непрерывно в области данных. Обращаясь к FAT, вы можете получить доступ ко всем этим кластерам.