--------------- * Epidemic #1 * --------------- Introduction to polymorphism, part 1 What is polymorphism? The answer for such question seems to be easy, but it's not afterall. Few years ago people tried to standardize its definition and specify its complication degree by enumerating levels of decoders complexity, now, however, some new (especially on PC platform) types of polymorphism appeared and the definition became obsolete. In fact polymorphism means all the techniques modifying the virus' code that way, that in all the files infected by the same virus it appears to be completely different. Of course it can be achieved using different ways and solutions, but usually it is done by using a decrypting procedures generator which makes in a given buffer a crypted code and the decoder. It's the most effective way, the construction of decoder differs in different methods of file infection, i.e. in case of file-infecting virus similar to Beol96, PolishPower or NeuroticDeath decoder's entry point HAS TO be located at the beginning of the virus code, while basing on method used by Infiltrator virus we have a free-hand and can use variable entry point (entry point can be located wherever in decoder's code), or so-called EPO technique (EPO = Entry Point Obscuring). The last idea has, in my opinion, a great future when it comes to polymorphism. It allows constructing advanced decoders quite easy. Simple conversion of existing generator may force authors of antivirus programs to use code-emulation instead of algorythmic techniques, and NONE of existing antivirus programs on Amiga has such an emulator built in (well, except for VirusWorkShop, which is not developed any more). Although PC machines allow us to freely construct the decoders, in case of Amiga computers we have to add 2 blocks - first to put the registers on stack (often done by a single instruction - MOVEM.L D0-A6,-(SP)) and the second to clear processor's cache after decryption. Neccessity of using the first blocks is the results from passing the parameters to program by system during execution, i.e. CLI command line; the second block is neccessary to clear the cache memory - after decryption an old code [that is the one kept in memory before decryption] would be executed, thus we have to force the system to reload cache before the execution begins. It can be done by only one call - a call to 'exec.library' procedure - _LVO_CacheClearU(). So what should we know before we start writing our generator? 1. We should know what are we going to use it for. We can use it, aside from crypting the virus in files also to crypt the virus code in memory. This will make the virus detection and removal by an antivirus program more difficult to make. 2. We should know if decrypting procedure size is going to be constant or variable. In first case it doesn't make any problem, in other we have to calculate the size boundaries of our decrypting routines. Most optimal size is between 256 and 1000 bytes. Some viruses have smaller decoders, but it doesn't mean that these are more discovery-prone or weak.. Usage of different "tricks" may make such virus much more difficult to find. 3. Instruction set garbaging the code should be as wide as possible. Even better if those instructions use different addressing modes, but sometimes you can stumble on a decoders using garbage for decryption also. Such decoders work however on completely different registers and an antivirus program has to chose the correct ones to properly decrypt virus and heal file. 4. For each instruction having a given task in our decrypting routine, i.e.: counter initialization, an instruction loading crypted data address to a given register etc., we should also use some instructions working either similarly, or better - a few sets doing exactly same thing. If we had, lets say, four instructions, initializing counter and another three loading crypted data address, we can place them in any order in decoder. Effect will be exactly same, but the complication would grow much enough that it would be really difficult to locate one block in decoder, to say nothing of two and more. 5. Jumps. It's the most important element after instructions garbaging decoder. We don't really have to make a decoder the way where the code execution order does not change and the only jump is the instruction making a loop. It's easier to make it in case of creating constant-length decoder, where it is possible to place separate blocks of instructions at random offsets in decoder and later connect them with jumps. 6. It'd be best for us to locate the virus code anywhere except after the decoder and launch it with a call. Random offset (i.e. 4-60 bytes) will force antivirus program to scan virus' code, but the virus will remain unknown to the viruskiller even after decryption. It can be done with a few assembly language instructions 7. The weakest part of polymorphic decoder is the way it places the registers on stack. The more complex structures and code it uses to perform such operation, the bigger chances we have that our virus will not be discovered too early. We can do it various ways: a. by placing everything at once on stack with MOVEM.L (hex: $48e7fffe). It's the easiest way, but at the beginning of decoder we ALWAYS have constant 4 bytes, and this can weaken seriously even the most havoc decoder. b. by placing the registers on stack in blocks by using two instructions: MOVEM and MOVE. We can place some garbage instructions between those, but we have to remember not to affect the registers we haven't store yet. c. by placing registers on stack in any order and remember it (the order and which registers we have just put on stack) in a declared structure. Then, at the end of our decoder we place a block of instructions picking up the registers in reverse order. The first instruction of the decrypted virus code may store all registers on stack at once then, that is: MOVEM.L D0-A6,-(SP) 8. Decrypting loop shouldn't be created with DBRA (DBF) instruction. I bet all the antivirus programs will be searching for this instruction while detecting polymorphic viruses. Instead of this instruction we could use a set of Bcc ones, i.e. BPL.x, BMI.x, BNE.x and so on. 9. We should remember to use other than EOR instructions for decoding 32bit integers. We can also use SWAP, BCHG etc 10. The rest? If you know assembler well - use your imagination. It'd be best if decoders made by your generator were different than all the old and well-known methods. You may want to try stream decryption or multilevel decoding. The more work you will put in youe virus, the better results you will get. ------------ moveq #0,d0 rts MaD roGEr.