IT学习者 | 文章大全 | 技术文档 | 桌面壁纸 | 实用查询 | 网络电台 | 成语 | 歇后语 | 网址 | 下载 | 周公解梦 | 生日密码 | 电视剧365 | Flash
 您现在的位置: IT学习者 >> 文章大全 >> 网页制作 >> 网页特效代码

深入挖掘Windows脚本技术

【 来源:网络  更新时间:2008-2-27 | 字体:

【目录】

1,前言

2,回顾WSH对象

3,WMI服务

4,脚本也有GUI

5,反查杀

6,来做个后门

7,结语

8,参考资料

【前言】

本文讲述一些Windows脚本编程的知识和技巧。这里的Windows脚本是指"Windows Script Host"(WSH Windows脚本宿主),而不是HTML或ASP中的脚本。前者由Wscript或Cscript解释,后两者分别由IE和IIS负责解释。描述的语言是VBScript。本文假设读者有一定的Windows脚本编程的基础。如果你对此还不了解,请先学习《Windows脚本技术》[1]。

【回顾WSH对象】

得益于com技术的支持,WSH能提供比批处理(.bat)更强大的功能。说白了,wsh不过是调用现成的“控件”作为一个对象,用对象的属性和方法实现目的。

常用的对象有:

WScript

Windows脚本宿主对象模型的根对象,要使用WSH自然离不开它。它提供多个子对象,比如WScript.Arguments和WScript.Shell。前者提供对整个命令行参数集的访问,后者可以运行程序、操纵注册表内容、创建快捷方式或访问系统文件夹。

Scripting.FileSystemObject

主要为IIS设计的对象,访问文件系统。这个恐怕是大家遇到最多的对象了,因为几乎所有的Windows脚本病毒都要通过它复制自己感染别人。

ADODB.Stream

ActiveX Data Objects数据库的子对象,提供流方式访问文件的功能。这虽然属于数据库的一部分,但感谢微软,ADO是系统自带的。

Microsoft.XMLHTTP

为支持XML而设计的对象,通过http协议访问网络。常用于跨站脚本执行漏洞和SQL injection。

还有很多不常见的:

活动目录服务接口(ADSI)相关对象 —— 功能涉及范围很广,主要用于Windows域管理。

InternetExplorer对象 —— 做IE能做的各种事。

Word,Excel,Outlook对象 —— 用来处理word文档,excel表单和邮件。

WBEM对象 —— WBEM即Web-Based Enterprise Management。它为管理Windows提供强大的功能支持。下一节提到的WMI服务提供该对象的接口。

很显然,WSH可以利用的对象远远不止这些。本文挂一漏万,谈一些较实用的对象及其用法。

先看一个支持断点续传下载web资源的例子,它用到了上面说的4个常用对象。

if (lcase(right(wscript.fullname,11))="wscript.exe") then      '判断脚本宿主的名称'

   die("Script host must be CScript.exe.")                     '脚本宿主不是CScript,于是就die了'

end if

if wscript.arguments.count<1 then                              '至少要有一个参数'

   die("Usage: cscript webdl.vbs url [filename]")              '麻雀虽小五脏俱全,Usage不能忘'

end if

url=wscript.arguments(0)                                       '参数数组下标从0开始'

if url="" then die("URL can't be null.")                       '敢唬我,空url可不行'

if wscript.arguments.count>1 then                              '先判断参数个数是否大于1'

   filename=wscript.arguments(1)                               '再访问第二个参数'

else                                                           '如果没有给出文件名,就从url中获得'

   t=instrrev(url,"/")                                         '获得最后一个"/"的位置'

   if t=0 or t=len(url) then die("Can not get filename to save.")    '没有"/"或以"/"结尾'

   filename=right(url,len(url)-t)                              '获得要保存的文件名'

end if

if not left(url,7)="http://"&url            '如果粗心把“http://”忘了,加上'

set fso=wscript.createobject("Scripting.FileSystemObject")     'FSO,ASO,HTTP三个对象一个都不能少'

set aso=wscript.createobject("ADODB.Stream")

set http=wscript.createobject("Microsoft.XMLHTTP")

if fso.fileexists(filename) then                               '判断要下载的文件是否已经存在'

   start=fso.getfile(filename).size                            '存在,以当前文件大小作为开始位置'

