VX Heaven

Library Collection Sources Engines Constructors Simulators Utilities Links Forum

Compatible, Resident Windows 95 Viruses


[Back to index] [Comments]

This article assumes the reader is familiar with articles in VLAD-6 by Quantum and Qark - it would take unnecessary room to cover that ground again.

When I started investigating Windows 95, a shade under a year ago, I decided to make a list of matters I felt were important in any virus running under that pseudo-OS or needed further consideration. The basic list isn't long...

Full Compatability

Compatability is the single most important thing any virus needs. How many old viruses can you name off the top of your head which failed to funtion properly once an undocumented change was made to an undocumented part of it's base operating system? This is what happened with Bizatch and will continue to happen with any virus that does not implement full OS compatability.

Keeping compatability some very important questions arise.

Compatable Function Calling.

Anyone who has read the VLAD-6 articles on Windows 95 will be familiar with this problem.

Quantum's solution was to locate the internal KERNEL32.DLL entry point and call KERNEL32 functions by ordinal. However, a compatability problem arose for him. If a newer version of KERNEL32 was in use or if the ordinal of a function he used was changed his code was rendered unusable, either causing a fault (which Windows 95 should handle) or trashing the run-time and necessitating a reboot.

Unfortunately each time MS releases an update to Win95 this is likely to happen.

How can increase our compatability then? Also, how can we call functions in a different module (ie. not KERNEL32.DLL)?

The answer becomes apparent when a few facts about Win95 are considered.

Hence the method I present in this issue is comprised of the following steps.

Strengths of this approach.

Inherant weaknesses of this approach. If MS should (*shudder*) move KERNEL32.DLL then this approach would meet the same fate as Bizatch.

However this is extremely unlikely for a number of reasons, not the least of which is the fact they'd have to change absolute addresses in other modules :)

You will agree that this approach is much more desirable than previously used approaches. However it is not perfect, since it does still rely on a constant value.

Expect to see a 100compatable approach in the next version of Mr Klunky, hopefully in IR-9 (if I get all the bugs ironed out).

Compatable Residency.

Although using an undocumented method one could probably go resident under w95, taking such an approach would be begging for compatability problems.

So, how do we go resident under Windows 95?

Well, you'll just have to look in the next section (Residency), won't you.

Monitoring File Activity Compatably.

As I said about going resident, you could probably achieve this using an undocumented approach - but probably shouldn't.

Once again, read the "Residency" section for answers to this question.


Residency under Windows 95... and (as we now see) compatable residency at that! but how?

First - what is a TSR virus, really?

Most simply stated it is a type of driver, not (not always anyway) a hardware driver. It's more of a file driver.

So we need to look at device drivers under Windows 95.

The VxD.

VxD stands for "Virtual something Driver" - remember highschool maths? "x" is the unknown quantity ;] A VxD has the LE executable format.

Any w95 device or activity (including AV software, CD ROMs, etc) needs a way of operating at privelage level 0 (ring 0). This way it can have priority to do anything it needs to. In the case of a virus this means intercepting file activity.

If we somehow can load our virus (compatably) as a ring 0 (VxD) process we can do vitually anything.

As soon as we are a ring 0 process we cannot directly use ring 3 (normal program type) functions. We have to do everything through VxD calls. These are in fact int 20h instructions followed by an ordinal identifying which VxD call we are making.

Luckily there are VxD calls that let us do just about anything that can be done in ring 3 - and then some.

When a VxD is it's control dispatch is the key to it's execution. This dispatcher has control passed to it when any of several system events occur. To signify success it RETurns with the carry flag clear, or set on failure. It should default to success for unhandler events.

Events we are concerned with follow.

So that we can do any setting up we need to when the VxD is loaded.

This event only occurs if the device can be dynamically loaded (ie. loaded at any point other than system start).

A virus needs this handler so it can go resident immediately after an infected program is run.

So that we can deinitialise all necessary items when we are manually unloaded.

