The MASM Forum Archive 2004 to 2012

General Forums => The Workshop => Topic started by: white scorpion on July 02, 2006, 11:37:22 AM

Title: Securely deleting files
Post by: white scorpion on July 02, 2006, 11:37:22 AM
Hi all,

I've written a small function which should securly delete the input file.
I want to implement this in TableCrypt (http://www.white-scorpion.nl/programs/TableCryptBeta/index.html) to delete the original file if a user wants to do so.

Now i know the content of the file isn't going to be retrievable by software solutions, but how about hardware solutions?
Would it be better to overwrite the file multiple times with the same data, or multiple times with different data?

I don't have the technical skills and stuff to test this, so anyone who does is highly encouraged to tell his view on this.

here's the code which deletes file 'test.txt' 10 times:

.686                     
.model flat, stdcall     
option casemap :none   

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc


includelib \masm32\lib\masm32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib

RemoveFile              PROTO :DWORD, :DWORD
GenerateRandomByte      PROTO

.data
FileName    db 'test.txt',0
AppName     db 'Sdel v1.0 - White Scorpion',0
Format      db '%s %d %s',0
Firstline   db 'File overwritten ',0
Secondline  db ' times successfully',13,10,'and deleted afterwards.',0
base        dw 256
.data?
mybuf       db 128 dup (?)
myseed      dd ?

.code
start:

invoke RemoveFile,addr FileName,10
invoke ExitProcess,0

RemoveFile proc file_to_delete:DWORD,number_of_times:DWORD
    LOCAL hFile:DWORD
    LOCAL inputfilesize:DWORD
    LOCAL hMap:DWORD
    LOCAL myoffset:DWORD

    cmp number_of_times,0
    jnz @F 
    xor eax,eax
    dec eax
    ret
@@:
    invoke CreateFile,file_to_delete,GENERIC_WRITE + GENERIC_READ, 0, NULL, OPEN_EXISTING,\
    FILE_ATTRIBUTE_NORMAL, NULL
    mov hFile,eax
    invoke GetFileSize,eax,NULL
    mov inputfilesize,eax
    invoke CreateFileMapping,hFile,NULL,PAGE_READWRITE,0,0,NULL
    .if eax==NULL
@@:
        invoke CloseHandle,hFile
        xor eax,eax
        dec eax
        ret
    .endif   
    mov hMap,eax
    invoke MapViewOfFile,hMap,FILE_MAP_WRITE,0,0,0
    .if eax==NULL
        invoke CloseHandle,hMap
        jmp @B
    .endif
    mov myoffset,eax
;----First Round Start ----   

    xor ebx,ebx
    mov ecx,inputfilesize
@@:
    mov byte ptr [eax],bl
    inc eax
    dec ecx
    jnz @B   
    invoke FlushViewOfFile,myoffset,inputfilesize
;----First Round End ------

    .if number_of_times>1
;---- Second Round Start ----   
        mov eax,myoffset
        xor ebx,ebx
        dec ebx
        mov ecx,inputfilesize
@@:
        mov byte ptr [eax],bl
        inc eax
        dec ecx
        jnz @B 
        invoke FlushViewOfFile,myoffset,inputfilesize
;---- Second Round End ------
    .endif

;----Rest of Rounds Start -----
    .if number_of_times>2
        invoke GetTickCount
        mov myseed,eax
        mov edx,number_of_times
        sub edx,2
times_loop:
        mov ecx,inputfilesize
        push myoffset
        pop esi
        push edx
@@:
        push ecx
        push esi
        invoke GenerateRandomByte
        pop esi
        pop ecx
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        invoke FlushViewOfFile,myoffset,inputfilesize
        pop edx
        dec edx
        jnz times_loop     
;----Rest of Rounds End ------- 
    .endif
 
    invoke FlushViewOfFile,myoffset,inputfilesize
    invoke UnmapViewOfFile,myoffset
    invoke CloseHandle,hMap
    invoke CloseHandle,hFile
    invoke DeleteFile,file_to_delete
    push offset Secondline
    push number_of_times
    push offset Firstline
    push offset Format
    push offset mybuf
    call wsprintf
    invoke MessageBoxA,NULL,addr mybuf,addr AppName,MB_OK
    xor eax,eax
    ret
RemoveFile endp


GenerateRandomByte proc
        mov eax,myseed
        mov ebx,127923
        mul ebx
        xor eax,479573
        xor eax,edx
        mov myseed,eax
        xor edx,edx
        div base
        mov eax,edx
        ret
GenerateRandomByte endp

end start

Title: Re: Securely deleting files
Post by: TNick on July 02, 2006, 12:04:46 PM
I don't knew if you read this section in WorkShop (WriteFile <-> HadrDrive <-> Data Recovery ); there were some interesting replies on this matter
Title: Re: Securely deleting files
Post by: Ratch on July 02, 2006, 02:26:50 PM
White Scorpion,

     That is a heavy subject you are playing with.  I once saw a TV interview with a computer whiz about securely erasing files.  He said that they can recover more than 80% of the data after the hard disk has been reformatted.  He also said that a lot of programs aver that they complete erase data, but very few really do it correctly.  My file manager is ZTREE, which features a disk "wash" with a selection of 3 methods.  They are writing with nulls, random, or the "Department of Defense sanitization method".  If you GOOGLE for "erase files", you can find a lot of programs and info about this subject.  Anyway, it is unlikely that an uninitiated hacker will come up with a secure erase algo.  From what I seen about this subject, it is going to take study, research, and knowledge that one person is unlikely to be able find out about just by theorizing on their own.  I tried washing a 3" floppy with ZTREE, and it took longer than formatting it would have.  Ratch
Title: Re: Securely deleting files
Post by: Mark Jones on July 02, 2006, 03:07:06 PM
If you REALLY want the data destroyed, nothing beats a sledge hammer or chunk of thermite... :U
Title: Re: Securely deleting files
Post by: asmfan on July 02, 2006, 03:33:19 PM
I think that the layer of API abstraction cannot give the full access over what happens on h/w (HDD in particular). The idea of writing random bits is good. You can also compare to a different standarts of secure deletion of data, there are a lot of them... From writing 0's and/or 1's for several times to mixing them all in a different sequence... These standards are fully documented and considered more or less secure and used on huge productions
Title: Re: Securely deleting files
Post by: Darrel on July 02, 2006, 05:22:13 PM
Here's a program I wrote a while back that overwrites a file with 0's then 1's a specified number of times. Simply place it or a shortcut in your SendTo folder then you can right click on any folder or file and send it to DigitalShredder. Source is included.

Regards,

Darrel

Edit: See my next post for corrected file.
Title: Re: Securely deleting files
Post by: white scorpion on July 02, 2006, 07:36:33 PM
QuoteFrom what I seen about this subject, it is going to take study, research, and knowledge that one person is unlikely to be able find out about just by theorizing on their own.
There's no need to re-invent the wheel.
These studies have already been performed.
i've did quite some research about it a few years ago since i wanted to know more about it and perform data recoveries.

Like i said, no software solution will retrieve these files. But that's not a problem to fix, most programs are capable of doing so. If you keep the file on the original location and overwrite that location (which you can do using the windows API's) then there is nothing to worry about.
However, by changing the location of the head against the platters you can read the outside of a sector and read data that has not been overwritten yet (by time).

