深入挖掘Windows脚本技术2
【脚本也有GUI】虽然系统提供了WScript和CScript两个脚本宿主,分别负责窗口环境和命令行环境下的脚本运行,但实际上窗口环境下用户与脚本交互不太方便:参数输入只能建立快捷方式或弹出InputBox对话框,输出信息后只有在用户“确定”后才能继续运行。完全没有了窗口环境直观、快捷的优势。好在有前面提到的InternetExplorer对象,脚本可以提供web风格的GUI。还是来看个例子,一个清除系统日志的脚本,顺便复习一下WMI:
set ie=wscript.createobject("internetexplorer.application","event_") '创建ie对象'ie.menubar=0 '取消菜单栏'ie.addressbar=0 '取消地址栏'ie.toolbar=0 '取消工具栏'ie.statusbar=0 '取消状态栏'ie.width=400 '宽400'ie.height=400 '高400'ie.resizable=0 '不允许用户改变窗口大小'ie.navigate "about:blank" '打开空白页面'ie.left=fix((ie.document.parentwindow.screen.availwidth-ie.width)/2) '水平居中'ie.top=fix((ie.document.parentwindow.screen.availheight-ie.height)/2) '垂直居中'ie.visible=1 '窗口可见'
with ie.document '以下调用document.write方法,'.write "<html><body bgcolor=#dddddd scroll=no>" '写一段html到ie窗口中。'.write "<h2 align=center>远程清除系统日志</h2><br>".write "<p>目标IP:<input id=ip type=text size=15>" '也可以用navigate方法直接打开一'.write "<p>用户名:<input id=user type=text size=30>" '个html文件,效果是一样的。'.write "<p>密码: <input id=pass type=password size=30>".write "<p align=center>类型:" '不仅是input对象,所有DHTML支持'.write "<input id=app type=checkbox>应用程序 " '的对象及其属性、方法都可以使用。'.write "<input id=sys type=checkbox>系统 ".write "<input id=sec type=checkbox>安全" '访问这些对象的办法和网页中访问'.write "<p align=center><br>" '框架内对象是类似的。'.write "<input id=confirm type=button value=确定> ".write "<input id=cancel type=button value=取消>".write "</body></html>"end with
dim wmi '显式定义一个全局变量'set wnd=ie.document.parentwindow '设置wnd为窗口对象'set id=ie.document.all '设置id为document中全部对象的集合'id.confirm.onclick=getref("confirm") '设置点击"确定"按钮时的处理函数'id.cancel.onclick=getref("cancel") '设置点击"取消"按钮时的处理函数'
do while true '由于ie对象支持事件,所以相应的,'wscript.sleep 200 '脚本以无限循环来等待各种事件。'loop
sub event_onquit 'ie退出事件处理过程'wscript.quit '当ie退出时,脚本也退出'end sub
sub cancel '"取消"事件处理过程'ie.quit '调用ie的quit方法,关闭IE窗口'end sub '随后会触发event_onquit,于是脚本也退出了'
sub confirm '"确定"事件处理过程,这是关键'with idif .ip.value="" then .ip.value="." '空ip值则默认是对本地操作'if not (.app.checked or .sys.checked or .sec.checked) then 'app等都是checkbox,通过检测其checked' wnd.alert("至少选择一种日志") '属性,来判断是否被选中。' exit subend ifset lct=createobject("wbemscripting.swbemlocator") '创建服务器定位对象'on error resume next '使脚本宿主忽略非致命错误'set wmi=lct.connectserver(.ip.value,"root/cimv2",.user.value,.pass.value) '连接到root/cimv2名字空间'if err.number then '自己捕捉错误并处理' wnd.alert("连接WMI服务器失败") '这里只是简单的显示“失败”' err.clear on error goto 0 '仍然让脚本宿主处理全部错误' exit subend ifif .app.checked then clearlog "application" '清除每种选中的日志'if .sys.checked then clearlog "system"if .sec.checked then clearlog "security" '注意,在XP下有限制,不能清除安全日志'wnd.alert("日志已清除")end withend sub
sub clearlog(name)wql="select * from Win32_NTEventLogFile where logfilename='"&name&"'"set logs=wmi.execquery(wql) '注意,logs的成员不是每条日志,'for each l in logs '而是指定日志的文件对象。' if l.cleareventlog() then wnd.alert("清除日志"&name&"时出错!") ie.quit wscript.quit end ifnextend sub
总结一下整个过程。首先是创建internetexplorer.application对象。其直接的效果是启动了一个iexplorer进程,但窗口是不可见的,直到设置了ie.visible=1。然后用document.write方法将html语句写到ie窗口中。对于复杂的界面,可以将html代码保存为一个html文件,用ie.navigate(filename)打开。最后是响应窗口中的输入。这基本上属于DHTML的知识范畴。
与一般脚本编程最大的不同之处,在于ie是事件驱动的。你所要做的,就是设置好相应的事件处理函数/过程。在本例中,脚本只关心3个事件:ie退出,"确定"按钮被点击,"取消"按钮被点击。
注意,例子中只有两句设置事件处理过程的语句,没有定义ie退出事件与event_onquit过程关联。这是因为这里用到一个特性——创建ie对象时的第二个参数"event_"是一个前缀,ie对象的事件处理过程名是该前缀加事件名。所以onquit事件的处理过程默认就是event_onquit。
当点击"确定"按钮后,confirm过程被调用。例子中演示了如何访问ie中的对象,比如ie.document.all.ip.value就是在"目标IP"文本框中的输入。如果选中"应用程序"这个checkbox,那么ie.document.all.app.checked的值是true,否则是false。想调用alert方法,则用ie.document.parentwindow.alert。其他各种ie内对象的访问方法完全是类似的。具体的可以看DHTML相关资料。
有了web界面,交互就变得丰富多彩了。大家可以充分发挥创意。
比如,很多GUI工具(比如流光)启动时,有一个logo页,显示版权等信息。我们用ie对象也可以模拟一个出来:
set ie=wscript.createobject("internetexplorer.application")ie.fullscreen=1ie.width=300ie.height=150ie.navigate "about:blank"ie.left=fix((ie.document.parentwindow.screen.availwidth-ie.width)/2)ie.top=fix((ie.document.parentwindow.screen.availheight-ie.height)/2)ie.document.write "<body bgcolor =skyblue scroll=no><br><br>"&_"<h2 align=center>这是一个Logo</h2></body>"ie.visible=1wscript.sleep 5000ie.quit
上面这段代码执行后,将在屏幕中央显示一个连标题栏和边框都没有的ie窗口,持续5秒。窗口里是蓝底黑字的“这是一个Logo”。
脚本GUI化之后,与用户的交互更直观。像Nmap那样有很多参数的工具,在本地使用时,写一个图形界面的“接口”就一劳永逸了。输出的结果也可以用脚本处理,以更适合阅读的方式显示,就像流光等工具能生成html扫描报告那样。
【反查杀】首先必须说明的是,我完全没有试图挑战杀毒软件杀毒能力的意思。Windows脚本是一种解释性语言,明文保存代码。由于没有经过编译过程,代码的复杂程度远不如可执行程序(exe)。exe做不到的事,没理由指望脚本能做到。不过,正因为脚本的反查杀能力很差,以至于杀毒软件使用的查杀办法也不高级。于是我们就有机可乘了。
先看看常见的反查杀办法:1,字符串或语句的分割/重组。最典型的例子就是将 fso=createobject("scripting.filesystemobject")变成 fso=createobject("script"+"ing.filesyste"+"mobject")这种办法的扩展是用execute语句:execute("fso=crea"+"teobject(""scr"+"ipting.filesy"+"stemobject"")")
2,变量名自动改变。
RandomizeSet Of = CreateObject("Scripting.FileSystemObject")vC = Of.OpenTextFile(WScript.ScriptFullName, 1).ReadallfS = Array("Of", "vC", "fS", "fSC")For fSC = 0 To 3vC = Replace(vC, fS(fSC), Chr((Int(Rnd * 22) + 65)) & Chr((Int(Rnd * 22) + 65)) & Chr((Int(Rnd * 22) + 65)) & Chr((Int(Rnd * 22) + 65)))NextOf.OpenTextFile(WScript.ScriptFullName, 2, 1).Writeline vC
上面这段代码取自爱虫病毒,大家运行一下,就知道是怎么回事了。
3,用官方工具——脚本编码器screnc.exe[5]加密脚本。加密后的脚本能被脚本宿主直接解释。本来这是最好的解决办法,但“枪打出头鸟”,由于加密是可逆的,现在所有的杀毒软件都有解码功能。因此这个办法的效果基本上为零。
第一个办法的有效告诉我们这样一个事实:对脚本病毒的查杀基本上是属于静态的。而且,我发现即使只是改变大小写,也能起到反查效果(只试了一种杀毒软件)。反查杀的关键是减少特征码。
对于exe的反查杀,最容易想到的就是“加壳”。在脚本上也可以应用这个办法。比如:
str="cswpire.tohcO"" ""!K"for i=1 to len(str) step 3rev=rev+strreverse(mid(str,i,3))nextexecute rev
一个最简单的“壳”。“壳”的算法是每n个字符反转顺序一次。n就是算法的“种子”,本例中它等于3。这个“壳”是死的,起不到减少特征码的效果。反而增加了特征码,如"cswpire"。
下面看一个复杂些的例子:
str="wscript.echo ""OK!"":randomize:key=int(rnd*8+2):str=rev:str=replace(str,chr(34),chr(34)+chr(34)):set aso=createobject(""ADODB.Stream""):with aso:.open:.writetext ""str=""+chr(34)+str+chr(34)+"":key=""+cstr(key)+"":str=rev:execute str:function rev():for i=1 to len(str) step key:rev=rev+strreverse(mid(str,i,key)):next:end function"":.savetofile wscript.scriptfullname,2:end with":key=1:str=rev:execute str:function rev():for i=1 to len(str) step key:rev=rev+strreverse(mid(str,i,key)):next:end function
(注意,该代码只有一行,没有回车)保存成vbs文件,双击执行,效果还是和前一段代码一样,弹出一个对话框显示"OK!"。但是,执行完后再看代码,可能变成了这样:
str="tpircsw"" ohce.ar:""!KOezimodnni=yek:8*dnr(trts:)2+ts:ver=alper=r,rts(ec)43(rhc43(rhc,3(rhc+)tes:))4rc=osa jboetaeDA""(tcertS.BDOw:)""maeosa hti:nepo.:tetirw.ts"" txerhc+""=rts+)43(3(rhc+rek:""+)4tsc+""=y+)yek(rr=rts:""cexe:verts etuitcnuf:(ver noi rof:)l ot 1=)rts(nek pets =ver:yerts+veresreverts(dim(yek,i,rtxen:))uf dne:""noitcntevas.:w elifo.tpircsftpircsemanllu dne:2,htiw":key=7:str=rev:execute str:function rev():for i=1 to len(str) step key:rev=rev+strreverse(mid(str,i,key)):next:end function
再执行,又变成其他样子了。这个脚本是自变形的。
如果仔细看代码就会发现,“壳”的算法依旧,而“种子”随机改变。但是,加壳过的内容每次不同了,“壳”本身还是没有任何改变。很多exe加壳工具加的壳,本身就被当作恶意代码来提取特征码。为了更好的反查杀,脚本的“壳”也需要动态改变。这就要用到所谓的多态技术。不过,exe的多态是用来反动态查杀的,而脚本的“多态”只是应付静态查杀,两者有很大不同。
对于exe,真正的多态目前还未听说被实现的。脚本也只能做多少算多少。不影响功能的变形方法,除了上面提到的3种,还有:1,随机改变大小写;2,冒号(:)与回车符随机互换(字符串内和"then"之后的冒号除外);3,字符串分割时,"+"与"&"随机互换;4,()+-*/&,等字符两边任意添加空格或续行符(_)和回车符的组合;5,用自定义函数替换内置函数;即使自定义的函数只是简单的封装内置函数,但至少改变了关键字的位置。…………还有其他“多态”算法有待你的研究。
这些算法的应用,是以大幅增加代码长度为前提的。如果想写一个比较完美的“壳”,相信会涉及到“文法分析”的知识,因为脚本要“读懂”自己,从而达到类似Java混淆器的效果,这就很复杂了,有机会再和大家探讨。下面我们应用“语句分割”、“变量名自动改变”、“随机大小写”、“+和&互换”四种方法,看一下效果如何:
A001="wscript.echo ""OK!"":A004=chr(34):randomize:A005=int(rnd*24000+40960):A001=A006(A001):A000=A005 mod 10+2:A001=replace(A002,A004,A004&A004):set A007=createobject(""ADODB.Stream""):A007.open:A007.writetext hex(A005+1)&""=""&A004&A001&A004&A008("":execute ""&A004&A006(""A000=""&A000&"":A001=A002:execute A001:function A002():for A003=1 to len(A001) step A000:A002=A002+strreverse(mid(A001,A003,A000)):next:end function"")&A004):A007.savetofile wscript.scriptfullname,2:function A006(A009):for A00A=0 to 12:A009=replace(A009,hex(&HA000+A00A),hex(A005+A00A)):next:A006=A009:end function:function A008(A009):for A00A=1 to len(A009):A00B=mid(A009,A00A,1):if int(rnd*2-1) then A00B=ucase(A00B):end if:if A00A>11 and int(rnd*5)=0 then A008=A008&A004&chr(38+int(rnd*2)*5)&A004:end if:A008=A008&A00B:next:end function":A000=1:A001=A002:execute A001:function A002():for A003=1 to len(A001) step A000:A002=A002+strreverse(mid(A001,A003,A000)):next:end function
- 联系我们: QQ:82526114(技术) 411523648(客服) 237057746(财务)
- 电话:+86-762-4372098 邮箱:webmaster@814e.net,support@814e.net
- 粤ICP备05002242号 网监局备案:4403701910502
