"Vircing" the InVircible: 2. The Self-Checking Capabilities.

2. The Self-Checking Capabilities.

Whenever a virus is suspected, the first thing the user should do
is to boot from an uninfected write-protected system diskette - to
make sure that no virus is present in memory when doing any virus
hunting. Unfortunately, many users forget to do so and immediately
resort to their anti-virus programs, thus letting the virus to
infect those programs. For this reason, most anti-virus products
have the capability to verify their own integrity - to checksum
themselves in order to to determine whether they have been modified,
possibly by a virus, and to warn the user about it.

However, for most anti-virus programs self-checking is some kind
of last-resort fail-safe - just in case the user has accidentally
infected them. Not so with InVircible. It is designed to rely on
its self-checking capabilities and even to use them actively for
virus detection. While the documentation does advise the user to
boot from a clean environment, the author of the product often
brags about how well his product is able to cope with viruses which
are active in memory and how it can even use them for disinfection
purposes. All of this leaves the users of InVircible with the
impression that booting from a clean environment when suspecting a
virus is unimportant and that the product will automatically handle
the problem for them. Let's see whether the product lives up to its
promises.

2.1. Bypassing the Self-Check.

First of all, a virus that is resident and active in memory
presents the danger of hiding itself (using stealth techniques)
from the anti-virus program. Secondly, such a virus can intercept
the file accesses that the anti-virus program makes to inspect the
system. The virus can then use those accesses for spreading itself
on all infectable objects on this system (fast infection).

The programs from the InVircible package claim to be immune to
stealth techniques and fast infection. However, as we shall see in
section 7.1. and 7.2., this is not always the case.

Finally, at least one program from the package does not perform
any self-checking at all. This is the program IVHELP.EXE. This
presents a particularly dangerous security hole, since whenever the
user suspects an infection and attempts to use the product, s/he is
quite likely to invoke the help system, thus allowing the virus to
infect it and to use it to spread itself further.

Why the help system does not perform a self-check is quite clear
to us. It is not developed by the author of the product. It is, in
fact, a popular hypertext browser, known by the name Tech Help! by
Flambeaux Software, Inc. - the same hypertext browser that is used
by Patricia Hoffman's VSUM. Since the folks at Flambeaux Software
specialize in hypertext engines and not in anti-virus software, it
is quite natural that their program does not perform any kind of
self-checking. Obviously, the author of InVircible has decided that
it is much easier to license someone else's hypertext browser,
instead of creating his own. However, the programmer's laziness
cannot be an excuse for the security hole introduced this way,
which exposes the users' data by creating additional risks of a
virus infection.

Next, we found out that it is particularly easy to fool all of the
programs included in InVircible by infecting them with a companion
virus. They are all EXE files and obviously none of them bothers
checking whether or not a COM file with the same name exists in the
current directory. As a matter of comparison, even F-PROT - a
known-virus scanner - is able to detect when it gets infected this
way by a virus - even if this is a virus unknown to the scanner. In
general, InVircible's ineptness to deal with companion infections
is proverbial, as we shall see in section 7.3.

Then, we tried a method that has been discovered by the virus
writers as effective against the self-checking performed by the
popular scanner TbScan and that has been widely publicized in the
underground virus writing magazines. The method consists of
damaging the pointer that points to the full path of the currently
executed program (argv[0] for C programmers or ParamStr(0) for
Turbo Pascal ones). This way, the program is unable to find itself
on the disk. If this happens, some anti-virus programs silently
fail to checksum themselves, without reporting anything to the user.

Sadly, all programs from the InVircible package fall into this
category. We simulated the attack by appending a piece of code to
them (much like a virus) which, at runtime, destroyed the pointer
mentioned above and transferred control to the original entry
point. All programs that were tested this way failed to detect
that they had been modified. As a consequence, this means that the
self-checking capabilities of InVircible will not work by
definition under any DOS version lower than 3.0 - because those DOS
versions do not support the pointer mentioned above. A good
implementation of the self-check is expected to notice that it
cannot find its image on the disk and to notify the user about this.
Obviously, the self-check of InVircible does not belong to this
category.

In fact, the above security hole can be exploited in a much
simpler way by the virus writers. As it turns out, InVircible's
self-checking mechanism does not report anything if any kind of
critical error occurs. It does not even report that the file has
been modified. Remember that when a modification is discovered, the
self-checker attempts to repair the file. Now, if the file has the
ReadOnly attribute set, this "repair" of course fails. As it
happens, this is sufficient to shut up the self-checker. So, a
virus can easily circumvent InVircible's self-checking modules by
simply setting the ReadOnly attribute to the files it infects.
Obviously, the capabilities of a programmer who has written an
anti-virus program that has such a blatant security hole should be
at least questioned.