QuoteI don't knew if you read this section in WorkShop (WriteFile <-> HadrDrive <-> Data Recovery ); there were some interesting replies on this matter
I did read it, but decided to start my own thread since i don't want to waste the threadstarters thread.

In theory, if you would write the same random bytes of data multiple times the magnetic field of the bits should get stronger and so making it harder to retrieve the original bits. However, in the time i've spend learning on the subject i still don't have a good number of times needed to securely erase a file.
Formatting a harddisk doesn't help because often you aren't overwriting all bytes, and even if you do (full format), the same problem with the head vs platter occurs.
If a harddisk has just been formatted, it's quite easy (for someone with the technical knowledge and equipment) to retrieve the data.

According to our government standards you should overwrite a file at least 3-4 times. However, if these 3 to 4 times would be random data at all times, then in my opinion it wouldn't be as strong as 3 - 4 times with the same random data every time.
This is the main subject on my question, i would like to hear your opinions about the subject.

here (http://www.actionfront.com/ts_dataremoval.aspx) is a nice article on the subject. In the time i was studying the subject i've also spoken to some of the guys of this company.
However, since this is information they don't really want to share, it's something i decided to ask here, since here most people are willing to share information.

Quote
If you REALLY want the data destroyed, nothing beats a sledge hammer or chunk of thermite..
Could you give me the sourcecode for this approach?  :bg

Title: Re: Securely deleting files
Post by: Mark Jones on July 02, 2006, 08:44:30 PM
Quote from: White Scorpion on July 02, 2006, 07:36:33 PM
Quote
If you REALLY want the data destroyed, nothing beats a sledge hammer or chunk of thermite..
Could you give me the sourcecode for this approach?  :bg

Well, if you happen to have the CPU heatsinked to the HDD and execute this code, it should work about the same as thermite:


loopit:
    RDTSC
    jmp loopit
Title: Re: Securely deleting files
Post by: white scorpion on July 02, 2006, 08:57:34 PM
QuoteWell, if you happen to have the CPU heatsinked to the HDD
I doubt that will be the case.. why this instruction?
Doesn't any endless instruction heat up the cpu?

Title: Re: Securely deleting files
Post by: Mark Jones on July 02, 2006, 10:52:02 PM
Oh come on, it's a joke! :U
Title: Re: Securely deleting files
Post by: white scorpion on July 03, 2006, 06:25:45 AM
I know,
but i've never seen above instruction before, so it's something not used that often.
That's why i wondered why you choose exactly that instruction, even for a joke.

Btw, there were times when people actually believed that with an endless loop your whole computer would explode.
Although the cpu can be heated up, an intel cpu will stop working around 75 degrees celsius.
I believe amd is around 85-90 degrees.
I still don't get why it would explode ;)
Title: Re: Securely deleting files
Post by: Mark_Larson on July 03, 2006, 03:40:42 PM
Quote from: Ratch on July 02, 2006, 02:26:50 PM
White Scorpion,

     That is a heavy subject you are playing with.  I once saw a TV interview with a computer whiz about securely erasing files.  He said that they can recover more than 80% of the data after the hard disk has been reformatted.

That's because when you reformat a HD it doesn't erase any of the data.  It simply does a read-verify of all the sectors.   That's a common misconception that people have that formatting their drive erases their data.  That's why you hear people trying to do "low level formats" to get around issues like this.  Scorpions solution looks workable, I'll have to peruse it more carefully when I get the chance.



Quote from: Ratch on July 02, 2006, 02:26:50 PM
  He also said that a lot of programs aver that they complete erase data, but very few really do it correctly.  My file manager is ZTREE, which features a disk "wash" with a selection of 3 methods.  They are writing with nulls, random, or the "Department of Defense sanitization method".  If you GOOGLE for "erase files", you can find a lot of programs and info about this subject.  Anyway, it is unlikely that an uninitiated hacker will come up with a secure erase algo.  From what I seen about this subject, it is going to take study, research, and knowledge that one person is unlikely to be able find out about just by theorizing on their own.  I tried washing a 3" floppy with ZTREE, and it took longer than formatting it would have.  Ratch

  There are probably other solutions that are workable.  I'll have to see if I can dig up my copy of Norton Diskeditor to see if how well Scorp's code works.  Anyone else have a copy of Norton Diskeditor that can try in case I can't find my copy?

It basically let's you look at the disk at the low level.  you see the Root directory, fat tables, partition tables, sectors, etc.  You can modify it all directly.  I would keep backups of my first sector.  If I virus overwrote it, I could use Norton Diskeditor to write a new copy.  It supported saving different sectors to a file.

Title: Re: Securely deleting files
Post by: white scorpion on July 03, 2006, 05:00:50 PM
although no norton disk editor, but this cd (free of course), has some utilities which allow you to edit and view sectors of the harddisk:
http://www.ultimatebootcd.com/

I've used the cd quite often to solve partition problems, doing memtests and a whole lot more..
Title: Re: Securely deleting files
Post by: skywalker on July 03, 2006, 10:08:33 PM
Quote from: Mark Jones on July 02, 2006, 03:07:06 PM
If you REALLY want the data destroyed, nothing beats a sledge hammer or chunk of thermite... :U

That would waste the disk, a strong magnet works much better.

Title: Re: Securely deleting files
Post by: Mark Jones on July 03, 2006, 10:54:32 PM
...and have you tried this?

How strong is "strong?"

AFAICR, the magentic field strength at the track-level is very high because of the way the head channels the magnetic lines of force into the platter. I doubt even rubbing a neodymium straight on the disk surface itself would do much good, although I could be mistaken.
Title: Re: Securely deleting files
Post by: white scorpion on July 04, 2006, 06:33:48 AM
Lol..
What i did in the past was freezing the disk, and then hitting it on the table one time with a lot of power.
The platter totally shatters in pieces.
This definitely makes retrieving data much more difficult...

But to be honest, i don't care about hardware solutions to destroy data because there are some minor issues with that:
- unable to implement that in my program
- often it's unreversable. Once a harddisk is damaged, you can't fix it anymore.
- the user wouldn't be too happy if my program would destroy part of his computer.
- you can't specify the data you want to destroy. It's all or nothing.

So i need a software solution which also protects against hardware recovery.
Title: Re: Securely deleting files
Post by: Tedd on July 04, 2006, 01:31:27 PM
repeat 10 (or more :wink) times:
- val = random number (byte)
- repeat 10: fill file-data with val
- val = neg(val)
- repeat 10: fill file-data with val

The point of negating the value is to attempt to corrupt the 'echos' which are left on the disk surface when you write data, which can be used for advanced recovery.
I can't say this will make the data completely unrecoverable, but the only way you can assure that is to burn/destroy the disk platters.

Also, consider the file-system structures which will indicate where the file-data was, not just the file-data itself. While a cluster-chain will only tell you where the file was, this at least limits the sectors you have to attempt recovery on.
Title: Re: Securely deleting files
Post by: skywalker on July 04, 2006, 01:58:39 PM
Quote from: Mark Jones on July 03, 2006, 10:54:32 PM
...and have you tried this?

How strong is "strong?"

AFAICR, the magentic field strength at the track-level is very high because of the way the head channels the magnetic lines of force into the platter. I doubt even rubbing a neodymium straight on the disk surface itself would do much good, although I could be mistaken.

I used a magnet about 1 x 3 inch. It works quite well. Try it out.
Title: Re: Securely deleting files
Post by: white scorpion on July 04, 2006, 02:23:12 PM
QuoteAlso, consider the file-system structures which will indicate where the file-data was, not just the file-data itself. While a cluster-chain will only tell you where the file was, this at least limits the sectors you have to attempt recovery on.
I agree, but as far as i know there is no way of doing this without the use of a driver. This means that the application has to be installed or at least run with administrator privileges.
I want to keep the app available for everyone, it should even work on a guest account.
That's why i decided to implement it like this. If you know of a way to do this without elevated privileges then i really want to hear about it.

to neg the value. as far as i know i can do either:

not eax

or

xor eax,0FFFFFFFFh

the not instruction uses 2 bytes, xor uses 3. so that means that not eax would be best?
Title: Re: Securely deleting files
Post by: Mark Jones on July 04, 2006, 03:42:07 PM
Generate a seeded random-number stream for each file or for linear sectors... write it unmodified, then write each byte logical-NOT, unmodified, not, unmodified, not...
Title: Re: Securely deleting files
Post by: arafel on July 04, 2006, 03:51:43 PM
Quote from: skywalker on July 04, 2006, 01:58:39 PM
I used a magnet about 1 x 3 inch. It works quite well. Try it out.

Good thing you didn't said it was one of those flexible magnets as well  :green

All recent hdrives come with appropriate shielding. For completely destroying the data you'll need at least a 10inch neodymium-iron-boron magnet in order for it to be able to penetrate the shielding. For a "no name" ancient hard drive a 5" magnet will be sufficient probably.

I can tell you for sure that a circular 2" in diameter/0.2" thick, bipolar, nib magnet placed on a ten years old Seagate drive for two weeks hadn't made any damage.
Title: Re: Securely deleting files
Post by: skywalker on July 04, 2006, 05:54:40 PM
I only used the magnet on a floppy disk.

Title: Re: Securely deleting files
Post by: white scorpion on July 04, 2006, 07:02:03 PM
QuoteGenerate a seeded random-number stream for each file or for linear sectors... write it unmodified, then write each byte logical-NOT, unmodified, not, unmodified, not...
So that would be something like:

mov byte ptr [eax],bl
not ebx
mov byte ptr [eax],bl
not ebx

etc
etc

but in the mean time flushing it to disk as well.
That's pretty easy to implement ;)
Will post source shortly.

[update]
here's the resulting code:

.686                     
.model flat, stdcall     
option casemap :none   

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc

includelib \masm32\lib\kernel32.lib

RemoveFile              PROTO :DWORD, :DWORD
GenerateRandomByte      PROTO

.data
FileName    db 'test.txt',0
base        dw 256
.data?
myseed      dd ?

.code
start:

invoke RemoveFile,addr FileName,10
invoke ExitProcess,0

RemoveFile proc file_to_delete:DWORD,number_of_times:DWORD
    LOCAL hFile:DWORD
    LOCAL inputfilesize:DWORD
    LOCAL hMap:DWORD
    LOCAL myoffset:DWORD
    LOCAL backup:DWORD

    cmp number_of_times,0
    jnz @F 
    xor eax,eax
    dec eax
    ret
@@:
    invoke CreateFile,file_to_delete,GENERIC_WRITE + GENERIC_READ, 0, NULL, OPEN_EXISTING,\
    FILE_ATTRIBUTE_NORMAL, NULL
    mov hFile,eax
    invoke GetFileSize,eax,NULL
    mov inputfilesize,eax
    invoke CreateFileMapping,hFile,NULL,PAGE_READWRITE,0,0,NULL
    .if eax==NULL
@@:
        invoke CloseHandle,hFile
        xor eax,eax
        dec eax
        ret
    .endif   
    mov hMap,eax
    invoke MapViewOfFile,hMap,FILE_MAP_WRITE,0,0,0
    .if eax==NULL
        invoke CloseHandle,hMap
        jmp @B
    .endif
    mov myoffset,eax
;----Rounds Start -----
        invoke GetTickCount
        mov backup,eax
        mov edx,number_of_times
times_loop:
        mov eax,backup
        mov myseed,eax
        mov ecx,inputfilesize
        push myoffset
        pop esi
        push edx
@@:
        invoke GenerateRandomByte
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        invoke FlushViewOfFile,myoffset,inputfilesize
        mov eax,backup
        mov myseed,eax
        mov ecx,inputfilesize
        push myoffset
        pop esi
@@:
        invoke GenerateRandomByte
        not eax
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        invoke FlushViewOfFile,myoffset,inputfilesize
        pop edx
        dec edx
        jnz times_loop     
;----Rounds End ------- 
    invoke UnmapViewOfFile,myoffset
    invoke CloseHandle,hMap
    invoke CloseHandle,hFile
    invoke DeleteFile,file_to_delete
    xor eax,eax
    ret
RemoveFile endp


GenerateRandomByte proc
        mov eax,myseed
        mov ebx,127923
        mul ebx
        xor eax,479573
        xor eax,edx
        mov myseed,eax
        xor edx,edx
        div base
        mov eax,edx
        ret
GenerateRandomByte endp

end start


IMO i can implement it safely. Even if it wouldn't be secure (which i doubt), it will always be more secure then just deleting the file ;)
Title: Re: Securely deleting files
Post by: white scorpion on July 05, 2006, 09:00:00 PM
for those interested.
I've been given some tips and suggestions by f0dder (http://www.asmcommunity.net/board/index.php?topic=24986.0) which resulted in the following code:

RemoveFile proc file_to_delete:DWORD,number_of_times:DWORD
    LOCAL hFile:DWORD
    LOCAL inputfilesize:DWORD
    LOCAL backup:DWORD
    LOCAL BytesWr:DWORD
    LOCAL shredbuf[1024*10]:BYTE
    LOCAL buffer_times:DWORD
    LOCAL my_remainder:DWORD

    cmp number_of_times,0
    jnz @F 
    xor eax,eax
    dec eax
    ret
@@:
    invoke CreateFile,file_to_delete,GENERIC_WRITE, 0, NULL, OPEN_EXISTING,\
    FILE_ATTRIBUTE_NORMAL or FILE_FLAG_NO_BUFFERING, NULL
    .if eax==INVALID_HANDLE_VALUE
        xor eax,eax
        dec eax
    ret
    .endif   
    mov hFile,eax
    invoke GetFileSize,eax,NULL
    mov ebx,512
    xor edx,edx
    div ebx
    .if edx==0
        mul ebx
    .else
        mul ebx
        add eax,512
    .endif       
    mov inputfilesize,eax
   
;----Rounds Start -----
    invoke GetTickCount
    mov backup,eax
    mov myseed,eax
   .if inputfilesize<=sizeof shredbuf
        mov edx,number_of_times
times_loop_small:
        push edx       
        mov ecx,inputfilesize 
        lea esi,shredbuf       
@@:
        invoke GenerateRandomByte
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        mov eax,backup
        mov myseed,eax
        invoke SetFilePointer,hFile,0,0,FILE_BEGIN
        invoke WriteFile,hFile,addr shredbuf,inputfilesize,addr BytesWr,NULL
        mov ecx,inputfilesize
        lea esi,shredbuf
@@:
        invoke GenerateRandomByte
        not eax
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        invoke SetFilePointer,hFile,0,0,FILE_BEGIN
        invoke WriteFile,hFile,addr shredbuf,inputfilesize,addr BytesWr,NULL
        pop edx
        dec edx
        jnz times_loop_small   
;----Rounds End ------- 
    .else
        mov eax,inputfilesize
        mov ebx,sizeof shredbuf
        xor edx,edx
        div ebx
        mov buffer_times,eax
        mov my_remainder,edx
        mov edx,number_of_times
times_loop_big:
        push edx
        invoke SetFilePointer,hFile,0,0,FILE_BEGIN
        mov eax,buffer_times
bufloop1: 
        push eax     
        mov ecx,sizeof shredbuf
        lea esi,shredbuf       
@@:       
        invoke GenerateRandomByte
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        invoke WriteFile,hFile,addr shredbuf,sizeof shredbuf,addr BytesWr,NULL
        pop eax
        dec eax
        jnz bufloop1
        mov ecx,my_remainder
        .if ecx==0
            jmp second_round
        .endif
        lea esi,shredbuf
@@:
        invoke GenerateRandomByte
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        invoke WriteFile,hFile,addr shredbuf,my_remainder,addr BytesWr,NULL   
second_round:             
        invoke SetFilePointer,hFile,0,0,FILE_BEGIN
        mov eax,buffer_times
bufloop2:   
        push eax   
        mov ecx,sizeof shredbuf
        lea esi,shredbuf
@@:       
        invoke GenerateRandomByte
        not eax
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        invoke WriteFile,hFile,addr shredbuf,sizeof shredbuf,addr BytesWr,NULL
        pop eax
        dec eax
        jnz bufloop2
        mov ecx,my_remainder
        .if ecx==0
            jmp finish_round
        .endif
        lea esi,shredbuf
@@:
        invoke GenerateRandomByte
        not eax
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        invoke WriteFile,hFile,addr shredbuf,my_remainder,addr BytesWr,NULL       
finish_round:
        pop edx
        dec edx
        jnz times_loop_big
    .endif       
    invoke CloseHandle,hFile
    invoke DeleteFile,file_to_delete
    xor eax,eax
    ret
RemoveFile endp

No mapping to memory anymore, directly writing to disk. This function goes with a rate of 2,4MB's per second for deletion (if you give argument 5) on a 1600 mhz computer with a 4200rpm disk.
while doing so, it runs at 50% cpu, so it could be even faster on a faster machine.
The total write rate is 24mb's per second, so it closely matches my harddisk speed.

i've implemented it in TableCrypt (http://www.white-scorpion.nl/programs/TableCryptBeta/index.html) and in Shredder (http://www.white-scorpion.nl/programs/shredder.zip).

Title: Re: Securely deleting files
Post by: asmfan on July 05, 2006, 09:35:42 PM
Scorp, some suggestions- CreateFile returns (-1) if unable to obtain a handle so compare to it, and you shouldn't close -1 handle:). The second when writing to file file pointer automatically moving. So set it up only on the beginnig of new round. The rest will be later...
Title: Re: Securely deleting files
Post by: asmfan on July 05, 2006, 09:47:21 PM
Also i would suggest you to compact code by making a loop (to roll it) because i see the same fragments that fit one code. And the logic of program is so simple that you can avoid some strange mul.
All you need is to know how many times your buffer is in file: fileSize = k * buffSize + Q, k =0, 1, ... Q < buffSize. Then k times you write the full buffer and 1 (or 0) time you write Q bytes of buffer. Cant be easier.
Title: Re: Securely deleting files
Post by: white scorpion on July 06, 2006, 06:26:55 AM
1. you are right.it seems i've done too much copy and paste work from the previous code with MapViewOfFile...it should be INVALID_HANDLE_VALUE. willl change immediately.
2. This is happening. Take a good look.
3. any suggestions on making a loop?
4. Not exactly. Since im using flag FILE_FLAG_NO_BUFFERING the number of bytes written has to be in steps of sector size (mostly 512bytes) that's the reason i put in that code.

[EDIT]
updated above code.
Title: Re: Securely deleting files
Post by: asmfan on July 06, 2006, 07:50:24 AM
Ok, a suggestion on simplification. Make a buffer divisible by 512 (you have it). Then divide fileSize by buffSize. Proceed the quotient in eax in a loop if needed (eax not 0) then proceed the remainder in edx, using the same buffer. By the way FILE_FLAG_NO_BUFFERING cannot proceed files than less 512 bytes (AFAIC...?) or the last bytes that less 512 (the remainder)
Title: Re: Securely deleting files
Post by: white scorpion on July 06, 2006, 10:16:05 AM
Simply put, that's what above code does.

Devide filesize by 512
if remainder !=0
then add 512 to the quotient*512.
since we multiple it again we have the original filesize rounded up till the next step of 512 bytes.

I'm still not sure how to simplify this to make it work with every possible filesize (bigger or smaller then 512,devidable by 512 or not).
Title: Re: Securely deleting files
Post by: Tedd on July 06, 2006, 01:27:42 PM
Maybe I misread somewhere, but you don't appear to be resetting the seed before you call GenerateRandomByte again, which means you will get a different number each time.
This is bad for two reasons. The whole point of overwriting with an inverse pattern is to flatten out the magnetic echos, if you overwrite with the inverse of another random number that's just the same as overwriting with a random number. Secondly, while it may seem like a good idea to write different values, this creates interference between boundaries, but you're supposed to be avoiding interference and flattening out the magnetic signals. So it's still a better idea to fill the whole file with the same number, and then its inverse.

Generate a random value, save it, use that. Flush the file. NOT the previous value, save that, and use it. This is also obviously more effiecent than calling GenerateRandomByte each time.
Title: Re: Securely deleting files
Post by: white scorpion on July 06, 2006, 02:26:44 PM
QuoteMaybe I misread somewhere, but you don't appear to be resetting the seed before you call GenerateRandomByte again, which means you will get a different number each time.
This is bad for two reasons. The whole point of overwriting with an inverse pattern is to flatten out the magnetic echos, if you overwrite with the inverse of another random number that's just the same as overwriting with a random number. Secondly, while it may seem like a good idea to write different values, this creates interference between boundaries, but you're supposed to be avoiding interference and flattening out the magnetic signals. So it's still a better idea to fill the whole file with the same number, and then its inverse..
You're totally right.. Somewhere in all changes i made to this code i must have forgotten to put the

mov eax,backup
mov myseed,eax

part back in the loops...
Will fix right away!

QuoteGenerate a random value, save it, use that. Flush the file. NOT the previous value, save that, and use it. This is also obviously more effiecent than calling GenerateRandomByte each time.
This won't be more efficient since would have to call WriteFile for every byte (or DWORD) that is generated. Calling GenerateRandomByte for each byte is more efficient then WriteFile.

EDIT THis should be it then.

RemoveFile proc file_to_delete:DWORD,number_of_times:DWORD
    LOCAL hFile:DWORD
    LOCAL inputfilesize:DWORD
    LOCAL backup:DWORD
    LOCAL BytesWr:DWORD
    LOCAL shredbuf[1024*10]:BYTE
    LOCAL buffer_times:DWORD
    LOCAL my_remainder:DWORD

    cmp number_of_times,0
    jnz @F 
    xor eax,eax
    dec eax
    ret
@@:
    invoke CreateFile,file_to_delete,GENERIC_WRITE, 0, NULL, OPEN_EXISTING,\
    FILE_ATTRIBUTE_NORMAL or FILE_FLAG_NO_BUFFERING, NULL
    .if eax==NULL
@@:
        invoke CloseHandle,hFile
        xor eax,eax
        dec eax
    ret
    .endif   
    mov hFile,eax
    invoke GetFileSize,eax,NULL
    mov ebx,512
    xor edx,edx
    div ebx
    .if edx==0
        mul ebx
    .else
        mul ebx
        add eax,512
    .endif       
    mov inputfilesize,eax
    invoke GetTickCount
    mov backup,eax
    mov myseed,eax
   .if inputfilesize<=sizeof shredbuf
        mov edx,number_of_times
;----Rounds Small Start -----       
times_loop_small:
        push edx       
        mov ecx,inputfilesize 
        lea esi,shredbuf       
@@:
        invoke GenerateRandomByte
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        mov eax,backup
        mov myseed,eax
        invoke SetFilePointer,hFile,0,0,FILE_BEGIN
        invoke WriteFile,hFile,addr shredbuf,inputfilesize,addr BytesWr,NULL
        mov ecx,inputfilesize
        lea esi,shredbuf
@@:
        invoke GenerateRandomByte
        not eax
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        mov eax,backup
        mov myseed,eax
        invoke SetFilePointer,hFile,0,0,FILE_BEGIN
        invoke WriteFile,hFile,addr shredbuf,inputfilesize,addr BytesWr,NULL
        pop edx
        dec edx
        jnz times_loop_small   
;----Rounds Small End ------- 
    .else
        mov eax,inputfilesize
        mov ebx,sizeof shredbuf
        xor edx,edx
        div ebx
        mov buffer_times,eax
        mov my_remainder,edx
        mov edx,number_of_times
;----Rounds Big Start -----       
times_loop_big:
        push edx
        mov eax,backup
        mov myseed,eax
        invoke SetFilePointer,hFile,0,0,FILE_BEGIN
        mov eax,buffer_times
bufloop1: 
        push eax     
        mov ecx,sizeof shredbuf
        lea esi,shredbuf       
@@:       
        invoke GenerateRandomByte
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        invoke WriteFile,hFile,addr shredbuf,sizeof shredbuf,addr BytesWr,NULL
        pop eax
        dec eax
        jnz bufloop1
        mov ecx,my_remainder
        .if ecx==0
            jmp second_round
        .endif
        lea esi,shredbuf
@@:
        invoke GenerateRandomByte
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        invoke WriteFile,hFile,addr shredbuf,my_remainder,addr BytesWr,NULL   
second_round: 
mov eax,backup
        mov myseed,eax           
        invoke SetFilePointer,hFile,0,0,FILE_BEGIN
        mov eax,buffer_times
bufloop2:   
        push eax   
        mov ecx,sizeof shredbuf
        lea esi,shredbuf
@@:       
        invoke GenerateRandomByte
        not eax
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        invoke WriteFile,hFile,addr shredbuf,sizeof shredbuf,addr BytesWr,NULL
        pop eax
        dec eax
        jnz bufloop2
        mov ecx,my_remainder
        .if ecx==0
            jmp finish_round
        .endif
        lea esi,shredbuf
@@:
        invoke GenerateRandomByte
        not eax
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        invoke WriteFile,hFile,addr shredbuf,my_remainder,addr BytesWr,NULL       
finish_round:
        pop edx
        dec edx
        jnz times_loop_big
;----Rounds Small End -------         
    .endif       
    invoke CloseHandle,hFile
    invoke DeleteFile,file_to_delete
    xor eax,eax
    ret
RemoveFile endp

I'm really starting to get confused with this code since i 've rewritten it so many times now  :bg
Title: Re: Securely deleting files
Post by: Tedd on July 10, 2006, 09:44:24 AM
Quote from: White Scorpion on July 06, 2006, 02:26:44 PM
QuoteGenerate a random value, save it, use that. Flush the file. NOT the previous value, save that, and use it. This is also obviously more effiecent than calling GenerateRandomByte each time.
This won't be more efficient since would have to call WriteFile for every byte (or DWORD) that is generated. Calling GenerateRandomByte for each byte is more efficient then WriteFile.

What?! :dazzled:

repeat
    value = GenerateRandomByte
    repeat
        fill the whole buffer with 'value'
        write buffer chunks up to size of file
        flush file
        value = NOT(value)
        fill the whole buffer with 'value'
        write buffer chunks up to size of file
        flush file
    until bored
until bored


Why would you need to call WriteFile for every byte? You do need to call it for every chunk, and then flush the file, so that it's actually written to disk - which is exactly what you want otherwise the driver will cache it and only the last write will have any effect on the physical disk.
Title: Re: Securely deleting files
Post by: Tedd on July 10, 2006, 10:01:22 AM
    invoke CreateFile,file_to_delete,GENERIC_WRITE, 0, NULL, OPEN_EXISTING,\
    FILE_ATTRIBUTE_NORMAL or FILE_FLAG_NO_BUFFERING, NULL
    .if eax==NULL
@@:
        invoke CloseHandle,hFile
        xor eax,eax
        dec eax
    ret
    .endif   
    mov hFile,eax

No!
What is the value of hFile when CreateFile returns NULL? And if the file wasn't opened successfully, why are you attempting to close it again??
Not that this is correct anyway - CreateFile returns INVALID_HANDLE_VALUE (-1) upon failure.


    invoke GetFileSize,eax,NULL
    mov ebx,512
    xor edx,edx
    div ebx
    .if edx==0
        mul ebx
    .else
        mul ebx
        add eax,512
    .endif       
    mov inputfilesize,eax

..simplified..
    invoke GetFileSize,eax,NULL
    add eax,1FFh          ;512 - 1 (so rounds up to full sector)
    and eax,0FFFFFE00h    ;ffffffffh - 512 (round to sector length)
    mov inputfilesize,eax



@@:
        invoke GenerateRandomByte
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
  .
  .
@@:
        invoke GenerateRandomByte
        not eax
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B

Nooooooo.. ::)
Use ONE value for the entire file. Then use its inverse for the ENTIRE file.
What you're currently doing is no better than filling the file with random data numerous times - which may be fairly effective - but then your program should be considerably simpler.


