This works for the most part in Win 7 Pro SP 1.
I would like to fix the file renaming function if it's possible.
Thanks.
; SHRED.ASM Ver 1i B/W version Tasm code format
;
; Much help from Stealth, Raymond, Bitrake, Rudy Weiser, Frank Kotler,
; Fauzan Mirza, Robert Redelmeier, QvasiModo,
;
; © Copywrong Andy 1996 - 2013
; Tasm code
;
;
Tuesday, January 22, 2013
; Works under Windows 7 Professional Service Pack 1 using Run, cmd.exe
;
; FILENAME CHANGE IS NOT CURRENTLY WORKING
;
;
; ***** FILE is NOT recoverable !!!! ****
;
; Supports Long Filenames
; Works in Win XP in a DOS box, with short or long filenames
;
; Shreds a 331 Meg file in 80 secs on an AMD K-6 475 MHz
;
; Overwrite a file with zero bytes, truncates it to zero bytes,
; set file time and date to 12:59:58 pm 1/1/80,
; renames it and then deletes it.
; Single files only. (For Safety)
;
; Use SHORT (8.3) FILENAME when file is a LFN
; Ex. C:\PROGRA~1\VERYLO~1.ASM
;
; Works across drives, handles periods in the path names
;
; Help from Stealth, Raymond, Bitrake, Rudy Weiser, Frank Kotler,
; Fauzan Mirza, Robert Redelmeier, QvasiModo,
;
;
.MODEL SMALL
.386
.stack 200h
STOP equ int 3
.data? ; can contain ONLY un-initialized data, keeps executable small
random db 64000 dup(?)
file_name db 128 dup(?) ; DOS maximum path length
storage db 150 dup(?)
.data
handle dw ?
file_size dd ?
name_size dw ?
; Direct video writes, shows right after Version number !!
;
prompt db 13,10,13,10,9,'File Shredder Ver. 1h' ,13,10
db 13,10,9,'© Copyright 1996 - 2004',13,10
db 13,10,9,'IF YOU USE THIS PROGRAM, OVERWRITTEN FILES',13,10
db 13,10,9,'WILL BE GONE FOR GOOD. THIS PROGRAM CAUSES',13,10
db 13,10,9,'PERMANENT DATA LOSS. YOU HAVE BEEN WARNED!!',13,10
db 13,10,9,'Use SHORT (8.3) FILENAME when file is a LFN.',13,10
db 13,10,9,'Use full path when not in current DIR/DRIVE',13,10
db 13,10,9,'Usage: C:\PROGRA~1\FILENAME.ASM',13,10,13,10
db 13,10,9,'File name to SHRED --> $'
not_there db 13,10,13,10,13,9,'File not present.',13,10,'$'
emsg2 db 13,10,13,10,'Error moving file pointer.',13,10,'$'
emsg3 db 13,10,13,10,'Error writing to file.',13,10,'$'
done_msg db 13,10,13,10,'File has been shredded.',13,10,'$'
eraser_name db 'àáâãäåæç.',0
.code
start:
mov ah,15 ; clear the screen
int 10h
mov ah,0
int 10h
mov ax,@data
mov ds,ax
mov es,ax ; need for LFN functions
mov bx,00h ; write zeros into memory
zero_out: ; Set memory to zero
mov [random + bx],00h
inc bx
cmp bx,64000
jnz zero_out
mov dx, offset prompt
mov ah,9
int 21h
mov file_name,128 ; max characters in input
mov dx,offset file_name; get filename
mov ah,0ch ; flush keyboard buffer
mov al,0ah ; buffered keyboard input
int 21h
mov cl,[file_name + 1] ; how many bytes read in
add cl,2 ; find position after last character
mov ch,00
mov si,cx ; move count to index register
mov [name_size],cx ; save size
mov file_name[si],00 ; make into ASCII string
; Change any read-only attribute
change:
lea dx,file_name + 2
mov ax,4301h
mov bl,01h ; set attributes
;Bitfields for file attributes: (CX register)
;Bit(s) Description (Table 01420)
; 7 shareable (Novell NetWare)
; 7 pending deleted files (Novell DOS, OpenDOS)
; 6 unused
; 5 archive
; 4 directory
; 3 volume label
; execute-only (Novell NetWare)
; 2 system
; 1 hidden
; 0 read-only
mov cx,00000000b ; remove read-only attribute
int 21h
;INT 21 - Windows95 - LONG FILENAME - CREATE OR OPEN FILE
; AX = 716Ch
; BX = access mode and sharing flags (see #01782,also AX=6C00h);
; CX = attributes
; DX = action (see #01781)
; DS:SI -> ASCIZ filename
open_it:
mov ax,716Ch ; create file
xor cx,cx ; file attributes
; file access modes (bits) BX register
; 000 read-only
; 001 write-only
; 010 read-write
; 100 read-only, do not modify file's last-access time
; Bitfields for Windows95 long-name open action: DX Register
; Bit(s) Description (Table 01781)
; 0 open file (fail if file does not exist)
; 1 truncate file if it already exists (fail if file does not exist)
; 4 create new file if file does not already exist (fail if exists)
; Note: the only valid combinations of multiple flags are bits 4&0 and 4&1
mov bx,00000001b ; access mode - write only
mov dx,00000001b ; open file
lea si,file_name + 2 ; sets the file name
int 21h
mov [handle],ax ; Save file handle
jnc short get_size ; No errors, go on
no_file:
mov dx,offset not_there; Get error message
jmp error ; and go display/exit
get_size:
mov ax,4202h ; Set file pointer
mov bx,[handle] ; for this file
xor cx,cx ; relative to end of file
xor dx,dx ; offset 0 bytes
int 21h
jnc save_size
err2:
mov dx,offset emsg2 ; Get error message
jmp error ; and go display/exit
save_size:
mov word ptr [file_size],ax ; Save low word of file size
mov word ptr [file_size + 2],dx ; Save high word
mov ax,4200h ; Move file pointer
mov bx,[handle] ; for this file
xor cx,cx ; relative to beginning of file
xor dx,dx ; offset 0 bytes
int 21h
jc err2 ; Errors: go handle
next_bunch:
mov cx,64000 ; Assume 64,000 bytes or more
; left to do
sub word ptr [file_size],cx ; Is there ? - subtract it
sbb word ptr [file_size + 2],0 ; from saved file size
jae wipe ; There were 64,000 bytes or
; more left
mov cx,word ptr [file_size] ; Get number of bytes left
add cx,64000 ; back CX (undo subtraction)
wipe:
mov ah,40h ; Write file
mov bx,[handle] ; Handle
lea dx,random ; Write the random bytes
int 21h
jnc check_size ; No errors, go on
err3:
mov dx,offset emsg3 ; Get appropriate error message
jmp error ; and go display/exit
check_size:
cmp ax,cx
jnz err3
cmp ax,64000 ; Full 64,000 bytes written,
je next_bunch ; yes, go check for more
jmp SHORT $+2 ; short delay cuz sometimes
; file isn't renamed
;
mov bx,[handle] ; close file
mov ah,3eh
int 21h
trunc:
; Truncate file to zero bytes
mov ah,3ch ; truncate file to zero bytes
mov cx,0
mov dx,offset file_name + 2
int 21h
mov bx,[handle] ; close file
mov ah,3eh
int 21h
; Store the path
scan:
lea si,[file_name + 2]
xor cx,cx
mov di,si
mov cx,[name_size]
mov al,'\'
add di,cx
std ; scan from right to left
dec di
repne scasb
jnz short no_path ; No slash is present
add cx,1 ;
no_path:
mov di,offset storage
cld ; change directions and scan
rep movsb ; from left to right
mov al,00
stosb ; make path ASCIZ
;STOP
; Add on eraser_name to end of storage
add_eraser:
mov cx,[name_size]
mov si,cx
lea di,storage
mov al,00 ; stops at the byte after the "00"
repnz scasb
dec di ; backup one
xor cx,cx
mov si,offset eraser_name
mov cx,9 ; # of characters
rep movsb
; Rename and delete file (LFN)
rename:
mov dx,offset file_name + 2 ; old file name
mov di,offset storage
mov ax,7156h ; LFN support
int 21h
; Change file date and time
mov ax,716Ch ; open file
xor cx,cx ; file attributes
; file access modes (bits) FOR BX Register
; 000 read-only
; 001 write-only
; 010 read-write
; 100 read-only, do not modify file's last-access time
; set bit 14 - commit file after every write operation
mov bx,00000000000000010b ; access mode (R/W)
mov dx,1 ; open file
lea si,storage ; sets the file name
int 21h
mov bx,ax ; save file handle
push bx
mov ax,5701h ; change file date
; BITS 5-10 are minutes, 11-15 are hours
mov cx,677dh ; 12:59:58 pm 110011101111101b
;
; BITS 0-4 are day, 5-8 are month, 9-15 (year - 1980)
mov dx,021h ; 1/1/80 0000000000100001b
int 21h
pop bx
;INT 21 U - DOS 4.0+ - COMMIT FILE
; AH = 6Ah
; BX = file handle
mov ah,6ah ; make sure this file is written to disk
int 21h
mov ah,3eh ; close file
int 21h
; INT 21 - Windows95 - LONG FILENAME - DELETE FILE
; AX = 7141h
; DS:DX -> ASCIZ long name of file to delete
mov dx,offset storage ; delete file
mov ax,7141h
xor si,si
int 21h
; idea from Fauzan Mirza
xor ax,ax ; Zero out file_name
mov di,offset storage + 2
mov cx,150
repnz stosb
finito:
mov ah,9
mov dx,offset done_msg
int 21h
mov ax,4c00h ; Set errorlevel to 0
int 21h
error:
mov ah,9
int 21h
mov ax,4c01h ; Set errorlevel to 1
int 21h
end start
i guess you mean long file names
google for info on INT 21h, AH=71h
or use Ralf Brown's Interrupt List
No, this was introduced in Win 95.
But I recently tried it on a Win 7 system.
File shredding went ok, but it didn't rename the file right.
I recall someone recommending putting in a delay for XP, I may see if grdb.exe will work under Win7 and see what's going on "under the hood" when this hound runs.
rename:
mov dx,offset file_name + 2 ; old file name
mov di,offset storage
mov ax,7156h ; LFN support, Win 95 rocks.
int 21h
Hi,
Print out the error code. You may have an illegal filename.
Or somesuch.
Regards,
Steve
This fragment may be an error:
mov bx,[handle] ; close file
mov ah,3eh
int 21h
trunc:
; Truncate file to zero bytes
mov ah,3ch ; truncate file to zero bytes
mov cx,0
mov dx,offset file_name + 2
int 21h
mov bx,[handle] ; close file
mov ah,3eh
int 21h
it's a questionable strategy to close a file, then reopen it with ah=3Ch and then assume that you can close it with the very same handle again. And if the last close fails and the file is still open, you won't be able to rename it.
You are exactly right and I neglected to put in err3 for errors.
Will be back.
Andy
I corrected the code but the problem remains.
I even put a short delay after closing the file.
I am going to see if what debug says.
I guess I have to put in some int 3s
and do a go and look at the registers ?
I forgot how to list the registers.
Andy
There's a modified Open Watcom Win32 debugger (WDW) that is able to debug DOS ( and Win16 ) applications:
http://www.japheth.de/Download/wdw.zip (http://www.japheth.de/Download/wdw.zip)
It understands CodeView symbolic debugging info, so if you assemble with -Zi and link with /CO you'll be able to step thru your source and watch variables.
Thanks.
I assembled and linked with full debug info using tasm.exe and tlink.exe.
I used Watcom and loaded my program, but not sure if it will work with tasm generated programs.
I guess I will have to convert my code to masm style.
I think I have a masm .exe template to look at.
Quote from: Magnum on January 24, 2013, 04:05:10 AM
I used Watcom and loaded my program, but not sure if it will work with tasm generated programs.
I guess I will have to convert my code to masm style.
The WDW debugger probably won't work with Borland debug info. However, the program is already in Masm-syntax ... almost: there's a "repnz stosb" which had to be changed to "rep stosb".
I received this advice.
Using a loop like this to initialize memory seems like a rather glaring
omission of the instructions Intel designed for such tasks;
;; Assuming ES == DS, and CLD has been done
mov di,offset [random]
mov cx,64000 / 2
mov ax,0
rep stosw
When you overwrite a file, you should probably round up the length to
the next full allocation cluster size (often 4KB, but check!), so that
you get rid of any data remaining in that tail.
Otherwise I agree with Robert, such a program should probably be written
in C or (my personal favourite for snippets like this: Perl!)
Terje
PS. I wrote a disk eraser (in Turbo Pascal + inline asm) _many_ years
ago, it works at the lowest bios level I can access, from a bootable
floppy/CD/memory stick. Today using a Linux boot disk is probably
better, since that will have drivers for many more disk controller types.
Quote from: Magnum on January 24, 2013, 06:55:43 AM
When you overwrite a file, you should probably round up the length to
the next full allocation cluster size (often 4KB, but check!), so that
you get rid of any data remaining in that tail.
64000d is 0FA00h, that's not that bad - but I agree that 57344d (0E000h) may be a bit "better" - although I doubt that you'll be able to notice.
Quote
Otherwise I agree with Robert, such a program should probably be written
in C or (my personal favourite for snippets like this: Perl!)
I happen to read CLAX occasionally; IMO "Robert" didn't even vaguely suggest to rewrite the little program in C.
However, it's true that a Win32 version has advantages - besides running on 64-bit Windows it will also allow to handle files > 4 ( or even 2) GB.
Many in the CLAX group are the quiet type.
Herbert Kleebauer posts every once in a while or as a friend once said, "Once in a blue moon."
I try to appreciate any help I get and look for the good in every situation.
Andy
<so that you get rid of any data remaining in that tail.
I don't understand what "tail" is.
Hi,
If your file size does not end at a sector/cluster boundry,
there will (possibly) be data in the rest of the cluster. That
is the tail in this case. For example for a cluster size of 4096,
if your file ends at byte 2999, then bytes 3000 to 4096 (or
4095 if zero based) will not be erased.
HTH,
Steve N.
Thanks.
Would it be better to erase the whole cluster ?
What is typically in the unused part of the cluster ?
Andy
Clusters are just groupings of sectors, to make keeping track of them require less space.
So the 'unused' part consists of the sectors allocated to this cluster, and they will contain whatever was left in them from any previous files that occupied those sectors in that cluster.
If you're hoping to erase and leave as little information as possible (while not being destructive to anything else) then you should round up and erase full clusters (even if the file takes one whole byte of a cluster.)
different operating systems behave a little differently, of course
completely unwritten sectors are likely to have whatever the last file had that used that sector
partially unwritten sectors may be written with remnants from file buffers
thing to do is to find the cluster size for the drive you are writing to
make the file an even number of clusters in size (as Tedd suggested)
write it
then, change it's size
i think sector size is generally 512 bytes
(on older machines, it was the max - not sure that's still true - but 512 is used for backward compatibility)
the cluster size will depend mainly on the size of the partition
many of the partitions i have use 8 kb clusters (16 sectors per cluster)
My NTFS is using 4 Kb clusters.
GetDiskFreeSpace will get it for you
on the old forum, Hutch had a nice little routine for that
I don't think that'll work for my 16 bit program, but you never know.
Andy
oops :biggrin:
Hi,
DOS has Function 36H Get Disk Free Space.
INT 21,36 Get Disk Free Space
Returns the free clusters on the spcified drive. It also
gets information to calculate the equivalent number of bytes.
INPUT AH = 36H
DL = Drive Number
OUTPUT AX = Sectors per Cluster (0FFFFH if error)
BX = Clusters Available
CX = Bytes per Sector
DX = Total Clusters on Disk
]
Regards,
SteveI
I think we've strayed from what was suggested.
;; Assuming ES == DS, and CLD has been done
mov di,offset [random]
mov cx,64000 / 2
mov ax,0
rep stosw
When you overwrite a file, you should probably round up the length to
the next full allocation cluster size (often 4KB, but check!), so that
you get rid of any data remaining in that tail.
If I understand it, I would like to write over the ( file + the remaining bytes in the partially used cluster)
So if cluster size is 4 Kb x 1024 = 4096 bytes
So if the file is 8000 bytes in size, then are there 192 bytes left to be overwritten too ?
2 clusters x 4096 = 8192 bytes allocated for the file - 8000 = 192
open_it:
mov ax,716Ch ; create file
xor cx,cx ; file attributes
; file access modes (bits) BX register
; 000 read-only
; 001 write-only
; 010 read-write
; 100 read-only, do not modify file's last-access time
; Bitfields for Windows95 long-name open action: DX Register
; Bit(s) Description (Table 01781)
; 0 open file (fail if file does not exist)
; 1 truncate file if it already exists (fail if file does not exist)
; 4 create new file if file does not already exist (fail if exists)
; Note: the only valid combinations of multiple flags are bits 4&0 and 4&1
mov bx,00000001b ; access mode - write only
mov dx,00000001b ; open file
lea si,file_name + 2 ; sets the file name
int 21h
mov [handle],ax ; Save file handle
jnc short get_size ; No errors, go on
no_file:
mov dx,offset not_there; Get error message
jmp error ; and go display/exit
get_size:
mov ax,4202h ; Set file pointer
mov bx,[handle] ; for this file
xor cx,cx ; relative to end of file
xor dx,dx ; offset 0 bytes
int 21h
jnc save_size
err2:
mov dx,offset emsg2 ; Get error message
jmp error ; and go display/exit
save_size:
mov word ptr [file_size],ax ; Save low word of file size
mov word ptr [file_size + 2],dx ; Save high word
mov ax,4200h ; Move file pointer
mov bx,[handle] ; for this file
xor cx,cx ; relative to beginning of file
xor dx,dx ; offset 0 bytes
int 21h
jc err2 ; Errors: go handle
next_bunch:
mov cx,64000 ; Assume 64,000 bytes or more
; left to do
sub word ptr [file_size],cx ; Is there ? - subtract it
sbb word ptr [file_size + 2],0 ; from saved file size
jae wipe ; There were 64,000 bytes or
; more left
mov cx,word ptr [file_size] ; Get number of bytes left
add cx,64000 ; back CX (undo subtraction)
wipe:
mov ah,40h ; Write file
mov bx,[handle] ; Handle
lea dx,random ; Write the random bytes
int 21h
jnc check_size ; No errors, go on
err3:
mov dx,offset emsg3 ; Get appropriate error message
jmp error ; and go display/exit
check_size:
cmp ax,cx
jnz err3
cmp ax,64000 ; Full 64,000 bytes written,
je next_bunch ; yes, go check for more
jmp SHORT $+2 ; short delay cuz sometimes
; file isn't renamed in a cmd.exe or command.com environment
;
mov bx,[handle] ; close file
mov ah,3eh
int 21h
cluster sizes are always powers of 2 - that simplifies the calculation a little bit
mov eax,SizeOfMyFile
add eax,(ClusterSize-1)
and ax,(-ClusterSize) ;EAX = total bytes to write
or
mov edx,ClusterSize
mov eax,SizeOfMyFile
dec edx
add eax,edx
not edx
and eax,edx ;EAX = total bytes to write