Solved

how to delete a file

Posted on 2001-08-14
25
252 Views
Last Modified: 2010-04-06
My question has two parts in it:

1. is there a way to delete a file "securely" , i.e. so that it cannot at least be recovered using the DOS undelete command?

2. is there a way to read from the FAT the location(s) of the file (or its parts) on disk?

thanks for your help

yegor
0
Comment
Question by:yegor
  • 10
  • 5
  • 5
  • +4
25 Comments
 
LVL 7

Expert Comment

by:Motaz
Comment Utility
This is an answer for your first question:

function KillFile(FileName:string):boolean;
var
   f:file;
   Buf:array [0..1023] of byte;
   i:integer;
begin
 for i:=0 to SizeOf(Buf)-1 do
  Buf[i]:=0;

try
 AssignFile(f,FileName);
  FileMode:=2;   // Read and write access
  Reset(f);
  while not eof(f) do
    BlockWrite(f,Buf,SizeOf(Buf));
  CloseFile(f);
  Erase(f);
 except
 on e:exception do
 begin
   Result:=false;
   exit;
 end; // except
end; // try
Result:=true; // File successfully deleted
end;
0
 
LVL 22

Expert Comment

by:mnasman
Comment Utility
and look to this link for the second question

http://www.efg2.com/Lab/Library/Delphi/IO/DisksDrives.htm
0
 
LVL 2

Expert Comment

by:FrodoBeggins
Comment Utility
Motaz, I think you'd better use
  FillChar(Buf, SizeOf(buf), 0)
instead of
  for i:=0 to SizeOf(Buf)-1 do
    Buf[i]:=0;
It does the same, but faster :)

Rgds,
Frodo

0
 
LVL 4

Expert Comment

by:fva
Comment Utility
If you are interested:
AFAIK, DOD regulations on wiping data say something about overwriting some 7 times with alternating patterns like $AA and $55, then overwriting with zeros, then erasing.

F.
0
 
LVL 9

Expert Comment

by:ITugay
Comment Utility
yes.....
it sounds impossible but file may be read even after wiping it by "0". There is equipment that allow to read disk data on phisical level. Very expensive, but possible.

-----
Igor
0
 

Author Comment

by:yegor
Comment Utility

Montaz, Frodo,

sorry, on my machine this works in 3 cases out of 5 (the data is actually overwritten on disk), but the file is recoverable in all the cases. Sometimes the recovered file has only zeros in it, sometimes the original data. Anyways, I need something that does not allow any kind of recovery with undelete -- in many cases the name of the file itself (even if the first letter is missing) may in itself contain "sensitive data".

I have taken a look at the web page you suggest, but could not find there the answer to my second question. The unit floppy.pas (which pretends to give the number of the first cluster of data occupied by a file) does not work on my machine.

Please suggest something else... I need it badly.

Yegor
0
 

Author Comment

by:yegor
Comment Utility

Igor,

I do not speak about sophisticated equipment or peple stealing my HD and investigating it with the latest methods of modern technology... all I need is that the undelete command refuses to recover the file, and that the data is NOT present on the HD any more.

Yegor
0
 

Author Comment

by:yegor
Comment Utility

Igor,

I do not speak about sophisticated equipment or peple stealing my HD and investigating it with the latest methods of modern technology... all I need is that the undelete command refuses to recover the file, and that the data is NOT present on the HD any more.

Yegor
0
 
LVL 2

Accepted Solution

by:
FrodoBeggins earned 300 total points
Comment Utility
 AFAIK, the DOS command UNDELETE is uncapable to recover lost directories. I had many troubles with it, but that was many years ago. Try to create a subdirectory, move the file there (which moves only the entry in the FAT), delete the file and remove the directory. This should worlk for FAT (16 bit) I'm not sure if there is UNDELETE for FAT32 or NTFS.

  And for the name of the file - that's easy. Rename it before deletion. Only NTFS keeps transaction history, but it is very hard to read it.

Rgds,
Frodo
0
 
LVL 2

Expert Comment

by:FrodoBeggins
Comment Utility
Another suggestion. You may permanently destroy some file's data with the API function MoveFileEx. Create an empty file, and call MoveFileEx so it overwrites the unwanted file. Remember to specify MOVEFILE_REPLACE_EXISTING flag on the third parameter, dwFlags. That surely wipes out the file data. For the file name removal you can use rename before to start everything.

Rgds,
Frodo
0
 
LVL 2

Expert Comment

by:FrodoBeggins
Comment Utility
Hehe. Here's anothe method to use for data wipeout using Win32 API:

var hFile : THandle;
begin
  hFile := FileOpen('badfile.txt', fmOpenReadWrite); // gets file handle
  if hFile <> INVALID_HANDLE_VALUE then
    try
      SetFilePointer(hFile, 0, nil, FILE_BEGIN); //moves the file pointer to 0 bytes after the file start
      SetEndOfFile(hFile); // truncates the file to the file pointer :-)
    finally
      CloseHandle(hFile);
    end;

