All files are for educational and/or historic purposes only. [back to library]
//==// // // /|| // //==== //==// //| // // // // // //|| // // // // //|| // //==// //==// //=|| // // // // // || // // // // // || // // // // // ||// // // // // || //==== //==== //==// // ||/ -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- DISCLAIMER: The author hereby disclaims himself -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- DEDICATION: This was written to make the lives of scum such as Patty Hoffman, John McAffee, and Ross Greenberg a living hell. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- OTHER STUFF: Thanks go to The Shade of Sorrow, Demogorgon, and Orion Rouge on their comments (which I occasionally listened to!). Thanks also to Hellraiser, who gave me an example of some virus source code (his own, of course). -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Dark Angel's Phunky Virus Writing Guide ---- ------- ------ ----- ------- ----- Virii are wondrous creations written for the sole purpose of spreading and destroying the systems of unsuspecting fools. This eliminates the systems of simpletons who can't tell that there is a problem when a 100 byte file suddenly blossoms into a 1,000 byte file. Duh. These low-lifes do not deserve to exist, so it is our sacred duty to wipe their hard drives off the face of the Earth. It is a simple matter of speeding along survival of the fittest. Why did I create this guide? After writing several virii, I have noticed that virus writers generally learn how to write virii either on their own or by examining the disassembled code of other virii. There is an incredible lack of information on the subject. Even books published by morons such as Burger are, at best, sketchy on how to create a virus. This guide will show you what it takes to write a virus and also will give you a plethora of source code to include in your own virii. Virus writing is not as hard as you might first imagine. To write an effective virus, however, you *must* know assembly language. Short, compact code are hallmarks of assembly language and these are desirable characteristics of virii. However, it is *not* necessary to write in pure assembly. C may also be used, as it allows almost total control of the system while generating relatively compact code (if you stay away from the library functions). However, you still must access the interrupts, so assembly knowledge is still required. However, it is still best to stick with pure assembly, since most operations are more easily coded in assembly. If you do not know assembly, I would recommend picking up a copy of The Microsoft Macro Assembler Bible (Nabajyoti Barkakati, ISBN #: 0-672- 22659-6). It is an easy-to-follow book covering assembly in great detail. Also get yourself a copy of Undocumented DOS (Schulman, et al, ISBN #0-201- 57064-5), as it is very helpful. The question of which compiler to use arises often. I suggest using Borland Turbo Assembler and/or Borland C++. I do not have a copy of Zortech C (it was too large to download), but I would suspect that it is also a good choice. Stay away from Microsoft compilers, as they are not as flexible nor as efficient as those of other vendors. A few more items round out the list of tools helpful in constructing virii. The latest version of Norton Utilities is one of the most powerful programs available, and is immeasurably helpful. MAKE SURE YOU HAVE A COPY! You can find it on any decent board. It can be used during every step of the process, from the writing to the testing. A good debugger helps. Memory management utilities such as MAPMEM, PMAP, and MARK/RELEASE, are invaluable, especially when coding TSR virii. Sourcer, the commenting disassembler, is useful when you wish to examine the code of other virii (this is a good place to get ideas/techniques for your virus). Now that you have your tools, you are ready to create a work of art designed to smash the systems of cretins. There are three types of virii: 1) Tiny virii (under 500 bytes) which are designed to be undetectable due to their small size. TINY is one such virus. They are generally very simple because their code length is so limited. 2) Large virii (over 1,500 bytes) which are designed to be undetectable because they cover their tracks very well (all that code DOES have a use!). The best example of this is the Whale virus, which is perhaps the best 'Stealth' virus in existence. 3) Other virii which are not designed to be hidden at all (the writers don't give a shit). The common virus is like this. All overwriting virii are in this category. You must decide which kind of virus you wish to write. I will mostly be discussing the second type (Stealth virii). However, many of the techniques discribed may be easily applied to the first type (tiny virii). However, tiny virii generally do not have many of the "features" of larger virii, such as directory traversal. The third type is more of a replicating trojan-type, and will warrant a brief (very, very brief!) discussion later. A virus may be divided into three parts: the replicator, the concealer, and the bomb. The replicator part controls the spread of the virus to other files, the concealer keeps the virus from being detected, and the bomb only executes when the activation conditions of the virus (more on that later) are satisfied. -=-=-=-=-=-=-=- THE REPLICATOR -=-=-=-=-=-=-=- The job of the replicator is to spread the virus throughout the system of the clod who has caught the virus. How does it do this without destroying the file it infects? The easiest type of replicator infects COM files. It first saves the first few bytes of the infected file. It then copies a small portion of its code to the beginning of the file, and the rest to the end. +----------------+ +------------+ | P1 | P2 | | V1 | V2 | +----------------+ +------------+ The uninfected file The virus code In the diagram, P1 is part 1 of the file, P2 is part 2 of the file, and V1 and V2 are parts 1 and 2 of the virus. Note that the size of P1 should be the same as the size of V1, but the size of P2 doesn't necessarily have to be the same size as V2. The virus first saves P1 and copies it to the either 1) the end of the file or 2) inside the code of the virus. Let's assume it copies the code to the end of the file. The file now looks like: +---------------------+ | P1 | P2 | P1 | +---------------------+ Then, the virus copies the first part of itself to the beginning of the file. +---------------------+ | V1 | P2 | P1 | +---------------------+ Finally, the virus copies the second part of itself to the end of the file. The final, infected file looks like this: +-----------------------------+ | V1 | P2 | P1 | V2 | +-----------------------------+ The question is: What the fuck do V1 and V2 do? V1 transfers control of the program to V2. The code to do this is simple. JMP FAR PTR Duh ; Takes four bytes Duh DW V2_Start ; Takes two bytes Duh is a far pointer (Segment:Offset) pointing to the first instruction of V2. Note that the value of Duh must be changed to reflect the length of the file that is infected. For example, if the original size of the program is 79 bytes, Duh must be changed so that the instruction at CS:[155h] is executed. The value of Duh is obtained by adding the length of V1, the original size of the infected file, and 256 (to account for the PSP). In this case, V1 = 6 and P1 + P2 = 79, so 6 + 79 + 256 = 341 decimal (155 hex). An alternate, albeit more difficult to understand, method follows: DB 1101001b ; Code for JMP (2 byte-displacement) Duh DW V2_Start - OFFSET Duh ; 2 byte displacement This inserts the jump offset directly into the code following the jump instruction. You could also replace the second line with DW V2_Start - $ which accomplishes the same task. V2 contains the rest of the code, i.e. the stuff that does everything else. The last part of V2 copies P1 over V1 (in memory, not on disk) and then transfers control to the beginning of the file (in memory). The original program will then run happily as if nothing happened. The code to do this is also very simple. MOV SI, V2_START ; V2_START is a LABEL marking where V2 starts SUB SI, V1_LENGTH ; Go back to where P1 is stored MOV DI, 0100h ; All COM files are loaded @ CS:[100h] in memory MOV CX, V1_LENGTH ; Move CX bytes REP MOVSB ; DS:[SI] -> ES:[DI] MOV DI, 0100h JMP DI This code assumes that P1 is located just before V2, as in: P1_Stored_Here: . . . V2_Start: It also assumes ES equals CS. If these assumptions are false, change the code accordingly. Here is an example: PUSH CS ; Store CS POP ES ; and move it to ES ; Note MOV ES, CS is not a valid instruction MOV SI, P1_START ; Move from whereever P1 is stored MOV DI, 0100h ; to CS:[100h] MOV CX, V1_LENGTH REP MOVSB MOV DI, 0100h JMP DI This code first moves CS into ES and then sets the source pointer of MOVSB to where P1 is located. Remember that this is all taking place in memory, so you need the OFFSET of P1, not just the physical location in the file. The offset of P1 is 100h higher than the physical file location, as COM files are loaded starting from CS:[100h]. So here's a summary of the parts of the virus and location labels: V1_Start: JMP FAR PTR Duh Duh DW V2_Start V1_End: P2_Start: P2_End: P1_Start: ; First part of the program stored here for future use P1_End: V2_Start: ; Real Stuff V2_End: V1_Length EQU V1_End - V1_Start Alternatively, you could store P1 in V2 as follows: V2_Start: P1_Start: P1_End: V2_End: That's all there is to infecting a COM file without destroying it! Simple, no? EXE files, however, are a little tougher to infect without rendering them inexecutable - I will cover this topic in a later file. Now let us turn our attention back to the replicator portion of the virus. The steps are outlined below: 1) Find a file to infect 2) Check if it is already infected 3) If so, go back to 1 4) Infect it 5) If infected enough, quit 6) Otherwise, go back to 1 Finding a file to infect is a simple matter of writing a directory traversal procedure and issuing FINDFIRST and FINDNEXT calls to find possible files to infect. Once you find the file, open it and read the first few bytes. If they are the same as the first few bytes of V1, then the file is already infected. If the first bytes of V1 are not unique to your virus, change it so that they are. It is *extremely* important that your virus doesn't reinfect the same files, since that was how Jerusalem was first detected. If the file wasn't already infected, then infect it! Infection should take the following steps: 1) Change the file attributes to nothing. 2) Save the file date/time stamps. 3) Close the file. 4) Open it again in read/write mode. 5) Save P1 and append it to the end of the file. 6) Copy V1 to the beginning, but change the offset which it JMPs to so it transfers control correctly. See the previous part on infection. 7) Append V2 to the end of the file. 8) Restore file attributes/date/time. You should keep a counter of the number of files infected during this run. If the number exceeds, say three, then stop. It is better to infect slowly then to give yourself away by infecting the entire drive at once. You must be sure to cover your tracks when you infect a file. Save the file's original date/time/attributes and restore them when you are finished. THIS IS VERY IMPORTANT! It takes about 50 to 75 bytes of code, probably less, to do these few simple things which can do wonders for the concealment of your program. I will include code for the directory traversal function, as well as other parts of the replicator in the next installment of my phunky guide. -=-=-=-=- CONCEALER -=-=-=-=- This is the part which conceals the program from notice by the everyday user and virus scanner. The simplest form of concealment is the encryptor. The code for a simple XOR encryption system follows: encrypt_val db ? decrypt: encrypt: mov ah, encrypt_val mov cx, part_to_encrypt_end - part_to_encrypt_start mov si, part_to_encrypt_start mov di, si xor_loop: lodsb ; DS:[SI] -> AL xor al, ah stosb ; AL -> ES:[DI] loop xor_loop ret Note the encryption and decryption procedures are the same. This is due to the weird nature of XOR. You can CALL these procedures from anywhere in the program, but make sure you do not call it from a place within the area to be encrypted, as the program will crash. When writing the virus, set the encryption value to 0. part_to_encrypt_start and part_to_encrypt_end sandwich the area you wish to encrypt. Use a CALL decrypt in the beginning of V2 to unencrypt the file so your program can run. When infecting a file, first change the encrypt_val, then CALL encrypt, then write V2 to the end of the file, and CALL decrypt. MAKE SURE THIS PART DOES NOT LIE IN THE AREA TO BE ENCRYPTED!!! This is how V2 would look with the concealer: V2_Start: Concealer_Start: . . . Concealer_End: Replicator_Start: . . . Replicator_End: Part_To_Encrypt_Start: . . . Part_To_Encrypt_End: V2_End: Alternatively, you could move parts of the unencrypted stuff between Part_To_Encrypt_End and V2_End. The value of encryption is readily apparent. Encryption makes it harder for virus scanners to locate your virus. It also hides some text strings located in your program. It is the easiest and shortest way to hide your virus. Encryption is only one form of concealment. At least one other virus hooks into the DOS interrupts and alters the output of DIR so the file sizes appear normal. Another concealment scheme (for TSR virii) alters DOS so memory utilities do not detect the virus. Loading the virus in certain parts of memory allow it to survive warm reboots. There are many stealth techniques, limited only by the virus writer's imagination. -=-=-=-=- THE BOMB -=-=-=-=- So now all the boring stuff is over. The nastiness is contained here. The bomb part of the virus does all the deletion/slowdown/etc which make virii so annoying. Set some activation conditions of the virus. This can be anything, ranging from when it's your birthday to when the virus has infected 100 files. When these conditions are met, then your virus does the good stuff. Some suggestions of possible bombs: 1) System slowdown - easily handled by trapping an interrupt and causing a delay when it activates. 2) File deletion - Delete all ZIP files on the drive. 3) Message display - Display a nice message saying something to the effect of "You are fucked." 4) Killing/Replacing the Partition Table/Boot Sector/FAT of the hard drive - This is very nasty, as most dimwits cannot fix this. This is, of course, the fun part of writing a virus, so be original! -=-=-=-=-=-=-=- OFFSET PROBLEMS -=-=-=-=-=-=-=- There is one caveat regarding calculation of offsets. After you infect a file, the locations of variables change. You MUST account for this. All relative offsets can stay the same, but you must add the file size to the absolute offsets or your program will not work. This is the most tricky part of writing virii and taking these into account can often greatly increase the size of a virus. THIS IS VERY IMPORTANT AND YOU SHOULD BE SURE TO UNDERSTAND THIS BEFORE ATTEMPTING TO WRITE A NONOVERWRITING VIRUS! If you don't, you'll get fucked over and your virus WILL NOT WORK! One entire part of the guide will be devoted to this subject. -=-=-=- TESTING -=-=-=- Testing virii is a dangerous yet essential part of the virus creation process. This is to make certain that people *will* be hit by the virus and, hopefully, wiped out. Test thoroughly and make sure it activates under the conditions. It would be great if everyone had a second computer to test their virii out, but, of course, this is not the case. So it is ESSENTIAL that you keep BACKUPS of your files, partition, boot record, and FAT. Norton is handy in this doing this. Do NOT disregard this advice (even though I know that you will anyway) because you WILL be hit by your own virii. When I wrote my first virus, my system was taken down for two days because I didn't have good backups. Luckily, the virus was not overly destructive. BACKUPS MAKE SENSE! LEECH A BACKUP PROGRAM FROM YOUR LOCAL PIRATE BOARD! I find a RamDrive is often helpful in testing virii, as the damage is not permanent. RamDrives are also useful for testing trojans, but that is the topic of another file... -=-=-=-=-=-=- DISTRIBUTION -=-=-=-=-=-=- This is another fun part of virus writing. It involves sending your brilliantly-written program through the phone lines to your local, unsuspecting bulletin boards. What you should do is infect a file that actually does something (leech a useful utility from another board), infect it, and upload it to a place where it will be downloaded by users all over. The best thing is that it won't be detected by puny scanner-wanna-bes by McAffee, since it is new! Oh yeah, make sure you are using a false account (duh). Better yet, make a false account with the name/phone number of someone you don't like and upload the infected file under the his name. You can call back from time to time and use a door such as ZDoor to check the spread of the virus. The more who download, the more who share in the experience of your virus! I promised a brief section on overwriting virii, so here it is... -=-=-=-=-=-=-=-=- OVERWRITING VIRII -=-=-=-=-=-=-=-=- All these virii do is spread throughout the system. They render the infected files inexecutable, so they are easily detected. It is simple to write one: +-------------+ +-----+ +-------------+ | Program | + |Virus| = |Virus|am | +-------------+ +-----+ +-------------+ These virii are simple little hacks, but pretty worthless because of their easy detectability. Enuff said! -=-=-=-=-=-=-=-=-=-=-=-=- WELL, THAT JUST ABOUT... -=-=-=-=-=-=-=-=-=-=-=-=- wraps it up for this installment of Dark Angel's Phunky virus writing guide. There will (hopefully) be future issues where I discuss more about virii and include much more source code (mo' source!). Till then, happy coding!