What's the deal with the 'rounds'?? You're writing buffer-fulls, so a simple 'how-much-left-until-end-of-file' counter that you subtract from should work better than doubling the code to handle full-buffer/not-full-buffer.


My advice: delete THIS file, start over again - taking everything you've learned - and write a much better, more organised, and less messy, correct program.
Title: Re: Securely deleting files
Post by: Darrel on July 10, 2006, 05:21:12 PM
Corrected DigitalShredder. It now handles files of size 0.



[attachment deleted by admin]
Title: Re: Securely deleting files
Post by: white scorpion on July 10, 2006, 05:40:54 PM
Tedd, flushing the file to disk doesn't necessarily write to disk (it could be cached), hence the writefile.
I know there are some stupid mistakes in above code since the check you see (if eax==NULL) was from another APi call. I must have left it there when changing the code.
The code in the program itself already has been updated almost immediately after my previous post. I just forgot to change it here.

here's the current function. I must say that i still have to change the LOCAL variable of 10kb to either a global, or using HeapAlloc.

;****************************************************************
; the function which securely removes the inputfile
;****************************************************************
RemoveFile proc file_to_delete:DWORD,number_of_times:DWORD
    LOCAL hFile:DWORD
    LOCAL inputfilesize:DWORD
    LOCAL backup:DWORD
    LOCAL BytesWr:DWORD
    LOCAL shredbuf[1024*10]:BYTE
    LOCAL buffer_times:DWORD
    LOCAL my_remainder:DWORD

    cmp number_of_times,0
    jnz @F 
    xor eax,eax
    dec eax
    ret