else

   start=0                                                     '不存在,一切从零开始'

   fso.createtextfile(filename).close                          '新建文件'

end if

wscript.stdout.write "Connectting..."                          '好戏刚刚开始'

current=start                                                  '当前位置即开始位置'

do

   http.open "GET",url,true                                    '这里用异步方式调用HTTP'

   http.setrequestheader "Range","bytes="&start&"-"&cstr(start+20480) '断点续传的奥秘就在这里'

   http.setrequestheader "Content-Type:","application/octet-stream"

   http.send                                                   '构造完数据包就开始发送'

   for i=1 to 120                                              '循环等待'

      if http.readystate=3 then showplan()                     '状态3表示开始接收数据,显示进度'

      if http.readystate=4 then exit for                       '状态4表示数据接受完成'

      wscript.sleep 500                                        '等待500ms'

   next

   if not http.readystate=4 then die("Timeout.")               '1分钟还没下完20k?超时!'

   if http.status>299 then die("Error: "&http.status&" "&http.statustext) '不是吧,又出错?'

   if not http.status=206 then die("Server Not Support Partial Content.") '服务器不支持断点续传'

   aso.type=1                                                  '数据流类型设为字节'

   aso.open

   aso.loadfromfile filename                                   '打开文件'

   aso.position=start                                          '设置文件指针初始位置'

   aso.write http.responsebody                                 '写入数据'

   aso.savetofile filename,2                                   '覆盖保存'

   aso.close

   range=http.getresponseheader("Content-Range")               '获得http头中的"Content-Range"'

   if range="" then die("Can not get range.")                  '没有它就不知道下载完了没有'

   temp=mid(range,instr(range,"-")+1)                          'Content-Range是类似123-456/789的样子'

   current=clng(left(temp,instr(temp,"/")-1))                  '123是开始位置,456是结束位置'

   total=clng(mid(temp,instr(temp,"/")+1))                     '789是文件总字节数'

   if total-current=1 then exit do                             '结束位置比总大小少1就表示传输完成了'

   start=start+20480                                           '否则再下载20k'

loop while true

wscript.echo chr(13)&"Download ("&total&") Done."              '下载完了,显示总字节数'

function die(msg)                                              '函数名来自Perl内置函数die'

wscript.echo msg                                               '交代遗言^_^'

wscript.quit                                                   '去见马克思了'

end function

function showplan()                                            '显示下载进度'

if i mod 3 = 0 then c="/"                                      '简单的动态效果'

if i mod 3 = 1 then c="-"

if i mod 3 = 2 then c="\"

wscript.stdout.write chr(13)&"Download ("&current&") "&c&chr(8)'13号ASCII码是回到行首,8号是退格'

end function

可以看到,http控件的功能是很强大的。通过对http头的操作,很容易就实现断点续传。例子中只是单线程的,事实上由于http控件支持异步调用和事件,也可以实现多线程下载。在MSDN里有详细的用法。至于断点续传的详细资料,请看RFC2616。

FSO和ASO都可以访问文件,他们有什么区别呢?其实,ASO除了在访问字节(非文本)数据有用外,就没有存在的必要了。如果想把例子中的ASO用FSO来实现,那么写入http.responsebody的时候会出错。反之也不行,ASO无法判断文件是否存在。如果文件不存在,loadfromfile就直接出错,没有改正的机会。当然,可以用on error resume next语句让脚本宿主忽略非致命错误,自己捕捉并处理。但有现成的fileexists()为什么不用呢?

另外,由于FSO经常被脚本病毒和ASP木马利用,所以管理员可能会在注册表中修改该控件的信息,使脚本无法创建FSO。其实执行一个命令regsvr32 /s scrrun.dll就恢复了。即使scrrun.dll被删除,自己复制一个过去就行。

热身完之后,下面我们来看一个功能强大的对象——WBEM(由WMI提供)。

【WMI服务】

先看看MSDN里是怎么描述WMI的——Windows 管理规范 (WMI) 是可伸缩的系统管理结构,它采用一个统一的、基于标准的、可扩展的面向对象接口。我在刚开始理解WMI的时候,总以为WMI是"Windows管理接口"(Interface),呵呵。

再看什么是WMI服务——提供共同的界面和对象模式以便访问有关操作系统、设备、应用程序和服务的管理信息。如果此服务被终止,多数基于Windows的软件将无法正常运行。如果此服务被禁用,任何依赖它的服务将无法启动。