This event only occurs if the device can be dynamically unloaded (ie. unloaded at any point other than system shutdown).

A virus only needs this at the debugging level. One would not normally want their virus to be trivially unloadable.

So that we can initialise anything we need when the system finishes booting.

A virus that inserted itself into the w95 boot sequence will need this handler so that it can be properly installed in memory at the end of system boot.

So that we can deinitialise all necessary items when the system shuts down.

A virus needs this handler so that it can let '95 shut down without generating errors (and thus signalling the user that something is wrong).

Once we are loaded into ring 0 we need to monitor file activity.

Monitoring File Access.

A VxD call named "IFSMgr_InstallFileSystemApiHook" lets us insert our own file handler into the File System.

A virus VxD simply uses this function to trap all file processing and filter out the desired items.

The File System (FS) hook needs to follow C calling conventions to remain compatable with the rest of sub-systems. Certain parameters are passed to the FS hook on the stack and these are utilised to determine whether a call should be processed by the VxD.

There are several traps and tricks one needs to take care of, most are learnt by experience. I have included the most important two.

Ring-0/Ring-3 Incompatabilities

I previously mentioned the incompatabilities between ring 0 and ring 3 processes. They simply are not (in normal circumstances) able to use each other's code. For compatability reasons this is COMPLETELY ruled out.

However, here we find ourselves with a situation where we NEED code running at ring 3 (that is, attached to the host PE module) and code running at ring 0 (the file monitoring VxD). How do we resolve (once again in a compatable way) these needs and difficulties?

My approach was to have the code that is patched to the infected program in the VxD file, as data. When the VxD infects a file it writes the PE patch code to the correct position and appends a copy of the VxD to the PE patch code.

In it's turn, when the infected file is run control is passed to the PE patch code. This patch code creates the VxD file on disk and loads into memory as a driver.

This allows two distinctly different ring levels of code to exist in a single module and yet to interact in a compatable fashion.

Boot Sequence

Infecting the Windows 95 startup sequence is almost laughable when a compatable approach has been used. Observing a few step will guarantee, in a tasefully compatable fashion, that our virus will be loaded whenever w95 starts.

Other Concerns

There are a few of matters that concerned me or may concern the reader.

Size is not really a concern on Windows 95 machines for several reasons.
  • There is a 4GB continuous addressing space, with a minimum actual RAM requirement of 8MB.
  • Similaraly hard drive space on machines running '95 tend to be in the GB number range.
  • Available HDD space is never constant on a machine running '95, there is so much swapping inevitably going on.
  • The average user rarely, if ever, sees the size of programs (s)he is running, much less notices changes in those sizes!
How viable is this approach? Well, hopefully I have already answered that ;]

Remember that the example that comes with this is article is not really likely to survive "in the wild" and is purely for study and experimentation.

Loading multiple copies of the VxD.

I did discover something unsettling! Multiple copies of a VxD can be loaded into memory if one of several criteria is not met.

The easy way (which I used) was Device ID numbers.

Each VxD must have either a unique Device ID, or a Device ID set to Undefined_Device_ID.

If the Device ID is Undefined_Device_ID, multiple copies of the VxD could conceivably be loaded simultaneously.

So, I "steal" a device ID which (I believe) is unused.

I have developed a method of preventing multiple-loads while using Undefined_Device_ID, more on that next time.


This issue also includes an example of a virus employing the techniques discussed here.

Shudder in awe at the might of Mr Klunky!

You should find the source and a debug script for MrKlunky.VxD (compiled directly from the source) and for a util (Load-MrK.COM) in this issue.

The next version of Mr Klunky will incorporate the following...

Anyone who wants to yap with me about w95 techniques, approaches or anything virus related (EXCEPT morality) contact me through any IR member.

Goodbye! Enjoy!

And remember - A Smurf a day keeps the doctor away!

[Back to index] [Comments]
By accessing, viewing, downloading or otherwise using this content you agree to be bound by the Terms of Use! aka