This should be faster than all previous suggestions :)

Rgds,
Frodo
0
 
LVL 2

Expert Comment

by:FrodoBeggins
Comment Utility
AND to prevent any caching (definitely used if it is a remote file) use

var hFile : THandle;
begin
  hFile := FileOpen('badfile.txt', fmOpenReadWrite); // gets file handle
  if hFile <> INVALID_HANDLE_VALUE then
    try
      SetFilePointer(hFile, 0, nil, FILE_BEGIN); //moves the file pointer to the first byte in the file
      SetEndOfFile(hFile); // truncates the file to the file pointer
      FlushFileBuffers(hFile);
    finally
      CloseHandle(hFile);
    end;

Rgds,
Frodo
0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 
LVL 9

Expert Comment

by:ITugay
Comment Utility
Hi yegor,

here is procedure that can help you:


procedure WipeFile(const FileName: String);

const
  BufSize = 8192;

var
  F: TFileStream;
  Buf: array[0..BufSize-1] of byte;
  Cnt: Integer;

begin
  FillChar(Buf, BufSize, $FF);

  F := TFileStream.Create(FileName, fmOpenWrite or fmShareExclusive);
  try
    Cnt := F.Size;
    while Cnt > 0 do
    begin
      F.Write(Buf, BufSize);
      Cnt := Cnt - BufSize;
    end;
    FlushFileBuffers(F.Handle);
    F.Seek(0, soFromBeginning);
    SetEndOfFile(F.Handle);
    FlushFileBuffers(F.Handle);
  finally
    F.Free;
  end;
  DeleteFile(FileName);
end;

0
 
LVL 2

Expert Comment

by:FrodoBeggins
Comment Utility
Not "the first byte". _Before_ the first byte.

Rgds,
Frodo
0
 
LVL 9

Expert Comment

by:ITugay
Comment Utility
Hi yegor,

one important thing, add this line to the procedure just after "begin" operator:

  SetFileAttributes(PChar(FileName), 0);

It allow you to wipe read-only files.
0
 
LVL 2

Expert Comment

by:FrodoBeggins
Comment Utility
Yes, Igor, that should work too. But you need the file to be 8K or Xx8K. Or the last F.Write(8K buffer) will fail, I think

Rgds,
Frodo
0
 
LVL 9

Expert Comment

by:ITugay
Comment Utility
no Frodo,
be sure, just  file become litle-bit bigger (looks like bigger, don't forget about cluster size).  

-----
Igor.
0
 
LVL 2

Expert Comment

by:FrodoBeggins
Comment Utility
You mean the memory granularity? I think it is 4k on x86, MIPS and PowerPC. 8k is on Alpha.

Anyway, if it works - NP :)

Rgds,
Frodo
0
 

Author Comment

by:yegor
Comment Utility

Hi all,

thank you very much. I think now I _should_ have got all the info necessary to create a kind of relatively secure deletion procedure. By the bye, is not Truncate(File) doing the same as the method using SetEndOfFile ? Now the biggest problem is to decide whom my points go to, since every one's participation seems very useful to me... Any suggestions? thanks, yegor

P.S. That's what I am doing to check things:

1. create a file named "description_of_the_pleasant_day_on_which_i_killed_john_smith.txt" (as you see, it's MUCH better if the file name cannot be restored!),

2. write some bogus text into it,

3. find this text on the disk using a hex editor,

4. delete,

5. restart and try to "undelete",

6. go to the same location on HD and see whether the data has remained the same THERE (it must not, even if the file has not been restored with undelete, for otherwise the police could search the HD for keywords like "John Smith" and...).
0
 
LVL 6

Expert Comment

by:Stuart_Johnson
Comment Utility
Hi All,

Unfortunately no matter what you do using these methods, the file will still be allocated space until something else writes over it's space, thus deleting it from the allocation table.  Even when it is deleted from the allocation table, utilities like Norton's Unerase can usually recover the file.

I've been having a bit of a read up on file recovery, and even if a disk is low level formatted, the data can still be recovered using a negative image overlay.  And these overlays can be continually applied until there is no magnetic image left on the disk to check against.  I'm not exactly sure how many times it can be done, but according to the book I'm reading now, evidence can be recovered from someone's computer even after overwriting the same sectors six or seven times (sometimes more).

The only way I know of that would give you slight piece of mind is firstly use the DOD method of six overwrites with alternate patterns, then modify the file allocation table and remove the refrence to the file.  I dont think that is possible to do in Delphi.

Even overwriting the original file with different patterns and then deleting the file, you will still be left with an unerasable file with the same name (and in the example you posted, it could be incriminating evidence enough <G>).

I guess you could try renaming the file first and then writing all the crap data to it, and then delete it.

Interesting thread none the less!!

Stu
0
 
LVL 2

Expert Comment

by:FrodoBeggins
Comment Utility
Wau! Stu, it seems the only way to hide my murders is to use some very hard and heavy "object", like 20 Lbs hammer. And maybe the good restore procedure could spot me even then! :-)

