Hello everybody,

Any help, opinions, suggestions on this much appreciated:

I wrote a little program that deletes files and overwrites the file area (with cz's, what else?:)). When I run a standard undelete program these files can all be recovered but of course their contents are just a string of cz's. I'm happy with this but then I see that the file's name is sometimes suggestive making it easy to guess at what the contents were. It wouldn't be difficult, for example, to guess at the original contents of a file called How to be a better Chicken Thief.html.

I decided to get rid of the file name by renaming the file using MoveFile but after some trials I gave up on this idea. It seems this api doesn't just move the file. It first copies it then deletes it leaving the old file name available for undeletion.

The question: does anybody know of any api, procedure or link to any info that might help. Don't be deceived, I know very little about this part of the file system and any knowledge you have, no matter how trivial would be helpful.

I searched google for things like 'Remove FAT enty' and remove file name. The first search increased my knowledge of the file system and the second came up with variations of DeleteFile.

Therefore even a suggestion of what to search for would be most helpful:)

best regards,

czDrillard
Posted on 2002-12-09 01:54:42 by czDrillard
this will be a really low-level hack, you shouldn't forget all the FAT32 (since Win98) and NTFS (since NT) guys.

By the way... what happens if you delete a file, and immediately create a new one of the same size?
Maybe windows places it at the same location in the FAT?
Posted on 2002-12-09 04:41:29 by beaster


/*--begin wipe.c--*/

/*Version 2.30*/

#include <stdio.h>
#include <dos.h>
#include <dir.h>
#include <time.h>
#include <io.h>
#include <fcntl.h>
#include <sys\stat.h>

#define RAND_MAX 223 /*Don't change this; used for generating rand. char*/

/*Use the NUMPASSES define to change the number of
overwrites the program will perform. Nine passes is
the DoD standard for sensitive data*/

#define NUMPASSES 9

void flushcache (FILE *fptr)
{
union REGS regr;

fflush(fptr); /*Flush buffer*/

regr.h.ah = 0x0D;/*Perform disk reset to ensure that a write*/
int86(0x21, &regr, &regr);/*behind disk cache is flushed*/
}

char badfilechar (unsigned char ch)
{
/*This function checks to see if a character
is valid as part of a DOS filename. If it is
valid, the function returns 0.*/

if (ch <= 0x20 ||
ch == 0x22 ||
ch >= 0x2a && ch <= 0x2c ||
ch >= 0x2e && ch <= 0x2f ||
ch >= 0x3a && ch <= 0x3f ||
ch >= 0x5b && ch <= 0x5d ||
ch == 0x7c)
return 1;

return 0;
}

long round (float inpnum)
{
/*Rounds a floating point number to the nearest whole number*/
float rnd;
rnd = inpnum - (long)inpnum;
if (rnd < .5)
return((long)inpnum);
else
return((long)inpnum + 1);
}

int main (int argc, char *argv[])
{
FILE *fptr;
int x;
float percent;
unsigned long rate, y;
unsigned char c, randname[MAXFILE]={0}, fname[MAXPATH]={0};
unsigned char drive[MAXDRIVE], newfn[MAXPATH]={0}, dir[MAXDIR]={0};
time_t seed;
struct ffblk fb;
struct ftime ft = {0,0,0,1,1,0};/*time and date of 01-01-1980 00:00:00*/

if (argc != 2)
{
printf("\nSyntax:\n\n\tWIPE filename.ext\n");
return 1;
}

else if ((findfirst(argv[1], &fb, FA_ARCH | FA_RDONLY
| FA_HIDDEN | FA_SYSTEM)) == -1)
{
printf("\nFile not found\n");
return 1;
}

srand((unsigned)(time(&seed)));

fnsplit (argv[1], drive, dir, NULL, NULL);

do
{
strcpy(fname, drive);
strcat(fname, dir); /*Create string with complete filename & path*/
strcpy(newfn, fname);
strcat(fname, fb.ff_name);
strupr(fname);

chmod(fname, S_IWRITE); /*Make sure file can be written*/
/*to by changing attribs*/
fptr = fopen(fname, "w+");

percent=0; x=1;

while (x <= NUMPASSES)
{
if (fb.ff_fsize >= 32768 && x == 1)
{
printf("\nWiping %s 00.0%\x8\x8\x8\x8\x8\x8", fname);
rate = round(((float)fb.ff_fsize*(float)NUMPASSES)/1000.0);
/*rate is approx. 0.1% of completion; for progress display*/
}

else if (x == 1)
printf("\nWiping %s", fname);

if (x == NUMPASSES) /*If this is the last pass, use*/
c = 0xF6; /*character 0xF6 to overwrite the file*/

else if (x%2 == 1) /*If this is pass 1,3,5, or 7, use 0xFF*/
c = 0xFF; /*to overwrite the file*/

else /*if pass 2,4,6, or 8, use 0x00 to overwrite*/
c = 0x00;

if (fb.ff_fsize >= 32768)
for (y = 0;y < fb.ff_fsize;y++)
{
fputc(c, fptr);
if (y % rate == 0 && y != 0)
{
percent+=.1;
if (percent < 100)
printf(" %04.1f\x8\x8\x8\x8\x8", percent);
}
}

else
for (y = 0;y < fb.ff_fsize;y++)
fputc(c, fptr);

flushcache(fptr);

rewind(fptr);/*Set file pointer back to beginning of file*/

x++;
}

fclose(fptr);

for (x = 0;x < 8;x++)
do
randname[x] = rand()+33;/*Create a random char btwn 33-255*/
while (badfilechar(randname[x]) == 1);/*Make sure char is valid*/
/*for use in filename*/
strcat(newfn, randname);

rename(fname, newfn); /*Rename file to random filename*/

x = open(newfn, O_TRUNC | O_WRONLY);/*reopen file and set size to 0*/

setftime(x, &ft);

close(x);
unlink(newfn); /*Delete file*/
printf(", done.");
}while (findnext(&fb) != -1);
printf("\n");
return 0;
}