@@:
    invoke CreateFile,file_to_delete,GENERIC_WRITE, 0, NULL, OPEN_EXISTING,\
    FILE_ATTRIBUTE_NORMAL or FILE_FLAG_NO_BUFFERING, NULL
    .if eax==INVALID_HANDLE_VALUE
@@:
        xor eax,eax
        dec eax
    ret
    .endif   
    mov hFile,eax
    invoke GetFileSize,eax,NULL
    mov ebx,512
    xor edx,edx
    div ebx
    .if edx==0
        mul ebx
    .else
        mul ebx
        add eax,512
    .endif       
    mov inputfilesize,eax
    invoke GetTickCount
    mov backup,eax
    mov myseed,eax
   .if inputfilesize<=sizeof shredbuf
        mov edx,number_of_times
;----Rounds Small Start -----       
times_loop_small:
        push edx       
        mov ecx,inputfilesize 
        lea esi,shredbuf       
@@:
        invoke GenerateRandomByte
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        mov eax,backup
        mov myseed,eax
        invoke SetFilePointer,hFile,0,0,FILE_BEGIN
        invoke WriteFile,hFile,addr shredbuf,inputfilesize,addr BytesWr,NULL
        mov ecx,inputfilesize
        lea esi,shredbuf
@@:
        invoke GenerateRandomByte
        not eax
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        mov eax,backup
        mov myseed,eax
        invoke SetFilePointer,hFile,0,0,FILE_BEGIN
        invoke WriteFile,hFile,addr shredbuf,inputfilesize,addr BytesWr,NULL
        pop edx
        dec edx
        jnz times_loop_small   