Unfortunately Delphi can't control such objects. Fortunately we are fihting just against DOS "undelete".

And what if we set the different patterns in some different threads? Does this help, Stu? ;-))

Rgds,
Frodo
0
 
LVL 2

Expert Comment

by:FrodoBeggins
Comment Utility
Well, if we can't wipe the contents of the file, let's give it to "the police". Hidden. Something like:
1. Fill the file with zeroes, or FFs, or random data.
       FlushFileBuffers(hFile);
2. Encrypt the file using AES (or some other algorithm)
       FlushFileBuffers(hFile);
3. Rename the file
       FlushFileBuffers(hFile);
4. Delete the file

After undeletion the file will seem to have real data. Someone may even try to decrypt it. Someone may even decrypt it :)

Rgds,
Frodo
0
 
LVL 4

Expert Comment

by:fva
Comment Utility
Then they will twist your thumbs until you give out the password that decrypts the file to some readable text :))

F.
0
 
LVL 9

Expert Comment

by:ITugay
Comment Utility
Hi Yegor,

>>6. go to the same location on HD and see whether the
>>data has remained the same THERE (it must not, even
>>if the file has not been restored with undelete, for
>>otherwise the police could search the HD for keywords
>>like "John Smith" and...).

I'm guessed what is the problem. Seems it happens regarding BufSize = 8192. Once the system going to write 8K over the file less then 8K, sectors reallocated to other disk location. Changing BufSize = 512 should solve this problem.

But if your file that keep important information has been modified few times then there is no any gurantee that disk has only one instance of your data. Old instances can be found in different locations of HDD.

------
Igor.

PS: I though that Truncate and SetEndOfFile is the same.

0
 

Author Comment

by:yegor
Comment Utility

Hi all,

thanks again to every one. On consideration, my points go to Frodo, since he has suggested a very good and efficient thing (deleting the whole dir containing the file in question -- this is all right at least for temporary files which we always can create where we want), and the only one I did not think of. If somebody's interested, here's the code which seems to work well enough -- at least on my machine:

// quick "secure" deletetion of a file
function QSDelete(F: String; P: Integer): Boolean;
var
S: Integer;
Buffer1: array[0..131071] of byte;
Buffer2: array[0..131071] of byte;
Buffer3: array[0..131071] of byte;
Source: file;
i, ii: integer;
NewF: string;
Path: String;
SR: TSearchRec;
Atts, NewAtts: Word;
label kk;
begin
Result := True;
if P < 5 then P := 5;
Path := ExtractFilePath(F);
if Path[Length(Path)] <> '\' then Path := Path + '\';
// fill buffers
FillChar(Buffer1, SizeOf(Buffer1), 255);
FillChar(Buffer2, SizeOf(Buffer2), 170);
FillChar(Buffer3, SizeOf(Buffer3), 0);
// get file size
if FindFirst(F, faAnyFile, SR) <> 0 then
      begin
        Result := False;
        FindClose(SR);
        goto kk;
      end else
      begin
        S := SR.Size;
        Atts := FileGetAttr(SR.Name);
        NewAtts := Atts;
        NewAtts := NewAtts and not faReadOnly;
        FileSetAttr(Path + SR.Name, NewAtts);
        FindClose(SR);
      end;
AssignFile(Source, F);
FileMode := 2;
// overwriting original data
ii := 0;
while ii < P do
begin
    Reset(Source, 1);
    // first overwrite
    i := 0;
    repeat
    BlockWrite(Source, Buffer1, SizeOf(Buffer1));
    i := i + SizeOf(Buffer1);
    until i >= S;
    Seek(Source, 0);
    // second overwrite
    i := 0;
    repeat
    BlockWrite(Source, Buffer2, SizeOf(Buffer2));
    i := i + SizeOf(Buffer2);
    until i >= S;
    Seek(Source, 0);
    // third overwrite
    i := 0;
    repeat
    BlockWrite(Source, Buffer3, SizeOf(Buffer3));
    i := i + SizeOf(Buffer3);
    until i >= S;
    CloseFile(Source);
Inc(ii);
end;
  Reset(Source);
  Truncate(Source);
  CloseFile(Source);
NewF := Path + 'uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu...uuuuuuu';
if RenameFile(F, NewF)
   then AssignFile(Source, NewF)
      else begin
             Result := False;
             goto kk;
           end;
  Reset(Source);
  Truncate(Source);
  CloseFile(Source);
  Erase(Source);
  // create an empty file with the same name
  // as the erased original file
  AssignFile(Source, F);
  Rewrite(Source);
  Truncate(Source);
  CloseFile(Source);
  Erase(Source);
kk:
end;

yegor
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now