The next test that we did was to determine what exactly happens
when the program succeeds to determine that it has been modified.
Any good and reasonably modest anti-virus program would display an
alert and would refuse to run. However, the InVircible's opinion
about its capabilities is far from being that modest! Regardless
that a discovered modification of the program probably means that a
virus has infected it and this virus is now active in memory,
InVircible's programs boldly try to repair themselves. Our
experience with self-repairing methods and the advanced techniques
used by the contemporary viruses suggest that often such an attempt
is doomed to fail. However, it wouldn't hurt if, whenever it fails,
it simply informs the user about this and refuses to work further.
But even this is considered as too modest by InVircible. Instead,
the program performs some magic on its image on the disk and
announces that it has successfully restored itself and everything
is fine and dandy.

In order to test this claim, we did the following. The programs in
InVircible are distributed as EXE files compressed with the popular
program LZEXE 0.91 - with some strings that are usually used to
identify this kind of compression mangled with some additional data.
Such mangling did not fool the author of this paper, who is also
the author of an improvement of a program for decompression of
LZEXE-compressed files - UNLZEXE 0.8. The particular improvements
introduced by him were designed exactly to deal with
LZEXE-compressed files whose identification strings have been
damaged somehow. So, it was not a problem to decompress the
compressed executables.

The decompressed files were, of course, different from the
originals. Since no attempts were taken to fool the self-checking
algorithm in this case, the difference was detected immediately by
the program's self-checking module. However, if any self-repairing
module is able to reverse such a modification and to restore the
original (compressed) state of the file, we swore to eat our hat.

Imagine our surprise when InVircible boldly declared that the
program has been restored to its original state and proceeded with
its execution. We were already reaching for our hat, when we
decided to take a look at the "restored" program. Not very
surprisingly, it turned out not to be restored at all - it remained
in its decompressed state. We executed it several times and each
time it declared that it had successfully restored itself (then why
did it keep finding that it has been modified?), and even created a
data file, claiming to contain the "captured" virus that had
"infected" the program. We pity the users who will rely on such a
"reliable" and "honest" self-repairing algorithm.

Another problem of the self-checking mechanism of the product is
that it involves renaming the program that is checking itself to a
file with the same name and with an empty extension (e.g., IVB.EXE
gets renamed to IVB.) and back. If a file with the same name and no
extension already exists - even if it is zero bytes long - the
renaming operation fails. This has the outcome that the
self-checking mechanism simply transfers control to the main
program, without reporting anything to the user, even if the
program has been modified. Clearly, this is yet another way a virus
can use to disable InVircible's self-checking mechanism.

2.2. Damage of the User's Data.

While we were doing those tests, a minor disaster happened. The
author of this paper is a Bulgarian, who is closely affiliated with
the Laboratory of Computer Virology, at the Bulgarian Academy of
Sciences in Sofia. He often sends there software obtained from
different shareware sources, information about viruses, and so on.
To keep track of this information, a record is kept in a text file
named SOFIA in one of the directories on the disk. While we were
examining the programs from InVircible and running them, we
discovered that this file had suddenly disappeared. The DOS command
UNDELETE seemed unable to recover it. While this was annoying, we
always keep good backups and were able to recover the file. At that
time, we decided that we had accidentally deleted it by mistake -
although it didn't seem very likely.

To our surprise, the next time we executed one of InVircible's
programs while the file SOFIA was in the current directory, that
file disappeared again - and again it was not possible to undelete
it. This time we became very suspicious and used a monitoring
program to watch what exactly the programs from InVircible do when
executed. We discovered some very troubling things.

First of all, every single program from the package that performs
a self-check, when started, deletes a file named SOFIA in the
current directory. Second, some of the programs (IVINIT and IVB)
also destroy a file named WRITEST in the root directory of the
current drive. This happens every time those programs are run -
regardless of whether those files exist or not. Since the
self-checking mechanism also involves the creation of some files
(decoy launching), the disk is written to before the program has
terminated. This usually results in UNDELETE being unable to
recover the destroyed files.

We do not know what the author of InVircible has against a file
named after the capital of our native country. Nowhere in the
documentation does he explain why those two files are deleted - and
even does not mention that such a deletion takes place. The
destruction of those files is undoubtedly intentional and the user
is never offered a chance to save them - or even informed about the
intention of the product to destroy them. We were lucky to have
backups, but for some other users this behavior of the product can
easily result in the irreparable lost of precious data. This makes
us classify InVircible as a Trojan Horse destroying data and we
strongly discourage the users from ever using any programs released
by the same author. Indeed, we discovered the very same damaging
code in two other products of his - his infamous AVPL (the product
that creates "emasculated viruses") and the set of utilities
FIXBOOT, SWAPBOOT, and XMONKEY.

