Understanding Polymorphic Viruses

By Jeff Silverman

This essay is an executive summary about Polymorphic Virus.  It explains what a polymorphic virus is, the details about how to write one, and why they are so hard to detect.  The risks from polymorphic viruses are compared against other viruses.  Finally, I propose some suggestions for strategies which IS managers could take which will reduce the threat of damage due to viruses.
 

A discussion of terms

virus
a computer program which attaches itself to other computer programs and causes them to do something that harms the computer, or the data in the computer, or the network which connects to the computer.  Some writers distingush between "viruses" and "worms". 
worm
A worm is a stand alone program as opposed to a program that attaches to another program; for the purposes of this discussion there is little difference. 
Payload
The "payload" of a virus is the part of the software that actually does the damage; the rest of the virus is used to break the security.
Signature
Each virus has a "signature"; the "signature" is a string of bytes, which, if it appears, is diagnostic of the virus. Care must be taken when picking signatures, because if a signature is common then it will snare uninfected programs by mistake, this is a "false alarm". if the signature is too long, then it will fail to detect encrypted viruses and polymorphic viruses. Picking good signatures is key to a high probability of detection and a low false alarm rate.
Virus scanner
A "virus scanning program" is a program that scans other programs looking for viruses.  From the point of view of a virus scanning program, a virus is a string of bytes.  The scanner works by comparing the contents of all of the programs in a computer against a database of viruses. 

For the purposes of this discussion, there are three kinds of viruses: a "normal" virus, an "encrypted" virus, and a "polymorphic" virus.  "Normal" viruses are not encrypted in any way, and you can examine how they work using a standard debugger or disassembler.  "Encrypted" viruses have two parts, a decryption routine and an encrypted payload.  The payload includes a compatible encryption routine so that virus can infect other machines.  A "polymorphic" virus is similar to an encrypted virus, except that the decryption routine has been cleverly coded in chunks, and each chunk ends with a jump instruction to the next chunk.  The chunks come in different sizes and orders and there can be junk bytes in between the chunks.  Thus, there is no consistent signature for the virus and detection is very difficult.
 

Why are polymorphic viruses so dangerous?

We can measure the quality of a virus scanning program using three figures of merit: speed (fast is good), the probability of detection (ideal is 1.0) and the probability of false alarm (ideal is 0.0).   The problem with measuring  Pd rates and Pfa rates is that the process of detecting viruses is deterministic, so if your virus scanner misses a virus on a first pass, it will miss it on subsequent passes. Nevertheless, it is possible that a virus scanner manufacturer may pick signatures that are too short, which will give many false alarms, or too long, which may miss a virus variant.
Real virus scanning programs have Pd rates approaching 1.0, and Pfa rates approaching .00 for unencrypted viruses, especially if you keep the software and the signature files up to date.  See for example The Virus Test Center anti virus tests for April 2000 for details.  However, for encrypted viruses and for polymorphic viruses the signatures can be as short as three bytes.  So virus scanning is not a universal panacea.

