--==< An Introduction to Encryption, Part III >==-- Is an impenetrable encryption possible?. By MidNyte, February 2000 A short (and over-simplified) history of the virus ----------------------------------------------------- First of all came the un-encrypted virus. Then came virus scanners, which were basically just hex searchers looking for strings of hex only found in certain viruses. Viruses retaliated by coming up with encryption. Most of the virus is encrypted, and a small decryption engine at the start of the virus decrypts the virus body. As the encryption changes each time, the virus scanner is limited to searching for a much smaller section of code inside the constant decryptor. This wasn't much of a problem for virus scanners though. Viruses fought back again with polymorphism, this is essentially a way that a virus can change it's decryptor every time it infects a new file. That way no constant strings appear in the virus. Virus scanners came up with two ways to combat this, heuristics and emulation. Heuristics is simply looking for code that looks 'virus-like' This can be something as simple as the string '*.exe'. Emulation is the controlled running of the program instruction by instruction (not quite, but close enough for this article). A virus, under emulation, will be allowed to run just enough to decrypt itself and reveal it's code for either a straightforward scan or a generic (heuristic) scan. Anti-emulation is the viruses way of defeating this, it is a basically a way to detect emulation in progress and act accordingly. Some anti-emulation systems are incorporated into the decryptor of a virus, so that if the virus is being emulated it will not decrypt properly and hence not reveal it's code. Another defence the virus can use is anti-debugging, which is designed to hinder people who try to debug (in this case unencrypt) your code. This is different in that it doesn't defend the virus from antivirus programs, it defends it from the antivirus companies, the people who will try and study the virus and work out a way to detect it. Anti-debugging can be very simple, like turning off the keyboard interrupts at the start of the code and back on again at the end or it can be quite complicated, with the actual anti-debugging routine also being used as a key to decryption to protect against patching. This is the focus of this article. Anti-debugging: more detail ------------------------------ Anti-debugging tricks are basically little pieces of code that have no overall effect on the running of a virus when being run as normal, but that cause the virus to malfunction, crash or worse when they are run under a debugging environment. The simple example above was to turn of the keyboard interrupt at the start of the code, and turn it on again at the end of the virus before control is passed back to the host program. This is simply achieved with: in al, 020h ; \ or al, 002h ; }Disable Keyboard interrupt out 020h, al ; / ...at the start, and: in al, 020h ; \ and al, 0FDh ; }Enable keyboard interrupt (FDh = NOT 2) out 020h, al ; / ...at the end. When the virus is run under normal conditions, the keyboard is only off for a very small time, too small for people to notice. If the program is running under a debugger, as soon as the first few instructions are run the keyboard will no longer work, leaving the person at the debugger with no choice but to reset (at least it used to be in the good old days :) The simple work around for the person debugging was too simply patch over the code that turned off the keyboard with NOPs or other do-nothing instructions. Now the virus would work as normal under a debugger, without disabling the keyboard. To retaliate from this, the virus started to use it's anti-debugging routine as a key for decryption. The hex string to turn off the keyboard is 'E4 20 0C 02 E6 20'. If this was one of the decryption keys, the person debugging could not just replace the instructions with NOPs as this would change the key to '90 90 90 90 90 90' and cause the virus to decrypt incorrectly. This seems like an ideal solution, but unfortunately it is not. The whole point of this article is to point out the following fact: Any decryption routine can have it's basic functionality copied by someone determined to debug it. This means that your routine that uses an antidebugging routine and also uses that routine as a key for further decryption could be useless. Let's go through it with an example. The original virus looks like this: start: in al, 020h ; \ or al, 002h ; }Disable Keyboard interrupt out 020h, al ; / xor si,si lea bx, start_of_encrypted lea cx, end_of_encrypted sub cx, bx shr cx, 001h decrypt: mov ax, word ptr [start+si] xor [bx],ax inc si cmp si, offset decrypt jne next_key_word xor si,si next_key_word: loop decrypt The pointer to the relevant word of the decryption key is kept in si, and means that the key is all the code from 'start:' to 'decrypt:'. This works out as 'E4 20 0C 02 E6 20 33 F6 BB 19 01 B9 36 01 2B CB D1 E9'. If the keyboard part was nopped out the key would change to '90 90 90 90 90 90 33 F6 BB 19 01 B9 36 01 2B CB D1 E9', as we've already seen. What the person doing the debugging could do though, is simply take the encrypted portion of the virus and put it into his own program, only this time the key would be stored as data, not as an executable part of the program, like this: start: xor si,si lea bx, start_of_encrypted lea cx, end_of_encrypted sub cx, bx shr cx, 001h decrypt: mov ax, word ptr [key+si] xor [bx],ax inc si cmp si, offset key_end jne next_key_word xor si,si next_key_word: loop decrypt key: db 'E4 20 0C 02 E6 20 33 F6 BB 19 01 B9 36 01 2B CB D1 E9' key_end: As you can see, the above will decrypt the encrypted section in exactly the same manner, only because the key is stored as data we can change the code as much as we like. Is an impenetrable encryption possible? ------------------------------------------ So then, is it possible to include enough current techniques, or to come up with a new technique to completely eliminate the chance of the antivirus programmers being able to decode it? Many people think that they have found a way to ensure that their program is completely impenetrable to decryption unless it is running at the time. This is, unfortunately, unachievable in theory. Because of the above demonstrated technique, any anti-debugging technique can be overcome by someone with enough time to debug a program by hand. This means that *any* anti-debug code you put into a virus can be got around eventually because the person debugging can always read what is going on in a hex editor and make a new routine to simulate it, hence the routine you write will not always be used to decrypt the code. They will only see one layer of decryption at a time, however, and this is the key to making in impenetrable encryption. Conclusion ------------- In the end then, we can never make it *impossible* for a researcher to decrypt a virus through programming tricks, however we can make it *impractical* through the use of scale, ie, we can use so many layers and different tricks that it is impractical to debug. If it takes a week for a programmer to decrypt a virus with hundreds of layers of encryption, they may be able to justify it. If they have ten viruses of this kind it gets harder to justify, and with a hundred of them it starts to get impractical. The ball would be back in their court. Contact ---------- Comments/questions/suggestions/bug reports/etc. are welcomed as always, as long as it is kept reasonable. - MidNyte As always, I welcome ANY feedback, good or bad, as long as it is reasonable. | midnyte01@excite.com | www.coderz.org/midnyte | www.shadowvx.com/midnyte |