When faced with the above facts, the author of InVircible
initially refused to admit them. Then he began to claim that those
are "just temporary files" used by his programs. First of all,
using fixed names for the temporary files - especially so naturally
sounding ones like SOFIA and WRITEST - shows an extremely poor
programming practice. There exists a DOS function call to create a
file with a unique name - it is provided exactly for the purpose to
create temporary files without endangering the user's data. Second,
destroying a file without warning the user or providing him/her
with the option to avoid the destructive action - even for the
purpose to write some temporary data to this file - is another
extremely poor programming practice. Finally, the way that the file
SOFIA is "handled" is a bit suspicious for a "temporary" file.

Indeed, one would expect the program to create a temporary file,
write some data to it, read it back later, close the file and
delete it. This is definitely not what the programs from InVircible
(as well as the other ones released by the same author) do. When
used in a normal, documented way, they simply delete the file SOFIA
in the current directory - without making any other use of it. They
do not open it, do not create it, do not write to or read from it,
they even do not check whether the files exists and whether the
deletion has been successful! They simply delete it.

As we have discovered later, there are some cases when InVircible
creates this file and writes some data to it. If any of the programs
is executed with the string "!@#" as a command line, that program does
not perform its usual task, but instead creates the file SOFIA in the
current directory and writes the following data to it:

        procedure NETZ;
        begin
        Blztc[1] := 23117;
        Blztc[2] := 126;
        Blztc[3] := 100;
        Blztc[4] := 0;
        Blztc[5] := 2;
        Blztc[6] := 10197;
        Blztc[7] := 10197;
        Blztc[8] := 6042;
        Blztc[9] := 128;
        Blztc[10] := 0;
        Blztc[11] := 14;
        Blztc[12] := 3022;
        Blztc[13] := 28;
        Blztc[14] := 0;
        Blztc[15] := 9215;
        end;

The above data is created by IVScan; the other programs create a
similarly looking file - only the numbers are different. Note that
in this mode the file is not deleted after the program exits. This
is definitely an interpretation of the word "temporary" that we were
not aware of.

The meaning of the numbers above is the following. The numbers 1
to 14 are the contents (in decimal) of the EXE header of the
respective program that has generated the file. The part of the
header is from offset 0 to 0x1A and is taken as unsigned two-byte
words. The 15th number is the contents of the EXE header between
offsets 0x21 to 0x22, again taken as a one unsigned two-byte word.
This information might be important to the author of the programs,
but it can easily be generated by an external program and is
definitely not worth sacrificing the user's data.

The cases described above are not the only ones which expose the
user's data to risk. When the decoys are created, the InVircible
does not check whether files with those names already exist. The
probability for this happening is relatively low but is
nevertheless higher than zero. If this happens, the decoy will
destroy the file with the same name in the root directory of drive
C:.

Finally, IVSCAN automatically cuts off some data from the end of
the executable files (see the section describing this program), and
IVINIT performs some aggressive actions on the user's command
interpreter (again, the reader should refer to the section
describing IVINIT).

2.3. The Self-Checking Algorithms Outlined.

Here we shall describe the algorithms that the programs from the
package use to check themselves for infection. In all cases, plain DOS
functions are used, so the operations performed during the self-check
can be easily intercepted even by the simplest memory resident virus.

The programs from InVircible use the following algorithms to detect
whether they have been modified or whether a (possibly stealth) virus
is active in memory.

2.3.1. Algorithm HeaderCheck:

Part A:

1) Open the file containing the program, read 0x1C bytes from it
(the EXE header), check whether the contents of the header is as it
should be, close the file.

2) Open the file again, move to offset 0x21, read the next 2
bytes, check their contents, close the file.

3) Delete a file named SOFIA in the current directory.

Part B:

1) Rename the file containing the program to one with no extension.

2) Open the renamed file, move to the end of the file and check
whether the offset to which we have moved is the same as the
expected original length of the file, close the file.

3) Open the file, read 0x1C bytes from it (the EXE header), check
whether the contents of the header is as it should be (and whether
it is the same as the contents read when executing Part A), close
the file.

4) Rename the file back to its original extension.

