Insane Reality issue #8 - (c)opyright 1996 Immortal Riot/Genesis - REALITY.013 Article: Polymorphism Author: Rogue Warrior [IRG] % Improved Polymorphism by Rogue Warrior [IRG] % ________________________________________________ These docs are ESSENTIAL for the modern virus writer.. read them! - _Sepultura_ ============================================================================= ============================================================================ === Rogue Warrior's Guide to improving Polymorphic Engines ============================================================================ === Table of contents :- 1. Introduction 2. Levels of Polymorphism 3. Polymorphic Virus Detection Methods 4. Combatting Detection Methods Anti-Scan String Cryptanalysis Generic Decryption 5. Combatting Analysis of your virus by AV researchers 5. Conclusion ============================================================================ === Introduction :- This is a guide for those who already know how to make an engine but cannot work out why their viruses are still detectable. The single purpose of polymorphic viruses is to avoid detection - at the heart of the polymorphic virus is the engine. It can usually take from 30-80% of the virus code size so is a very important component of the virus to have working properly. This guide will tell you how polymorphic detectors work in order to help you design/make a better engine to defeat scanners. Making a good engine takes a good amount of time. If you don't make it correctly you might as well leave it out completely because it's main purpose (avoiding detection) will not work!. ============================================================================ === Levels of Polymorphism :- Polymorphism covers has many levels of skill. According to Vesselin Bontchev (AV) these are :- 1. Fixed set of constant decryptors (a.k.a Oligomorphic). 2. Variable instructions for single instruction. 3. Garbage code insertion. 4. Instruction swapping. 5. 2+3+4 --------------------------------------------------------- 6. Permuting #6 is not considered higher than #5 it's simply considered a different classing. I think there is now a 7th class. Highly advanced polymorphism which is designed to be better than #5. These ones have the following attributes: * Heuristic counter-measures * Goat counter-measures * Emulator counter-measures All these attributes are not part of the virus but instead part of the _polymorphic code produced by the virus_. ============================================================================ === Polymorphic Virus Detection Methods :- There are many methods for detecting polymorphic viruses here are some popular methods: - Scan Strings - Variable Scan Strings - Cryptanalysis - Generic Decryptor - Heuristics Scan Strings ::- Works by searching for a pattern of bytes in FIXED positions and a FIXED sequence. e.g., scan string: aa ?? bb ?? cc virus text: aa xx bb xx cc Variable Scan Strings ::- Work by searching for a pattern of bytes in VARIABLE positions but in a FIXED sequence. e.g., scan string: aa * bb * cc virus text: 1. aa xx xx bb xx xx xx xx cc 2. aa bb xx xx xx cc 3. and so on... Cryptanalysis ::- Works by finding part of the VIRUS BODY and then performing some very basic cryptanalysis on it and then decrypting it (if possible). This method according to many AV is not used anymore (due to the effectiveness of Generic Decryptor) but I will tell you how to defeat it anyway just to be sure ;-) -- its not hard to defeat. Generic Decryptor (a.k.a. Emulation) ::- Works by emulating instructions in the polymorphic decryptor in order to make the virus decrypt itself and then it detects the virus by a standard scan string. Heuristics ::- This has undeservedly been a virus buzz word for a long time. It has been the target of polymorph engine creators to beat the heuristics which shows how little they know of polymorphic detection. This method involves searching for inconsistencies between the code being analysed and normal everyday code found in programs. While it is important - it is not THAT important and will not help you stop being detected by anti virus software. It is important to note that heuristics is not used very much (they do use a bit) in the most popular AV programs (F-PROT, McAfee and AVP) these are the programs you should target. Do not target programs which only hard core virus people use. Most of the hard core AV software could spot a virus anyway. -- in other words: _target the less intelligent software users_ ============================================================================ === Combatting Virus Detection Methods :- ---------------------------------------------------------------------------- --- - Anti Scan String methods This is really easy - avoid the use of code common to every decryptor just because some code isn't in the same position doesn't mean it cannot be scanned though. For example: xx=garbage code. Your Decryptor #1 (as hexidecimal): 45 34 xx xx xx 54 80 xx xx xx 12 xx xx xx 34 32 xx xx xx 43 xx xx xx xx Your Decryptor #2: xx xx xx 45 30 xx xx xx xx xx 54 81 xx xx xx xx xx 12 xx xx 34 32 xx 43 Looking at this code you can see an obvious pattern it can be scanned using this string: 45 3? * 54 8? * 12 * 34 32 * 43 Legend: ? - match 1 positions only * - match up to N bytes but low as 0 bytes This will identify this decryptor (not the virus) by looking for code common to each decryptor. So how do you combat it? Well try making sure that you always have at LEAST 1 alternative to every instruction your engine can generate. NOTE: Make enough alternatives that it makes multiple variable scan strings not an option to AV! ---------------------------------------------------------------------------- --- Cryptanalysis :- This is very easy to defeat - simple add multiple encryption operations for example: A loop using a single XOR with byte/word is very easy to cryptanalyse but a loop using XOR b/w, ADD b/w, SUB b/w, ROL b/w in one loop is VERY hard to cryptanalyse. The only problem with this is applying the encryptions in reverse order to that of your virus decryptor so that when the virus decryptor is run it will do it in the correct ordering. There is an easy way to do this! -- There isn't really I was just joking there is no easy way =) You can leave bit out anyway because AV's are using all using Generic Decryption as far as I know. ---------------------------------------------------------------------------- --- Generic Decryption :- This method is very popular amongst AV and requires the cooperation of the virus to work. If a virus can detect it is being emulated and then throw an emulator off by some method then it will defeat this method. Products known to be using this technique are: F-PROT AVP TBAV DSAV (and I would guess McAfee?). How does generic decryption work? well the AV products each have in them a little Intel software CPU emulator which does not allow instructions to actually execute but simulates them enough in certain controlled ways in order to make the virus decrypt itself in a safe environment - this way all they need is a scan string for a very complex polymorphic virus! These controlled conditions avoid endless loops and other similar bugs in normal programs from making the emulator hang. I experimented and found that making a 10 KB decryptor on a virus will dramatically slow down scanning in DSAV and AVP because the emulator is actually simulating the code. I made 10 x 10KB samples and these took over 3 minutes to be examined by DSAV and AVP however each of these took only milliseconds to run normally. This shows that the emulators in DSAV and AVP are really quite good and don't give up easily when trying to decrypt a virus (I used the /ANALYSE option on DSAV). F-PROT and TBSCAN did not emulate these samples correctly even with maximum heuristics enabled or if they did they must have discovered how to simulate INCREDIBLY quickly (even TBSCAN being written in assembly language cannot run them that fast). So how do we stop this emulation taking place? or better put: How do we detect ourselves being emulated and throw the emulator off? e.g., Imagine we know that the PSP contains a certain constant value at ALL times - but we also know the emulator doesn't emulate the PSP. With this knowledge we can construct some code in our polymorphic DECRYPTOR to detect this and throw the emulator off: mov ax,[0000] sub ax,20CDh jz ok mov ah,4Ch int 21h ok: Note: This code must be in the decryptor because it's goal is to stop decrypting BEFORE we reach the virus body. This code must be generated with the same principles of variability that all other poly code requires - if you don't make this code variable also then you risk having the code used against you to detect the virus!!! Possible methods to exploit for detecting and terminating emulation: - Inability of DOS call return values to be predicted by the emulator without actually calling them. i.e., we can make a DOS call in the poly code and check the return values. If they are not consistent with a REAL call to that function then it can be assumed we are being emulated and then take evasive action. - Inability of emulator to write to ALL of memory. By writing to safe areas in RAM we can test if that area has ACTUALLY been written to by the virus or just emulated. If it has not been written to then we assume emulation in progress. e.g., long winded version: cli ;disable ints cld ;set data string copy direction push 6000h pop ds ;any segment which AV and virus don't own. push ds pop es ;es=ds=6000h sub si,si mov di,0002 lodsw ;save in ax, si=di=2 xor ds:[0000],1234h ;write mov cx,0f000h ;some large amount L1: rep movsw ;write to memory (a large amount is better) cmp ds:[0000],ax ;did the AV forget about the write? mov ds:[0000],ax ;set it back to normal regardless jz not_emulated ;seems they messed up remembering where we wrote. mov ah,4Ch int 21h ;bye Mr Emulator. not_emulated: - Inability of emulator to emulate all control structures (PSP, MCB, SFT, etc). Most emulators can emulate the PSP, MCB and so on but every single structure would take too much memory and processing so trying to exploit this possible weakness is a good idea. TbClean a program which emulates viruses to disinfect programs only emulates certain small parts of the PSP leaving other parts to be exploited by emulation trapping. In fact one can trick TbClean into converting the virus infected file into an infected Trojan horse program for the person who runs it next. NOTE: TbClean is good fun for testing your polymorphic decryptors it shows you how the emulator is going to go through your code like a hot knife through butter. Make sure to crack the registration on TbClean so you can use it properly . - Limited resources of an emulator. Remember that many AV programs are built to be fast so by making your virus take a very long time (in AV program terms) to analyse your virus might make it quit thinking that it has encountered an endless loop. However! running a time consuming decryptor normally takes next to no time. So we can see that resources of time, memory, processing power all contribute to methods for killing off an AV scanner emulator. *** You must think how to detect and force the emulator to quit *** ============================================================================ === Stopping analysis of your virus by AV researchers AV researchers are the ones responsible for making your virus detectable so having some ways to hinder AV researchers doing analysis of your polymorphic virus and engine is always good to throw in. The most common way to analyse a new polymorphic virus is to generate 1000's of samples of your virus. This involves activating the virus on a test computer and executing 1000's of goat programs. The goal in generating these 1000's of copies is to get a good sampling of what the engine can generate and then test the detection method against it. If your virus chooses only to show a certain sample then their detector may work in the Lab but not when it comes to "in the wild" situations. Of course it is best to not make it obvious to AV that you are trying to do this or they might catch on and alter their methods. ============================================================================ === Planning your engine features It's always good idea to have plan of the engine structure. Many coders spend their time byte-fiddling trying to optimise their code - this method of planning enables to you block-fiddle - each of these blocks can be shuffled and optimised meaning every change for the better is saving you lots of bytes instead of 1-2 bytes. NOTE: NEVER place ANY code in a CALL/RET routine unless it is used more than once! A polymorphic engine is very similar to the code generation phase of a compiler - most compiler writers use the word "emit" [1] as the word to say they're outputting code. So try to use the same because it's good to follow this standard when planning your engine. [1]: Means "output" or "give off" for those bad at English. e.g., Here is a very basic model of an engine plan (you may want to add more detail than this to any plan you make): Engine: EmitDecryptor EmitDecryptor: repeat EmitGarbage & EmitAntiEmulation, random(5) times EmitSetupRegs repeat EmitGarbage & EmitAntiEmulation, random(5) times MarkLoopStart repeat EmitDecryptionCode, random(5) times repeat EmitGarbage & EmitAntiEmulation, random(5) times EmitEndLoop repeat EmitGarbage & EmitAntiEmulation, random(5) times End-EmitDecryptor EmitGarbage: Randomly Select 1 of: EmitFakeINT21 - randomly select some int 21 functions EmitFakeINT10 - randomly select some int 10 functions EmitCMPbmemXX - cmp byte ptr [xxxx],xx EmitCMPwmemXXXX - cmp word ptr [xxxx],cccc EmitMOVbmemXX - mov byte ptr [xxxx],cc EmitMOVwmemXXXX - mov word ptr [xxxx],cccc EmitMOVbregXX - mov rb,cc EmitMOVwregXXXX - mov rx,cccc EmitMOVbregMEM - mov rb,byte ptr [xxx] EmitMOVwregMEM - mov rw,byte ptr [xxxx] EmitCALL - CALL xxxx/garb/jmp yyyy/garb/xxxx:/garb/ret/yyyy: EmitJMP - JMP xxxx/garb/xxxx: End-EmitGarbage EmitAntiEmulation: Randomly Select 1 of: EmitFarCALL - place RETF into mem/CALL yyyy:xxxx EmitFarJMP - place Far JMP into mem/JMP yyyy:xxxx EmitWriteAndTest - write to known RAM mem, test it changes, if not crash EmitFakeExit - set int 21 = virus_cs:virus_return and call ah=4c, int 21 EmitPSPcheck - cmp ds:[0000],21CDh/jnz crash: use better check! just an example. EmitDOScheck - dos call/check return value is consistent. End-EmitAntiEmulation EmitSetupRegs: If Boolean Then LoopType = Counter or Pointer Select Count Register from [AX,BX,CX,DX,SI,DI] Select Pointer Register from [SI,DI,BP] Else LoopType = Pointer Select Pointer Register from [SI,DI,BP] End If End-EmitSetupRegs MarkLoopStart: Save output pointer (usually DI register) to remember loop location. End-MarkLoopStart EmitDecryptionCode: Randomly select 1 of: EmitXORptr EmitADDptr EmitSUBptr End-EmitDecryptionCode EmitEndLoop: If LoopType=Counter and Counter=CX and Boolean Then EmitLoop Else If LoopType=Counter and Boolean Then EmitDECJNZ Else If LoopType=Counter and Boolean Then EmitDECJZJMP Else If LoopType=Pointer and Boolean Then EmitDECCMPJNZ Else If LoopType=Pointer and Boolean Then EmitDECCMPJZJMP End End-EmitEndLoop This is just a simple example of a plan so you can see how to structure your engine - do not forget these parts: - encrypting the virus body in reverse order and reverse operation. - adjusting for execution location in memory: if the entry point of the virus is not at a zero offset then you must adjust all memory references and pointers by the relocation amount. This part is usually done while emitting. ============================================================================ === Conclusion If you are going to go the trouble of making a polymorph engine then do it right and don't waste 1-3Kb of code on an engine which can be generically decrypted. If you are going to make a good engine remember the following points: - it must not have fixed bytes in fixed positions. - it must not have fixed bytes in variable positions. - it must not be able to be decrypted by generic decryption engines in AV software. - it helps if the code is heuristically "clean" but it is not the be all and end all of an engine to be this way. - make sure it is a bitch to analyse by AV. - make sure it is a bitch to remove if it does get caught. The final pain in the ass Some AV are obsessed with EXACT detection - even if they are able to detect your decryptor like they do to many some TPE based viruses - in the end they always want exact detection. So try to make your engine such a hard ass that it might allow detection of the actual "decryptor" part but NOT the virus body - This will be a great annoyance to the AV (even though they may say otherwise). Remember inexact detection leads to inability to remove the virus and if you virus ever becomes common they will have to answer the customers question "why can't you remove it ?". ============================================================================ ===