看上去似乎是个很重要的服务。不过,默认情况下并没有服务依赖它,反而是它要依赖RPC和EventLog服务。但它又是时常用到的。我把WMI服务设置为手动启动并停止,使用电脑一段时间,发现WMI服务又启动了。被需要就启动,这是服务设置为“手动”的特点。当我知道WMI提供的管理信息有多庞大后,对WMI服务的自启动就不感到奇怪了。

想直观了解WMI的复杂,可以使用WMITools.exe[2]这个工具。这是一个工具集。使用其中的WMI Object Browser可以看到很多WMI提供的对象,其复杂程度不亚于注册表。更重要的是,WMI还提供动态信息,比如当前进程、服务、用户等。

WMI的逻辑结构是这样的:

首先是WMI使用者,比如脚本(确切的说是脚本宿主)和其他用到WMI接口的应用程序。由WMI使用者访问CIM对象管理器WinMgmt(即WMI服务),后者再访问CIM(公共信息模型Common Information Model)储存库。静态或动态的信息(对象的属性)就保存在CIM库中,同时还存有对象的方法。一些操作,比如启动一个服务,通过执行对象的方法实现。这实际上是通过COM技术调用了各种dll。最后由dll中封装的API完成请求。

WMI是事件驱动的,操作系统、服务、应用程序、设备驱动程序等都可作为事件源,通过COM接口生成事件通知。WinMgmt捕捉到事件,然后刷新CIM库中的动态信息。这也是为什么WMI服务依赖EventLog的原因。

说完概念,我们来看看具体如何操作WMI接口。

下面这个例子的代码来自我写的脚本RTCS。它是远程配置telnet服务的脚本。

这里只列出关键的部分:

首先是创建对象并连接服务器:

set objlocator=createobject("wbemscripting.swbemlocator")

set objswbemservices=objlocator.connectserver(ipaddress,"root\default",username,password)

第一句创建一个服务定位对象,然后第二句用该对象的connectserver方法连接服务器。

除了IP地址、用户名、密码外,还有一个名字空间参数root\default。

就像注册表有根键一样,CIM库也是分类的。用面向对象的术语来描述就叫做“名字空间”(Name Space)。

由于RTCS要处理NTLM认证方式和telnet服务端口,所以需要访问注册表。而操作注册表的对象在root\default。

set objinstance=objswbemservices.get("stdregprov")      '实例化stdregprov对象'

set objmethod=objinstance.methods_("SetDWORDvalue")     'SetDWORDvalue方法本身也是对象'

set objinparam=objmethod.inparameters.spawninstance_()  '实例化输入参数对象'

objinparam.hdefkey=&h80000002                           '根目录是HKLM,代码80000002(16进制)'

objinparam.ssubkeyname="SOFTWARE\Microsoft\TelnetServer\1.0"   '设置子键'

objinparam.svaluename="NTLM"           '设置键值名'

objinparam.uvalue=ntlm                 '设置键值内容,ntlm是变量,由用户输入参数决定'

set objoutparam=objinstance.execmethod_("SetDWORDvalue",objinparam) '执行方法'

然后设置端口

objinparam.svaluename="TelnetPort"

objinparam.uvalue=port                 'port也是由用户输入的参数'

set objoutparam=objinstance.execmethod_("SetDWORDvalue",objinparam)

看到这里你是不是觉得有些头大了呢?又是名字空间,又是类的实例化。我在刚开始学习WMI的时候也觉得很不习惯。记得我的初中老师说过,读书要先把书读厚,再把书读薄。读厚是因为加入了自己的想法,读薄是因为把握要领了。

我们现在就把书读薄。上面的代码可以改为:

set olct=createobject("wbemscripting.swbemlocator")

set oreg=olct.connectserver(ip,"root\default",user,pass).get("stdregprov")

HKLM=&h80000002

out=oreg.setdwordvalue(HKLM,"SOFTWARE\Microsoft\TelnetServer\1.0","NTLM",ntlm)

out=oreg.setdwordvalue(HKLM,"SOFTWARE\Microsoft\TelnetServer\1.0","TelnetPort",port)

现在是不是简单多了?

接着是对telnet服务状态的控制。