The above algorithm will be bypassed by any full-stealth virus
which removes itself from the infected files when those files are
renamed to empty extensions and which re-infects them when they are
renamed back to executable extensions. The algorithm will also be
bypassed by a virus which does not modify the size of the file and
which overwrites the programs after offset 0x21 from the beginning
of the file. Finally, the algorithm will be bypassed by any virus
that conceals its presence in the infected files regardless of
their extension.

2.3.2. Algorithm CheckSum:

1) Open the file containing the program, move to offset 0x1C, read
the checksum of the whole file stored in the next 4 bytes (for
LZEXE-compressed files - as the ones in the InVircible package are
- those 4 bytes normally contain the identifier "LZ91"), close the
file.

2) Open the file again, read the whole file in 4 Kb bites, compute
its checksum and compare it with the one stored in the four bytes
at offset 0x1C.

The above algorithm will be bypassed by any read-stealth virus.

2.3.3. Algorithm DecoyLaunch:

1) Create a file with a random 8-character name and no extension,
write 3 bytes to it, close the file. This is the decoy. The name is
randomly generated from the alphabet 0-9@A-Z.

2) Rename the decoy to a COM extension, execute the decoy.

3) Open the decoy, move to the end of the file, check that the
offset we have moved to corresponds to the expected length of the
file (3 bytes), move back to the beginning of the file, try to read
0x80 bytes from it (of course, only 3 are read), check the contents
of those bytes, write 3 additional bytes to the file, close the
file.

4) Rename the decoy to an empty extension.

5) Open the renamed decoy, move to the end of the file, check that
the offset to which it has moved corresponds to the expected
length of the file (6 bytes), close the file, delete the decoy.

All file opens are in Read-Write mode, so this is likely to
trigger most popular monitoring and access control programs and to
cause false alarms.

It is clear that the above algorithm will be bypassed by a
full-stealth virus which disinfects the files when they are renamed
to empty extensions and infects them back when they are renamed to
have executable extensions. Similarly, a virus which avoids
infecting files with names consisting of exactly 8 characters will
be able to bypass the above algorithm. Also, a virus which does not
infect 3- or 6-byte COM files will not be detected by the above
algorithm. Additionally, a virus which does not infect files with
particular contents (all COM decoys consist of the bytes 0x90,
0xCD, 0x20, 0xCD, 0x19, 0x20) will escape detection by this
algorithm. At last, the above algorithm will not detect a virus
which infects only EXE files. Finally, the algorithm will be
bypassed by any virus that conceals its presence in the infected
files regardless of their extension.

2.3.4. Algorithm AdvancedDecoyLaunch:

1) Create a file with a random name and no extension (the same
name is used as in the algorithm DecoyLaunch), write 8 Kb to it,
close the file. This is the decoy.

2) Rename the decoy to a file with a COM extension, execute it,
and rename it back to an empty extension.

3) Open the decoy, move to the end of the file, check that the
offset we have moved to corresponds to the expected length of the
file (8192 bytes), close the file, delete the decoy.

4) Create another file with the same random name and an EXE
extension, write 516 bytes to it, close the file. This is the new
(EXE) decoy.

5) Execute the decoy.

6) Check whether a file with the same name as the decoy, but with
a COM extension exists. Probably this is a check for a memory
resident fast infecting companion virus.

7) Rename the decoy to a file with no extension.

Cool Open the renamed file, move to the end of the file, check
whether the offset we have moved to corresponds to the expected
length of the file (516 bytes), close the file.

9) Open the file again, read 516 bytes from it and check whether
they are those 516 bytes that were originally written.

The above algorithm will be easily bypassed by:

1) A full-stealth virus that disinfects the infected files when
they are renamed to empty extensions and that reinfects them when
they are renamed to have executable extensions.

2) A full-stealth virus that does not change the size of the
infected files. In fact, the virus has to conceal its presence only
in the EXE files, since the COM decoys are never checksummed.

3) A virus which avoids to infect files with names that consist of
exactly 8 characters.

4) A virus that avoids infecting files with the contents of the
decoys This contents is always one and the same - for instance, the
8 Kb COM decoy consists of the bytes 0xE9, 0x01, 0x00, 0x90, 0xC3
and then the byte 0x90, repeated 8187 times.

5) A virus which does not infect 8 Kb COM and 516-byte EXE files.

6) A virus that conceals its presence in the infected files
regardless of their extension.

2.4. Usage of the Self-Checking Algorithms by InVircible's Programs.

The different programs from InVircible use the above algorithms in
the following way:

IVB: HeaderCheck, destroy the file WRITEST, CheckSum, DecoyLaunch.

IVSCAN: HeaderCheck, DecoyLaunch, CheckSum.

