Sepultura
Insane Reality Magazine [7]
December 1995
Use anarchy to get what you want
Most virii these days, take many Pre-Discovery precautions. This simply means that they take precautions to avoid discovery, assuming the virus has not already been discovered. Common examples of Pre-Discovery Stratagies are File Stealth, Sector Stealth, and MCB stealth (i.e any stealth). These mechanisms are used to stop the virus being discovered, but once it has been discovered, and is in the hands of the AV, they're essentially useless. It is only a matter of days (or even hours) until a suitable scan string or algorithm has been determined, for inclusion in to there AV programs.
There is how ever, a solution: post discovery strategies. These are mechanisms that instead of serving the purpose of hiding the virus from detection, make the virus harder to analyse, and hence determine a scan string or detection algorithm. To be entirely honest, the previous statement is not completely correct - in order to take advantage of any of these methods your virus can not have a scan string - without atleast polymorphism, Post Discovery Stratagies are useless. This document will be divided in to three main sections:
I have decided to do it in that particular order, as it follows my master scheme, which in my opinion takes maximum advantage of Post Discovery Stratagies, and which I will outline throughout this document.
I have supplied example code fragments throughout this document, several full programs in the Anti - Debugger section, as well as a bait maker in the Anti-Bait section, so you can test your Anti-Bait routines.
I used the enemy I used anarchy
This section is not intended to tell you what a polymorphic engine is, nor will it tell you how to code one. If you do not know either of these, you should read this when you do, or alternatively you could read this, and take the explained methods in to account when you do code one.
The thing you have to remember is that the AV people need to devise an alogrithm that will detect near to 100% of their samples, but at the same time, have only a small number of false positives. Your job, is ofcourse, to stop them from doing this.
One of the most obvious things that would you help in your Post Discovery Stratagies, is to make the decryptors and junk as varied as is possible. This way, they cannot use an algorithm that traces through the code, and concludes that the file is not infected, as soon as an opcode is encounted that can't be generated by your engine. What might not seem to obvious, is that although your engine should be able to CREATE a wide variety of junk instructions, it should not USE a wide variety of junk instructions in each decryptor. This might seem strange, but it can be very useful in delaying the AV's efforts. This is because there are two methods that the AV will use to analyse your engine:
The first of these can be countered by keeping the actual engine encrypted, independently of the virus, and then keeping the decryptor protected - using the methods outlined in Section 3 (Anti - Debugger Techniques).
The second method can be countered using the techniques that will be discussed in this section (Polymorphism), and Section 2 (Anti - Bait Techniques).
By using only a very small variety of the large number of junk instructions that your engine can generate, when the AV people look at the sample bait files, they will only see a small selection of the junk that your virus can really create. Because your polymorphic engine is so heavily encrypted / armoured, they will not have time to disassemble it, and will have to make their judgements based on the bait files. However, since the decryptors will only have a limited selection of all possible cases, they could easilly make the mistake of basing their algorithm on just those decryptors, and release an incomplete algorithm. Of course they will not realise their mistake until it is to late. Let us look at the following code as an example:
The above code fragment, will ensure that all files infected in any 1 session, will only use 5 out of the 15 possible junk instructions.
The above techniques work well, but can be even more effective, when used in conjucntion with slow mutation. Slow Mutation basically means that instead of making certain descisions based on random numbers, you make the descisions based on relatively static values. The most common values used for this, are from the date (i.e. the month or day of the month). For example, let us imagine that the sub - procedure 'choose_junk_routines' in the previous example, was replaced with this:
The advantage of using this method, is that the same set of five junk routines will be used for a entire month. With the previous example if the AV was to make some bait files, and look at them, and think that your virus only generated five different junk instructions, and then ran the bait maker again, another time, after resetting the system, he/she would get bait file with (probably) a different set of junk instructions in the decryptor. Because of this, he/she would probably catch on. This is important to note, because they will have to make a set of bait files to devise the algorithm, and then at least another set to test it. If you based the 5 instructions on the month, and armoured the choose_junk_ routines procedure, then they would get the same 5 instructions, because they would be all produced in the same month, and would not easily catch on. Other things you should base upon slow mutation techniques include things such as what registers to use, the looping method, the encrypt/decrypt method, and the length of the decryptor. This way, they have to reboot the computer each time, and set a new date, to see all possible combinations. Consisdering there are thousands of bait file to be made, this also means that there are thousands of resets to be done!
Another thing you could base slow mutation descisions on, is a generation counter. This is very effective, because if the AV runs an infected file, and then because the virus is TSR in memory, runs the bait creator, to create some infected samples, all the infected samples, will be of the same generation. Even if the AV people think of changing the date, the fact that the virus changes some aspects of itself on each generation, will not be so obvious. This is especially true if the virus makes the changes on, say every fourth generation, instead of each and every generation. For example:
Of course, you do not have to base something as trivial as the method of decrement on the generation counter, and could instead base something more important like the actual method of decryption on it.
Also, if you wanted to be really sly (and I know you do), you could use the above method, but then release the virus in the wild, with its generation counter set to something like 16. This way, no one will see the first 2 methods, until the generation counter has carried over. About a week after releasing it, you could release it somewhere else, so that the AV people will get the first specimen, and their algorithm will be missing the first two methods, while the second infection you release can have the counter set to 0, so that the decryptors using the first two methods will be in the wild, and will spread, before the AV realise their mistake.
Another thing you could base your slow poly on, is the file you are infecting. For example, let us imagine you based the above example on the SIZE of the file to be infected, divided by 1000, rather then the generation divided by 8. Since the bait files will be of the same or similar size, little to no change will be seen. If a different file of a different size was infected however, you would have a totally different decryptor!
One of the biggest mistakes you could make when coding an engine is making two conditions dependant on the same thing. For example let us imagine that you made both the index register used, and the decryption method used dependant on the month. This could possibly mean, that when XOR encryption is used, you can guarantee BX is the index register, and when ADD is used SI will be the index register. This way, all they have to do is check for a XOR [SI],?? instruction or a ADD [BX],??. If you made this mistake, and had four index registers, and four decryption methods, the scanner need only to check for four possible instructions. However, if these were decided on totally independant criteria, they would have to check for 16 different instructions, increasing the chance of false positives. For another example, let us look at the following:
The above example will always generate, a working, conditional jump. It does however have a fairly obvious flaw. If the jump opcode is 70h then the offset of the jump will be 0, 10h, 20h, or 30h. If the jump opcode is 70h then the offset of the jump will be 1, 11h, 21h, or 31h. This will remain true for all of 70h to 7fh. This is very dangerous, as a scanner could something like this in its algorithm:
As you can see, if many things are dependant on each other, an algorithm could be used that uses techniques like the above, and if all rules are followed, safely assume the file was infected. To avoid the above check, the conditional jump coder should be something like this:
As you can see, in the above example, the offset of the jump is totally independant of the jumps opcode. This will make the detection algorithm alot harder to devise.
Hate your enemies
By using the methods explained in the previous section, we can safely say that the AV can not simply set the bait maker to generate 10,000 bait files, with the virus in memory, and get an accurate and complete of what is necessary. Instead they must use many varying files, reboot the system thousands of times to change the date, and fiddle with the generation counter, which will significantly slow things down. But let us take things a step further: let us imagine that the virus won't even infect the files in the first place. This would simply involve putting the candidate file through a number of tests, and if it fails any of them, saying the file could be a bait, and not infecting them. This section simply looks at what some of these test could entail.
The are two very obvious and easy test your virus should have:
New files should not be infected, as the files created by a bait maker will usually look new. Simply grab the current date, and compare it to the date stamp of the file. It is the same? Well then dont infect! It should be noted that this is easilly defeated, if the bait maker sets the files date stamp to a random date, before closing it.
The files created by bait makers, will usually be fairly small, so small files should be avoided. I would recommend that you avoid files smaller then between 5,000 and 10,000 bytes. The smaller you make this limit, the less chance there is that a legitimate file will be wrongly be left uninfected, but it is also more likely that a bad bait file will wrongly be infected. By making the limit larger, the greater the chance there is that a legitimate file will be wrongly be left uninfected, but its also more likely that a bait file will correctly be left uninfected. High limit or Low limit? The choice is yours... This could easilly be defeated if the bait maker created files which were, say, 50,000 bytes. This size is obviously far to large to avoid, as it is larger then many legitimate programs. You should also remember however that 10,240 files at 5,000 bytes will use 52 megabytes, so if the bait files were 50,000 bytes long, this figure would go upto 520 megabytes! Most test computers do not have such lard hard drives, so it is safe to assume that the bait files will be small.
As the above two methods are so easy to implement, I will not bother to supply any example code.
Most bait makers create filenames like '00000000.com' followed by '00000001.com'. All the file are names composed of the characters '0' to '9'. We could have a check in our virus, to ensure that this is not true, and if it is, not infect the file, as shown below:
This method could easilly be defeated by using file names like 'AAAAAAAA.COM' instead of '00000000.com'.
Many people consider this method overkill, but it is extremely effective, if you are serious about your Post-Discovery-Stratagies. It works by checking if the currents file to be infected, has a consecutive file name of the previous filename. For example, if the previous file to be infected was called 'AAAAAAAA.COM' you would not infect the next file if it was called 'AAAAAAAB.COM'. The easiest way to do this, is save the sum of the characters of the file name. If the next file is consecutive to it, the sum will be the sum of the previous one + 1. i.e:
'AAAAAAAA' = 'A' + 'A' + 'A' + 'A' + 'A' + 'A' + 'A' + 'A' = 208h
'AAAAAAAB' = 'A' + 'A' + 'A' + 'A' + 'A' + 'A' + 'A' + 'B' = 209h
Therefore, of the filename of your candidate file, and use it to check if the next file to be infected is consecutive. If it is do not infect! Example:
The above code is fairly lengthy, and messy, but it works! You should also not infect a file, if it is the same length as the previous file, for obvious reasons. This code could by defeated by incrementing filename by values other then 1, or even by incrementing it by a random amount each time.
To help you test your Anti-Bait code, I have put together a Bait Generator (Sepultura's Funky Bait Maker), which can be modified to show how each of the above methods are defeated. Here is the complete source:
The above Bait Maker can be very useful, to test your Anti-Bait techniques. It is also quite useful, for its orginal purpose - analysing virii. Use it for either - AV - VX - they're all the same to me.
The master hides behind the mask
Ok, now the AV can not even get your virus to infect their bait files, and if they do finally manage, they will have great problems in getting a complete, accurate view of what they are dealing with. There is two things they can do:
Both of the above can be defeated by using Anti-Debugger Techniques. The first is defeated by keeping your Anti - Bait routines encrypted, and heavilly armoured, to prevent disassembly. The second can be defeated by using the same methods on your polymorphic engine. This section has been designed to tell you how to do it.
There are many simple and trivial ways to thwart debuggers. This document will deal mainly with more advanced methods. The simple methods outlined in this section can be seen in the code example of "Using Your Anti-Debug Routines as the Decryption Key", later on in this document.
Perhaps the most obvious way to kill a debugger, is to overwrite the Interrupt Vector of Interrupts 1 (Debug Single Step), and 3 (Debug Break Point). This can be defeated by simply skipping the instructions. Another thing you could do, is place an INT 3 in a long loop, which will cause the debugger to stop at the INT 3 each iteration, which will stop the AV from simply proceeding through the loop. This is very easilly defeated by NOP'ing out the INT 3.
Another thing to do, is turn of the keyboard. There are manyways to do this, but the simplest is:
This technique involves replacing the vector of a INTERRUPT 1/3 with the interrupt off another interrupt, and calling that instead. This works especially well with INT 3, as it is only 1 byte long, and can not simply be replaced with the proper Interrupt. Here is an example of INT replacement from the virus [H8urNMEs]. It changes INT 3 to point to the tunneled INT 21, and calls INT 3 for all DOS requests:
It simply makes INT 3 point to DOS, and uses this fact to fetch the INT 24 vector.
When tracing through code, with INT 1, the 6 bytes below SP are overwritten with the pushed returnig IP, CS, and Flags. There are 2 ways to take advantage of this fact. The first is to PUSH a value on to the stack, POP it, and then adjust SP and POP it again to see if it changes. If it has, the code has been traced. Here is an example:
The second way is to store a critigal value like a Decryption key in SP. This value should also point to the code, and you should not use any stack operations. This way, if a debugger is running, the code that SP points to will be overwritten. Here is a complete program to illustrate it. To make it run properly, you must have to encrypt it. I will not how you how.. If you can not work it out you should not even be reading this. It also has the added advantage of avoiding the TBAV '#' (decryptor) flag. Any way here it is:
This is a lot easier to do then it sounds. Basically, all you have to do is retreive a byte from the Anti - Debugger routines each time, and use it to modify your decryption routine in some manor. Of course the code you are decrypting must have been encrypted in a corresponding manner! Any way, here is a code fragment example:
The last method, I am going to illustrate, is called the Running Line. It is VERY resistant to debuggers. It involves hooking INT 1, and Decrypting each instruction just before it's run, and Re-Encrypting it straigh after it has been executed. This way, only 1 instruction at a time is decrypted in memory. Here is a fully working example.
Taught when we are young to hate one another
I strongly urge you to employ the above techniques in your virii and/or poly engine. If your virus refuses to infect bait files, is very heavilly armoured, so the can not decrypt it, and dissasemble it, and mutates so slowly, and on such obscure conditions, how are they going to it? Devising an algorith for such a virus would be very difficult.
Thank you reading this article. I hope it's been as interesting to read as it has been to write!! Hopefully, we will be seeing the AV having to work a lot harder for their money too ;). Alternitively, this could be some help to the AV community, so they can see what lies ahead.
If you have any questions, comments, critisms, or new ideas, you can get in touch with me on IRC, channel #VIRUS, Nickname 'Sepultura' or 'Sep'. I would really appreciate any comments (excpet 'Get Bent!!').
[Back to index] [Comments (0)]