;----Rounds Small End ------- 
    .else
        mov eax,inputfilesize
        mov ebx,sizeof shredbuf
        xor edx,edx
        div ebx
        mov buffer_times,eax
        mov my_remainder,edx
        mov edx,number_of_times
;----Rounds Big Start -----       
times_loop_big:
        push edx
        mov eax,backup
        mov myseed,eax
        invoke SetFilePointer,hFile,0,0,FILE_BEGIN
        mov eax,buffer_times
bufloop1: 
        push eax     
        mov ecx,sizeof shredbuf
        lea esi,shredbuf       
@@:       
        invoke GenerateRandomByte
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        invoke WriteFile,hFile,addr shredbuf,sizeof shredbuf,addr BytesWr,NULL
        pop eax
        dec eax
        jnz bufloop1
        mov ecx,my_remainder
        .if ecx==0
            jmp second_round
        .endif
        lea esi,shredbuf
@@:
        invoke GenerateRandomByte
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        invoke WriteFile,hFile,addr shredbuf,my_remainder,addr BytesWr,NULL   
second_round: 
mov eax,backup
        mov myseed,eax           
        invoke SetFilePointer,hFile,0,0,FILE_BEGIN
        mov eax,buffer_times
bufloop2:   
        push eax   
        mov ecx,sizeof shredbuf
        lea esi,shredbuf