/*--end wipe.c--*/
Posted on 2002-12-09 07:15:48 by bazik
IIRC When a file is deleted from the disk, the clusters are only recoverable
until something overwrites the same clusters. I would search for things like
'file shredding' / 'secure delete' / etc. There is tons of ways todo such a thing.

Well if I would create such a function I would probably do something like the
below. This should be done with different variations and passes.
[color=sienna]

...
...
inv CreateFileA,ADDR FileName,GENERIC_WRITE,0,0,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN or \
FILE_FLAG_DELETE_ON_CLOSE or \
FILE_ATTRIBUTE_TEMPORARY,0
mov hFile,eax [color=green];[/@-Save file-handle[/color]
mov edi,5 [color=green];[/@-Number of passes[/color]
inc eax [color=green];[/@-Check if the file-handle is valid[/color]
@@: jz @F [color=green];[/@-Invalid-filehandle Check / Loop JumpPoint[/color]
[color=green];[/@-Write junk to file[/color]
inv WriteFile,hFile,JunkBuffer,FileSize,bWritten,0
[color=green];[/@-Reset position in file[/color]
inv SetFilePointer,hFile,0,0,0
dec edi [color=green];[/@-Decrease counter[/color]
jnz @B+2[color=green];[/@-Loop until 0[/color]
[color=green];[/@-Close/Delete file[/color]
inv CloseHandle,hFile

[color=green];[/@-Create a file with same size but different filename.[/color]
[color=green];[@/-This should delete the old file entry in the FAT.[/color]
inv CreateFileA,ADDR NewFileName,GENERIC_WRITE,0,0,
CREATE_ALWAYS,
FILE_FLAG_DELETE_ON_CLOSE or \
FILE_ATTRIBUTE_TEMPORARY,0
mov hFile,eax [color=green];[/@-Save file handle[/color]
inc eax [color=green];[/@-Check if the file-handle is valid[/color]
jz @F [color=green];[/@-If handle is invalid then jump[/color]
[color=green];[/@-Write junk to file[/color]
inv WriteFile,hFile,JunkBuffer,FileSize,bWritten,0
[color=green];[/@-Close/Delete file[/color]
inv CloseHandle,hFile
@@:
...
...
[/color]
Thou you need to keep in mind that I havent tested this code. So
it may contain some errors. But this should provide a somehwat basis.

[EDIT]: Bazik, managed to post C bashed code just a couple of minutes before i was done. Dont you just hate when that happens? ( :grin: )
Posted on 2002-12-09 07:18:41 by natas


[EDIT]: Bazik, managed to post C bashed code just a couple of minutes before i was done. Dont you just hate when that happens? ( :grin: )


But I dont have syntax highlighting ;)
Posted on 2002-12-09 07:39:51 by bazik

But I dont have syntax highlighting ;)

Dont hate me because im ORPosted on 2002-12-09 09:02:37 by natas
Recently I was fooling around with local labels. And I wanted to expand
the usability for it. So I tested if there was possible to jump over/below
the default jump point. This is not mentioned in the masm help file.
Ofcourse for some people this might not be usable, but i think it was.
Therefore im posting it for you all to see and comment. If you look at the
code above, you'll see the whole picture.

What I tried to create above was to use less labels. So therfore I choose
to put the compare instruction(jz) for 'invalid-filehandle' on one of the local labels.
If I had put the compare instruction above the first local label I would have
just jumped and executed the main code, instead of jumping to the end.

However this didnt create any problems for the code at all. Except for one thing,
each time the loop is executed it will also execute that extra instruction. And this
allowed me to skip that instruction. In order to skip an instruction you need to add
the size of the instruction located there. Otherwise It will fuck up. ( :tongue: )
[color=sienna]

@@: jz @F [color=green];[/@-Instruction is 2 bytes[/color]
inc edi [color=green] ;[/@-New jump point[/color]
jnz @B+2 [color=green];[/@-Jump over the standard jump point @@: by 2 bytes[/color]
@@:
[/color]

On a side note I could have just used the '$' and calculated number of bytes
to jump from the current location. However, when using local labels, masm
calculates the number of bytes from the current location to either the next or
last label. So it's easyer and more readable to use the local labels.
Posted on 2002-12-09 13:24:30 by natas
Thanks very much beaster, bazik and natas:) Christmas came early.

I think now because of your help I am on the right track. Here is some code I've been playing with. If I comment out the invoke DeleteFile,ADDR szNewNameBuf line at the end of the proc and call the proc twice the original file names are removed from the FAT and only the 'numbered' file names are displayed. I don't know why this is so but I'll keep playing with it until it becomes clear.

Btw, the following proc is called by a recursive findfirstfile/findnextfile proc which also passes it the file size. The files for deletion are cut and pasted from the MyDocuments folder to the windows\temp folder.


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FileDeleteAll proc uses edi FilePath:DWORD,FileName:DWORD,cbFile:DWORD

LOCAL hFile :DWORD
LOCAL dwWrite :DWORD




xor eax,eax
mov eax,[dwOverWrite]

.if eax==01h
invoke ZeroMem,FilePath,ADDR dwSterilize,ADDR dwDisable,ADDR dwNoMem
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;this proc is located in czMem.dll
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

.endif

invoke DeleteFile,FilePath
.if eax==00h
jmp @f

.endif

inc dwNewName ;first part of file name starts at 00000000
invoke RtlZeroMemory,OFFSET szTempPath,256
invoke RtlZeroMemory,OFFSET szNewNameBuf,256
invoke lstrcpy,ADDR szNewNameBuf,FilePath

mov edi,OFFSET szNewNameBuf
cld
or ecx,-1
xor eax,eax
repne scasb
mov al,5ch ;remove filename of original file from path
std
repne scasb
add edi,02h
xor eax,eax
stosd
cld

invoke dw2hex,dwNewName,ADDR szTempPath
invoke lstrcat,ADDR szNewNameBuf,ADDR szTempPath
invoke lstrcat,ADDR szNewNameBuf,ADDR szExtension
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;after first iteration file name is 00000001.txt
;after second iteration 00000002.txt...etc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

invoke CreateFile,ADDR szNewNameBuf,GENERIC_READ or GENERIC_WRITE,\
NULL,NULL,CREATE_NEW,NULL,NULL

mov hFile,eax
cmp eax,-1
jz @f

invoke GlobalAlloc,GMEM_ZEROINIT,cbFile
mov hMemory,eax
invoke GlobalLock,hMemory ;I haven't bothered checking for
mov pMemory,eax ;memory errors

mov edi,pMemory
xor ecx,ecx
mov ecx,cbFile ;size of file

.if ecx==00h ;if size==0, quit
invoke CloseHandle,hFile
invoke GlobalUnlock,pMemory
invoke GlobalFree,hMemory
jmp @f

.endif

xor eax,eax
mov ax,7a63h
@Begin:
stosw ;fill memory with cz
sub ecx,02h
cmp ecx,00h
jle @End
jmp @Begin

@End:
invoke WriteFile,hFile,pMemory,cbFile,ADDR WriteSize,NULL
invoke FlushFileBuffers,hFile
invoke CloseHandle,hFile
invoke GlobalUnlock,pMemory
invoke GlobalFree,hMemory

invoke DeleteFile,ADDR szNewNameBuf
;**********************************
;the line above must be commented out, else the original file name is left
;in the FAT and the just created file vanishes without a trace from the system.
;**********************************
@@:

ret

FileDeleteAll endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

thanks again for the help :alright:

best regards,

czDrillard



Posted on 2002-12-10 02:48:04 by czDrillard