IVTEST: HeaderCheck, DecoyLaunch, AdvancedDecoyLaunch.

IVX, IVLOGIN, INSTALL: HeaderCheck.

IVMENU, RESQDISK, FIXBOOT, SWAPBOOT, XMONKEY, AVPL: HeaderCheck,
CheckSum, DecoyLaunch.

IVINIT: HeaderCheck (Part A), InterpreterCheck, CheckSum, check
the MBR and compare it with the contents of the file PART.NTZ,
destroy the file WRITEST, DecoyLaunch, AdvancedDecoyLaunch,
HeaderCheck (Part B), check the boot sector and compare it with the
contents of the file BOOT.NTZ, check the CMOS and compare it with
the contents of the file CMOS.NTZ.

Note that some programs (INSTALL, IVTEST, IVX, IVLOGIN) do not
checksum themselves, some programs (IVX, IVLOGIN) perform only a
header check, and one program (IVHELP) does not perform any
self-checking whatsoever. The algorithm InterpreterCheck is used
only by IVINIT and will be described later.

2.5. Summary.

All in all, the means that InVircible uses to detect whether some
of its programs have been modified or whether there is an active
virus in memory are patchy, inconsistent, and trivial to bypass
once the virus writers know how they work. The latter is especially
trivial to achieve, since the programs use no anti-debugging
techniques. They use nothing that attempts to make their analysis
and disassembly (or even decompilation back to Turbo Pascal)
difficult. Also, they use plain DOS functions (instead of advanced
tunnelling like, for instance, TbScan or VDS) which are trivial to
intercept and analyze. Additionally, none of the programs checks
whether a companion virus has infected it - something that, for
instance, F-PROT does. Finally, a well-designed advanced
full-stealth virus like Dir_II will be able to both infect the
programs unnoticeably and hide its presence - as our tests have
demonstrated (see section 2.6). Furthermore, those self-checking
techniques are extremely aggressive, are likely to cause conflicts
with any other anti-virus software of the behavior blocker type,
and, as we have demonstrated, sometimes intentionally destroy the
user's data (see section 2.2).

2.6. Testing the Self-Checking Algorithms with Real Viruses.

We used the following known viruses to demonstrate that the
self-checking techniques that InVircible uses should not be relied
upon. Each particular virus illustrates a different method to
bypass those techniques. Many other viruses exist that bypass the
product in the same way and a practically unlimited number of
viruses could be written that would bypass it using those
techniques.

First, we infected several of InVircible's programs with a simple
companion virus - merely AIDS_II. The infection went undetected by
any of the programs of the package, even after booting from the
rescue diskette.

Second, we used a full-stealth virus - Tremor.A - which removes
itself from the infected files if it senses that an attempt is made
to locate the virus body in them. The infection went undetected by
any programs of the package. Furthermore, while we were testing IVB
and IVSCAN, the virus infected some of the files opened by those
programs, without InVircible detecting that a virus was using it to
spread further. It is not particularly clear to us why this was not
detected by the programs in question. When we booted the machine
from the infected disk, the integrity checker (IVB) crashed, thus
making the disk non-bootable (because the program is invoked during
the booting process from AUTOEXEC.BAT). Only after booting from a
clean floppy and running a clean copy of the integrity checker, did
it succeed to detect that some files on the hard disk had been
modified.

We would like to emphasize that this (booting from a
write-protected, uninfected system diskette and running a known
clean copy of the anti-virus program) is the only secure way to
look for viruses. The users must not rely on any self-checking
techniques used by the anti-virus program, regardless how loudly
those techniques are boasted about by the program's author. They
are simply too unreliable.

Next, we used a very advanced stealth virus - Dir_II.T. The level
of stealth used by this virus completely bypasses all checks
performed by any of the InVircible's programs and the virus was not
detected by any of them. Obviously, the author of the package is
aware of the serious problem that such a level of stealth poses to
his package, because almost all programs from the package are
designed to perform a known-virus scan of the memory for this virus
(Dir_II) and another one (Necropolis). However, there are many
variants of the virus that are not detected by this scan, so it was
easy for us to pick one that went undetected and used the disk
access performed by InVircible's programs to spread itself like a
wildfire on the whole hard disk. While the known-virus memory scan
performed by the programs from the package could be improved to
detect other variants of this virus, our tests clearly show that
the generic anti-virus techniques employed by the package are
completely unable to handle stealth viruses of this type.

Finally, we infected one of InVircible's programs with a simple
overwriting virus - Trivial.30.A. When the infected program was
executed, it not only failed to detect that it was infected, but
also let the virus infect all other files in the same directory.