There are viruses out there that will format your hard drive, and flash your BIOS.  Are polymorphic viruses any worse than these?  In terms of the damage done, no.  However Polymorphic viruses are more dangerous than normal or encrypted viruses because they are very hard to detect.  There is no string of bytes that consistently identifies an infected file.  So a system can be infected for a long time, and infect other machines, without anybody being aware of the problem.
One proposed method of detecting polymorphic viruses (see Symantec's "How to manage Polymorphic Viruses") is to create a "black box" in RAM and run the program.  If the program attempts to modify something it isn't supposed to, then it is a virus.  The problem with this approach is that the virus could use some logic to run only a certain fraction of the time, or after a certain date.  Determining whether a program is infected is equivalent to the halting problem in Turing's Theorem.
Here is an example of a comment about how difficult it is to detect a polymorphic virus (From McAfee):

The DAME, or Dark Avenger Mutating Engine, was submitted in February, 1992. DAME is not actually a virus itself, but rather a polymorphic encryption engine which is used as part of the viruses indicated in this entry. The encryption produced by the encryption engine is extremely complex, with no more than three bytes remaining constant within replicated samples. As a result, viruses encrypted with this engine can only be identified by the presence of the encryption engine itself.
The problem with 3 bytes remaining in the signature is that the odds become very large for a false alarm.  If you have a random stream of bytes, you are virtually assured that after 16 MB, you'll see the three bytes.  Modern disk drives are three orders of magnitude larger than this.
 

What does a polymorphic virus look like?

Consider the following code fragment of a "normal" virus.  This virus resets a controller and then reboots the PC, which is pretty innocuous as these things go.  Here is the code
00001                                           # reboot.s
00002                                           #
00003                                           # An assembly language program t
o reset the hard drive controller and then reboot a PC
00004
00005 0000           8816       0080                    mov 0x80,dl
00006 0004           8826       000D                    mov 0x0d,ah
00007 0008           CD                     13          int 0x13
00008 000A           CD                     19          int 0x19
00009                                                   end
 

The "signature" of this virus is 88 16 00 80 88 26 00 0d cd 13 cd 19, which is 12 bytes long.  Now, if I want to change this by adding NOP instructions, I can.  The virus becomes 88 16 00 80 90 88 26 00 0d 90 90 cd 13 90 90 90 cd 19.  That's relatively simple.  If I want to get more sophisticated, I can add jump instructions and other instructions which really don't do anything.

00001                                           # reboot.s
00002                                           #
00003                                           # An assembly language program t
o reset the hard drive controller and then reboot a PC
00004
00005 0000           EB           10                    jmp L1
00006 0002           90                                 nop
00007 0003           8826       000D            L2:     mov 0x0d,ah
00008 0007           EB           0F                    jmp L3
00009 0009           90                         L4:     nop
00010 000A           90                                 nop
00011 000B           CD                     13          int 0x13
00012 000D           90                                 nop
00013 000E           90                                 nop
00014 000F           90                                 nop
00015 0010           CD                     19          int 0x19
00016                       00000012>           L1:
00017 0012           8816       0080                    mov 0x80,dl
00018 0016           EB           EB                    jmp L2
00019 0018           88FF                       L3:     mov bh,bh
00020 001A           EB           ED                    jmp L4
00021                                                   end
 

This is still the same payload as the original example, but now it looks nothing at all like the original program.  It's signature is eb 10 90 88 26 00 0d eb 0f 90 90 cd 13 90 90 90 cd 19 88 16 00 80 88 ff eb ed and looks very different from the original, but it is still the same payload.
There is some theoretical work about executing code and seeing what it does, but this approach is doomed to failure.  The virus code can sense if the virus scanning program is active, and change its function if it is.  Or the virus code can sense the date and not act until a certain day.  Can you imagine trying to track down a virus that only ran when the minute of the hour was a multiple of 3?  It would do its thing at 12:12 but not at 12:13 or 12:14?

So what are we to do?

There are some things we as an industry can do that just won't work.
  1. User Education.  A lot of the articles about polymorphic viruses are surprisingly old.  For example, I found a paper, http://www.bocklabs.wisc.edu/~janda/polymorf.html, on polymorphic viruses dated Jan 24, 1993.  And all of this time, we have been telling our users to not engage in dangerous computing practices, but they still do.  For example, users keep sending binary files such as executables, word for windows files, Excel spreadsheets, through E-mail.
  2. Better virus scanners.  The problem with this approach is that it is theoretically possible for a virus to detect when a virus detector is running and inactivate itself.
  3. Integrity verification systems. such as tripwire.  An integrity verification system is a program which scans all of the executables in a system, and for each executable, generates a checksum.  From time to time, the integrity verification system recalculates the checksum and generates an exception if the check sum changed.  This feature could even be built into the operating system, so that the integrity of the executable is checked each time the image is activated.  The problem here is that viruses can hide in .dlls, in libraries, or in scripts.  Also, building a standardized mechanism for storing checksums invites viruses which attack that storage mechanism.  Finally, tripwires require a rigorous seperation of read-only code and configuration information, which is the antithesis of design in the MS-Windows and Windows/NT systems.
  4. Better operating systems.  The problem here is that there are better operating systems.  Linux, FreeBSD, OpenBSD, Solaris are all available for the PC platform and all are significantly more secure, cheaper (both software and hardware), reliable, and better performing than MS-Windows.  Although there are worms and viruses for UNIX and Linux, it is a lot harder to infect a UNIX machine than a Windows machine because UNIX was designed from day one to be a multiuser multitasking operating system with security.  Quite frankly, until the market is willing to vote with its dollars, viruses will continue to be a problem.
  5. Firewalls.  The problem with firewalls is that they generally pass E-mail, and viruses propogate through E-mail.  Firewalls are good for other things, however, and no sysadmin worth his or her salt should go without one.
  6. Embrace heterogeneous computing.  Just as humans can't get feline leukemia, and cats don't get AIDS, heterogeneous computing saves us from disaster.  So why did I just submit my three year plan to my management which says that I will become efficient by promoting homogeneous computing solutions built around PCs running Linux?  The problem is that while heterogeneous computing makes life easy for software developers and system administrators, it also makes it easy for hackers and evil doing scum.  A virus for Intel/Linux will have a hard time on a solaris system, especially if its solaris/SPARC.  A virus of Intel/Linux will have a hard time running on Alpha/Linux, or Linux on System/390.  Again, Windows only runs on Intel.  We have to trade that against sysadmin efficientcy and the problems of managing code on multiple platforms.
  7. Better logging of internet traffic.  The problem here is that better logging will generate reams of data, and without tools to analyze those logs, it will swamp an already overworked IS staff.  Further, I can think of few things more boring than pouring over logs.  If we put stateful logging analyzers in place, then we might get a handle on what's going wrong, but then, why not put that state engine in the applications we're logging?
Although none of these alternatives will Fix The Problem, none of them will hurt and all are useful and ought to be done.

Then, there are some ideas which I have not seen in the literature that might be helpful:

  1. Two levels of system privilege.  The ordinary privilege level is for tasks such as user management and configuration changes, but not changing executable images or installing software.  The extraordinary privilege level is for software installation tasks.  The system cannot enter the extraordinary privilege level without making much noise.  So it would not be possible to modify executables easily.
  2. Store executables on read-only file systems.  This is easy, nay, trivial on UNIX machines.  Simply create partitions for /sbin, /bin, and /usr (you might have to symlink /usr/local/etc to /etc or similar). It is more challenging on MS-WIndows (including W2K) machines because the file systems that hold executables also hold read/write storage.  Also, some .DLL files are writable, and programs can store state information there, along with executable code.  This also raises issues with software licensing, which is not much of a problem in the UNIX world but Microsoft gets passionate about that sort of thing.  An executable on a read-only file system is intrinsically secure, so long as the file server itself is not compromised.  The file server could have a minimalist, highly secure operating system.
  3. A wholesale abandonment of MS-Windows.  I know that this sounds like microsoft bashing.  Everybody says that Microsoft builds secure operating systems, and that W2K finally got it right.  But there is more to security than the operating system - security also has to be designed into the applications and the layout of files in file systems.  Microsoft didn't do that, and now they are scrambling with patch after patch after patch.  With Windows/XP, Microsoft is deploying an automated patching tool.  Anybody who has studied Quality using the W. Edwards Deming approach knows that that's not quality, that's putting a band-aid on the problem.  In particular, there are some things Microsoft could do to improve the security of their systems:
  4. Proper staffing levels and competency levels for sysadmins.  One would think that with the .coms that are going .gone, there would be a glut of sysadmins, and this problem would go away.  In general, I don't see that.  What's more, a lot of the sysadmins who are getting laid off have no formal security training and little knowlege of computers beyond their immediate jobs.  They went too high, too fast, and it will take a while before they are useful for anything else.  I advocate that sysadmins ought to have software development backgrounds.  Why?  Because ultimately, they are managing software - they need to know at a gut level what works and what doesn't.  They need to know how to test.  They need to write process documentation.  I am trying to hire people, but I'm not going to hire somebody who has typographical errors on their resume.
  5. One thing that has worked very nicely for me, in a university setting, is hiring high school kids at a slight premium over what McDonald's is paying.  In general, they are anxious to get the training and experience.  That might not work for you.  I also have a lot of concern that I am training the next generation of hackers, so I spend a lot of time talking about the economic and ethical considerations of hacking.
  6. I have some scripts which invoke various Linux based hacker tools.  I run nmap on all of my machines periodically, and note any changes from nominal.  I also run snort from time to time.  These aren't universal panaceas, but, they will, for example, detect an infection of back orofice.
The pattern here is that our current practices aren't working.  We can manage our systems and do the profit-making things we're expected to do if we're constantly patching and repatching in response to directives from SANS.  This is not to say that we should ignore what SANS and CERT tell us, but rather, that we can't get multiple security advisories a week and expect to make progress on other things we're supposed to do.

Conclusions

I described polymorphic viruses, and how they are similar to and different from other viruses.  I explained why polymorphic viruses were so much more dangerous than other viruses.  I described some ideas that I have seen in the literature, and some ideas I have conceived on my own which I would like to see developed.

  © 2001 By Jeff Silverman. At the moment, I am reserving all rights. For permission to reproduce, please E-mail me.


Valid HTML 4.01!
HTML 4.01 transitional validation. see new web server .web server .web server .