@@:       
        invoke GenerateRandomByte
        not eax
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        invoke WriteFile,hFile,addr shredbuf,sizeof shredbuf,addr BytesWr,NULL
        pop eax
        dec eax
        jnz bufloop2
        mov ecx,my_remainder
        .if ecx==0
            jmp finish_round
        .endif
        lea esi,shredbuf
@@:
        invoke GenerateRandomByte
        not eax
        mov byte ptr [esi],al
        inc esi
        dec ecx
        jnz @B
        invoke WriteFile,hFile,addr shredbuf,my_remainder,addr BytesWr,NULL       
finish_round:
        pop edx
        dec edx
        jnz times_loop_big
;----Rounds Small End -------         
    .endif       
    invoke CloseHandle,hFile
    invoke DeleteFile,file_to_delete
    xor eax,eax
    ret
RemoveFile endp



;****************************************************************
;The function which will generate random bytes for the deletion of inputfile
;****************************************************************
GenerateRandomByte proc
        mov eax,myseed
        mov ebx,127923
        mul ebx
        xor eax,479573
        xor eax,edx
        mov myseed,eax
        xor edx,edx
        div mybase
        mov eax,edx
        ret
GenerateRandomByte endp


Let me know what you think of this one.
Title: Re: Securely deleting files
Post by: Tedd on July 11, 2006, 09:54:13 AM
QuoteTedd, flushing the file to disk doesn't necessarily write to disk (it could be cached), hence the writefile.
No, that is exactly what it does! Flushing a file writes the data to disk, that is the whole purpose of flushing! It empties all buffers for the file and causes them to be written to the disk. WriteFile writes the data to file-buffers almost always (yes, I see you've used FILE_FLAG_NO_BUFFERING).

So you've corrected one mistake, very good, but what about everything else I mentioned? Most importantly that your entire approach is just wrong.

::) I give up.
Title: Re: Securely deleting files
Post by: white scorpion on July 11, 2006, 03:15:35 PM
Please read this thread (http://www.asmcommunity.net/board/index.php?topic=24986.0) on asmcommunity. As you can see i've followed up almost every advise i've been given there.

Now you are telling me to start using FlushViewOfFile again?

How do i know whom to listen to? If one respected coder says one thing (with explanation), and the other one says another thing ( with explanation), then this makes it pretty difficult to make the right choice.
(on this particular subject i've messured the I/O writes to disk with both options and WriteFile gives as result as much bytes as 10 times the filesize. FlushViewOfFile on the other hands doesn't even show 1 time the filesize as writes to disk.
This makes it even more difficult for me to see which one is best. When you look at the harddisk led on your computer with both functions, you can see that with WriteFile the led is constantly burning and you can hear the harddisk working, with FlushViewOfFile this isn't the case.

I totally agree with you on one thing: start from scratch and rewrite the function.
But i first want a fully working and correct function before i start writing it all over again with the risk of having to edit that one dozens of times again, this doesn't have anything to do with discarding your advise  :P


Title: Re: Securely deleting files
Post by: Tedd on July 11, 2006, 05:11:52 PM
The intention of "flushing" is to empty buffers to disk/storage to ensure a correct and up-to-date version is stored. What windows actually does in the implementations of certain functions is a different matter (FlushViewOfFile 'should' flush dirty buffers, but maybe it does it lazily), and not something you have enough control over :bdg However, what you do want to do is flush the file -- how you achieve that is a different matter :P But since you have FILE_FLAG_NO_BUFFERING then there shouldn't a problem with buffering when using WriteFile, so it's all good (but without that hint, it would most likely buffer in all cases.)
See also: FlushFileBuffers :wink (then again, it could still be lazy. Stick with writefile+hint)

The problem (as I see it) with your current program is that it fills the file with DIFFERENT bytes. In my (obviously deranged) opinion this is the wrong thing to do. Choose one byte and fill the whole file with just that value. Then overwrite that with the inverse. Repeat ad nauseum, for different values. The idea is to flatten the magnetic fields on the surface of the disk in order to make recovery difficult/impossible. If you write different values to each byte, this will cause interference, which is precisely what is used for advanced recovery and why it's possible to recover a file even after it has been overwritten (hence the purpose of this program!) I'm sure overwriting the file with anything a large number of times will eventually make recovery impossible, but somehow trying to 'flatten' the data seems more effective (to me and my deranged brain.)
Title: Re: Securely deleting files
Post by: white scorpion on July 11, 2006, 09:09:21 PM
I understand what you mean, but in theory this shouldn't matter.

whether i write: 11101101 and then 00010010 at every byte, or 10101101 vs 01010010 on one byte position and then write another byte and its reverse on another location shouldn't really matter.
In both cases you have all 1's and all 0's on every possible location.

It would be easier to write a program which just writes 0x00 and 0xFF at every byte location, but these are often the first rounds in these programs, the rest is filled with random bytes.
I still am not sure why there are several different techniques, since in the end it shouldn't matter since you are writing to every bit location both 1's and 0's.

The way my program does this is what is recommended to me to do this.
I haven't got the technical equipment to verify which technique would be best, so i decided to pick the one which is used most, random bytes.
This of course makes the program a bit more complicated then simply writing all 11111111's and 00000000's, but if i think about it:

-if a 10 times overwritten file can be retrieved within 10 hours (just a number, no real value i think) of magnetical workings before it is completely gone, then it would be better to disturb this by writing random bytes rather then one and the same byte since the difference at locations can be easier retrieved with all same bytes.
This is just my thought.  i could very well be wrong.
Title: Re: Securely deleting files
Post by: Tedd on July 12, 2006, 10:50:07 AM
Quotewhether i write: 11101101 and then 00010010 at every byte, or 10101101 vs 01010010 on one byte position and then write another byte and its reverse on another location shouldn't really matter.
In both cases you have all 1's and all 0's on every possible location.
But it does matter. It doesn't matter much to the data-tracks - which is where your bytes are actually written to, but it does matter to the gaps between these tracks - which is where the interference is caused and what is used to retrieve the lost data. If you only consider the data-tracks, then simply overwriting the file once will erase the data, but then why go to the trouble of filling with random data and inverses multiple times? The point is that it's the gaps that are used for recovery, but you don't have write access to the gaps, so you have to write multiple times in order to influence the 'echos' in these gaps to make data recovery more difficult.
Title: Re: Securely deleting files
Post by: white scorpion on July 12, 2006, 03:37:46 PM
I know how hardware recovery works in theory, but this doesn't explain why writing a same byte on every location in the file is better then writing random bytes.
Both also reversed of course.

Perhaps i will use both techniques just to be sure.
Write 0x00 & 0xFF both 3 times, and then writing random byte and its reverse both 2 times.
Total times overwritten will still be 10.
So i could do it like this:
1st: 0x00
2nd: 0xFF
3rd: random
4th reverse of 3
5th: 0x00
6th: 0xFF
7th: random
8th: reverse of 7
9th 0x00
10th: 0xFF

Would this be better in your opinion?
Title: Re: Securely deleting files
Post by: Tedd on July 13, 2006, 12:02:55 PM
No, not really.
Pick one method and stick with it.
Title: Re: Securely deleting files
Post by: Mark Jones on July 13, 2006, 04:18:30 PM
Perhaps research "Magnetic Hysteresis." This is after all, what you're trying to defeat. :thumbu
Title: Re: Securely deleting files
Post by: white scorpion on July 19, 2006, 10:08:24 PM
Absolutely worth researching!
I've downloaded some pdf's on this topic which i will start reading asap.

Well, the pdf's i downloaded are lab manuals which doesn't contain any info which i can use :(

I've rewritten the complete function. It now uses 0x00 & 0xFF to overwrite the file.
depending on the number of times given as argument it will overwrite the file like this:

1st:  0x00
2nd: 0xFF
3rd: 0x00
4th: 0xFF
5th: 0x00
6th: 0xFF
....

Attached you will find the function. please let me know what to improve. I've used HeapAlloc with 64k allocation.



[attachment deleted by admin]
Title: Re: Securely deleting files
Post by: asmfan on July 24, 2006, 06:35:31 PM
Allow me to post my version of procedure (the idea is the main thing)
I wrote it in parallel with White Scorp. Scorp, you can freely use it in your program, modify and add...
it's basically for compare our code style...

[attachment deleted by admin]
Title: Re: Securely deleting files
Post by: CoR on January 21, 2007, 04:34:04 PM
I had little day dream about your "Magnetic Hysteresis".
I do not if it will make any difference or not but how about using NOT for the first time. Bare with me:

mov var, File data,
not var
write [File data], var

Basically rewrite file with it's negative and after that use write 1111, 0000 or some RND.


Pardon in advance if this idea already exist.
Title: Re: Securely deleting files
Post by: ecube on January 21, 2007, 07:26:38 PM
MASM version of sysinternals SDelete program this also has a fantastic GUI
http://www.geocities.com/asmsoft3264/src/SecureDeleteSrc12.zip