set objswbemservices=objlocator.connectserver(ipaddress,"root\cimv2",username,password)

set colinstances=objswbemservices.execquery("select * from win32_service where ")

这次连接的是root\cimv2名字空间。然后采用wql(sql for WMI)搜索tlntsvr服务。熟悉sql语法的一看就知道是在做什么了。这样得到的是一组Win32_Service实例,虽然where语句决定了该组总是只有一个成员。

为简单起见,假设只要切换服务状态。

for each objinstance in colinstances

   if objinstance.started=true then              '根据started属性判断服务是否已经启动'

      intstatus=objinstance.stopservice()        '是,调用stopservice停止服务'

   else

      intstatus=objinstance.startservice()       '否,调用startservice启动服务'

   end if

next

关键的代码就是这些了,其余都是处理输入输出和容错的代码。

总结一下过程:

1,连接服务器和合适的名字空间。

2,用get或execquery方法获得所需对象的一个或一组实例。

3,读写对象的属性,调用对象的方法。

那么,如何知道要连接哪个名字空间,获得哪些对象呢?《WMI技术指南》[3]中分类列出了大量常用的对象。可惜它没有相应的电子书,你只有到书店里找它了。你也可以用WMITools里WMI CIM Studio这个工具的搜索功能,很容易就能找想要的对象。找到对象后,WMI CIM Studio能列出其属性和方法,然后到MSDN里找具体的帮助。而应用举例,除了我写的7个RS系列脚本,还有参考资料[4]。

需要特别说明的是,在参考资料[4]中,连接服务器和名字空间用的是类似如下的语法:

Set objWMIService=GetObject("winmgmts:{impersonationLevel=impersonate}!\\"&strComputer&"\root\cimv2:Win32_Process")

详细的语法在《WMI技术指南》和MSDN中有介绍,但我们不关心它,因为这种办法没有用户名和密码参数。 因此,只有在当前用户在目标系统(含本地)有登陆权限的情况下才能使用。而connectserver如果要本地使用,第一个参数可以是127.0.0.1或者一个点".",第3、4个参数都是空字符串""。

最后,访问WMI还有一个“特权”的问题。如果你看过ROTS的代码,你会发现有两句“奇怪”的语句:

objswbemservices.security_.privileges.add 23,true

objswbemservices.security_.privileges.add 18,true

这是在向WMI服务申请权限。18和23都是权限代号。下面列出一些重要的代号:

5 在域中创建帐户

7 管理审计并查看、保存和清理安全日志

9 加载和卸载设备驱动

10 记录系统时间

11 改变系统时间

18 在本地关机

22 绕过历遍检查

23 允许远程关机

详细信息还是请看《WMI技术指南》或MSDN。

所有特权默认是没有的。我在写RCAS时,因为忘了申请特权11,结果一直测试失败,很久才找到原因。

只要有权限连接WMI服务,总能成功申请到需要的特权。这种特权机制,只是为了约束应用程序的行为,加强系统稳定性。有点奇怪的是,访问注册表却不用申请任何特权。真不知道微软的开发人员是怎么想的,可能是访问注册表太普遍了。

文章共6页,当前在第1页 9 7 [1] [2] [3] [4] [5] [6] 8 :
相 关 文 章
没有相关文章
相 关 软 件
逃生 放生 黄玫瑰 想太多 那滋味 擦肩而过 放手去爱 北京欢迎你 依然在一起 吻得太逼真 感动天感动地 坐上火车去拉萨 怎么会狠心伤害我
心碎 冲动 小太阳 别碰我 蒲公英 千山万水 改变自己 一定要爱你 等爱的玫瑰 陷入爱里面 北极星的眼泪 最后一次的温柔 亲爱的那不是爱情
光荣 火花 坏女人 日不落 樱花草 为你写诗 独家记忆 夏天的味道 寂寞才说爱 忘不掉的伤 爱上你是个错 第三者的第三者 地球人都知道我爱你
假如 相思 是非题 有缘人 舍不得 我的答铃 死而无憾 外滩十八号 越爱越难过 123木头人 和寂寞说分手 爱上你是我的错 爱情里没有谁对谁错
加入收藏留言建议自助友情链接普通友情链接站长的Blog
版权所有   COPYRIGHT 2002-2008 ★IT学习者★ ALL RIGHTS RESERVED.