剑走偏锋--使用WMI获取远程计算机进程程序集中查毒病毒打造内网安全环境

剑走偏锋-使用WMI获取远程计算机进程程序

集中查毒病毒打造内网安全环境

 

作者:高玉涵

时间:2019.04.18 15:45

博客:blog.csdn.net/cg_i

作者背景环境参见:

《由永恒之蓝病毒引发的运维安全思考——网络边界防御篇 》

《非常运维 一体化终端安全管理系统自动安装脚本详解》

 

TMOTWTDI -- Perl名言

真正见功夫的地方不在于代码本身,而在于对平台的理解和驾驭能力,可能这就是俗称的“内功”。-- 高玉涵

我希望不曾写过这个程序--高玉涵

 

引言

信息安全是运维的根本,直接关系到企业的安危,稍有不慎会造成灾难性后果。比如近段时间,世界范围内爆发的“勒索病毒”事件,另外,国内知名门户网站因系统安全漏洞、病毒引发的数据外泄事件等。因此,信息安全体系建设已经被提到了前所未有的高度。如何提升企业的安全防范水准是目前普遍面临的问题。

很高兴在我写这篇文章时,公司内网环境,正全省统一部署“一体化”终端安全管理系统(简称:管理系统)。这套系统是一整套的内网安全管理解决方案,部署后将彻底解决,我一直苦恼的内网安全问题,提高内网抵御各种风险的能力,我想同样管理着上百台“裸奔”系统机器,并深受其害的同行,应该倍感鼓舞吧!

迫于硬件配置太低,我所在单位内网终端设备(硬件配置:Atom D2560 CPU2.0GHzDDR2 2G内存、STAT2 160G硬盘、Windows XP Embedded (XPe) 32位)安装管理系统后,业务办理过程中,卡顿感明显(欣慰的是,总部已经意识到这些问题,正差手解决中),身为系统管理人员,在系统安全可控的前提下(《由永恒之蓝病毒引发的运维安全思考——网络边界防御篇 》文中简单介绍了,笔者在系统“祼奔”状态下,做的一些系统控制,防范系统安全的一些尝试,方法还是较为原始),确保各项业务正常办理是首要职责,无奈之下只好“壮士断腕”将防病毒模块卸载(防病毒模块资源占用较大、策略较为严格,会拦截业务系统调用的一些插件,导致某些业务无法理)

显而易见“自己感冒了都会害怕,传染给电脑呢?”没有防病毒模块的保护,系统安全根本无从谈起。在等待总部给出最终解决方案之前,现有系统控制措施依然有效,安全依然可控。能否在这段过度期间,提高内网系统抵御病毒能力,做到全网范围内,某台终端设备中毒,早发现、早查杀,将风险与损失降到最低?

本文主要讲述,通过Windows管理规范(Windows Management Instrumentation,WMI)技术,实现集中式的病毒扫描机制的方法。显然,WMI是一个庞大的话题,用几本书的篇幅也讲不完,因此,我只能在本文中给出最简短的概览、设计思路、示例代码,同时与大家分享。希望,对你的工作有所帮助,起到举一反三的效果。

 

集中查毒设计思路图

剑走偏锋--使用WMI获取远程计算机进程程序集中查毒病毒打造内网安全环境_第1张图片

(图 1 客户端程序与计算机的WMI服务通信)

1一个WMI客户端程序,定期轮询内网所有计算机,获取远程计算机当前系统运行的进程信息,并将进程程序文件,上转至集中查毒服务器。服务器还提供FTP文件服务功能,用于存放待“抽检”的文件,以远程计算机IP地址命名的文件夹内,标识各自所属内网的那台计算机,一但杀毒程序发现病毒,通过文件夹名称,即可定位内网已中毒的计算机,及时了解内网健康情况,达到早发现、早查杀,将风险与损失降到最低的目的。

你可能会问的一些问题

1.SpotCheck.vbs是什么?

我称之为“抽样检查”程序。抽样检查,是从一批产品中随机抽取少量产品(样本) 进行检验,据以判断该批产品是否合格的统计方法和理论。就像我们人需要定期做体验一样,通过设置“抽检”程序定期执行,可及时了解内网健康情况,做出相对应的诊察手段。

2.为什么是进程程序文件?

远程计算机动辄数十GB至数百GB字节的数据,都传到服务器进行查毒是不现实的(也太傻了)。病毒或恶意程序,要保持传染、窃取、破坏等能力,就必须保持“活性”(驻留在系统进程中)。我们只需“抽检”这部份数据即可达到目地。

 

Windows Script Host进行脚本编程

 

在我不长的从业生涯中,学习过数十种计算机语言,学习它们的背景都是因为系统间某些限制或更善长完成特定任务(有些纯粹是因为好奇)。这带来一个好处,让我避免了系统间的限制和兼容问题,根据要执行任务的平台,以它最自然的语言来完成任务。当然这也会带来一些困扰,如,编写代码时各种“方言”会混淆的写在一起。

显然我这个程序主要应用在Windows平台上,程序生命周期定位在“过渡”期内。所以,程序即要充分利用Windows平台提供的强大功能、编写过程也不能太复杂。

VBScript脚本语言来完成此类任务,可以说是再合适不过了。VBScriptMicrosoft自已的脚本语言很容易上手,其实编写之初,我几乎已经忘记这门语言,我从网上下了一份简明教程,通过几个小时的学习,就可以上手编写程序了。

另一方面,它直接可以同Windows对话,例如DLL对象、COM对象、Windows API类库等等,掌握后可以用它完成Windows下所有的工作,而不必通过复杂的编程环境。

 

Windows管理规范(WMI

 

如果你有一台Windows计算机,维护可能是一项令人沮丧的、耗费时间的工作。将这放大数百倍或数千倍。想象一下公司IT经理每天所要面对的事情(我就是这个苦逼的IT经理)。仅仅是记录计算机库存就是很大的一项任务,然后,有频繁的网络设置更改、网络打印机的添加删除、更新应用程序和移动目标共享文件夹,更别提系统崩溃、硬件失效和用户导致的灾难了,将组织的计算机聚集在一起,就像是试图在水中用手握住50个乒乓球。IT工作是进入隔离病房接受一些正式药物治疗的章程票。

摆脱这种错乱的一种方法是,尽可能地避免从一台计算机走到另一台计算机去做更改。在较大的网络中需求更加迫切。WMI则可以帮助减轻维护负担。WMI提供了一种方式来深入查看Windows的内部工作,监视设置并做出修改。WMI伸手触及到Windows操作系统的每个方面,包括设备驱动、系统服务和应用程序。WMI通过网络来工作,因此,运行一个WMI监视程序(或脚本)的计算机可以进入到组织的网上的任何计算机。

 

别急“压轴好戏”就要上场了

 

我知道你们急着想看代码,前面的内容如让你感到无趣或啰嗦,先在此表示歉意。为了保证程序能够正常运行,在这之前,我们还是先看看程序运行后的样子和一些注意事项。

1.程序文件

SpotCheck.vbs主程序文件,log.txt是程序运行后生成的日志文件,内容如下面的样子:

......

GetCurrentProcess():C:\WINDOWS\System32\smss.exe,C:\WINDOWS\system32\csrss.exe,C:\WINDOWS\system32\winlogon.exe,C:\WINDOWS\system32\services.exe,C:\WINDOWS\system32\lsass.exe,C:\WINDOWS\system32\cmd.exe,C:\WINDOWS\system32\ftp.exe,

2019/4/8 15:20:22 remote_assembly_upload_file:Method returned result = 0 Id of new process is 3628

2019/4/8 15:20:23 package_team:Method returned result = 0 Id of new process is 1860

2019/4/8 15:20:23 package_team:Method returned result = 0 Id of new process is 6568

2019/4/8 15:20:24 package_team:Method returned result = 0 Id of new process is 6232

......

可以看出日志中记录了GetCurrentProcess()函数,获取的当前进程运行的所有程序,并给出它们的绝对路径,文件间以逗号分隔,这些就是送去“抽检”的文件。

日志文件中还有一些其它信息,它们是程序运行过程中,函数运行状态,有性趣的同学,可通过研究源来代码来了解它们。

1.远程计算机需要做的一些工作

如果远程计算机启用了防火墙,使用netsh firewall set service RemoteAdmin命令,使防火墙允许远程登录。

在工作组网络上WindowsXP系统,要禁用“简单共享”操作如下:1.单击“开始->运行”,输入“gpedit.msc”回车,打开“组策略编辑器”,计算机配置→Windows设置→安全设置→本地策略→安全选项”;2.右边双击“网络访问:本地帐户的共享和安全模式”打开其属性对话框,更改成“经典_本地用户以自己的身份验证”选项。

 

SpotCheck程序示例源码

'***********************************************************************************
'*
'* File:        SpotCheck.vbs
'* Author:      高玉涵
'* Blog:        blog.csdn.net/cg_i
'* Created:     2019/4/6
'* Last Modified:2019/4/9   
'* Version:     0.1
'* Declaration:
'*              抽样检查程序,通过WMI技术获取远程计算机进程文件,传至指定集中杀毒服务器
'*              根据查杀结果了解内网计算机健康情况,做出相对应的诊察手段。
'***********************************************************************************
Option Explicit

'BUG = 1,显示错误信息;
public const BUG = 1
public const output_log_file = "log.txt"
public const ForReading = 1, ForWriting = 2, ForAppending = 8
public locator,svcs
dim computer
dim username
dim password

computer = "192.168.0.x"
username = "你的用户名"
password = "你的密码"

'----------------------------------------------------------------------
' Author:	高玉涵
' Created:  2016/8/16
' Version:  0.1
' Name:		output_log
' Declare:  写日志
' parameter:
'           strFileName  文件名
'           strMsg       信息
'           mode:
'           ForReading = 1, ForWriting = 2, ForAppending = 8
'----------------------------------------------------------------------
Sub output_log(strFileName,mode,strMsg)
	Dim fso,file,stream
	
	Set fso = CreateObject("Scripting.FileSystemObject")
	Set stream = fso.OpenTextFile(strFileName,mode,True)

	stream.WriteLine(Now & vbTab & strMsg & vbcrlf)
	stream.close
End Sub 
'----------------------------------------------------------------------
' Author:	高玉涵
' Created:  2019/4/6
' Version:  0.1
' Name:		manage
' Declare:  管理计算机
' parameter:
'           computername 计算机名或IP
'           username     用户名
'           password     密码
' return:   True,False
'----------------------------------------------------------------------
function manage(computername, username, password)
	set locator = CreateObject("WbemScripting.SWbemLocator")

	on error resume next

	set svcs = locator.ConnectServer(computername, "root\CIMV2", username, password)
	
	if err <> 0 then
		if BUG then WScript.Echo "manage():" & Err.Description, "0x" & Hex(Err.Number)
		output_log output_log_file, ForAppending, "manage():" & Err.Description, "0x" & Hex(Err.Number)

		manage = False
		exit function
	end if
	manage = True
end function
'----------------------------------------------------------------------
' Author:	高玉涵
' Created:  2019/4/6
' Version:  0.1
' Name:		GetCurrentProcess
' Declare:  获取当前系统进程
' parameter:
'           svcs         计算机SWbemServices对象
' return:   成功,返回每个进程执行路径字符串,以逗号分隔。失败,为空
'----------------------------------------------------------------------
function GetCurrentProcess(svcs)
	Const wbemFlagReturnImmediately = &h10
	Const wbemFlagForwardOnly = &h20
	dim processes,process,strTmp

	on error resume next

	set processes = svcs.ExecQuery("SELECT * FROM Win32_Process", "WQL", _
                                          wbemFlagReturnImmediately + wbemFlagForwardOnly)
	for each process in processes
		if process.ExecutablePath <> vbEmpty and process.ExecutablePath <> "" then strTmp = strTmp & process.ExecutablePath & ","
	next

	if err <> 0 then
		if BUG then WScript.Echo "GetCurrentProcess():" & Err.Description, "0x" & Hex(Err.Number)
		output_log output_log_file, ForAppending, "GetCurrentProcess():" & Err.Description, "0x" & Hex(Err.Number)

		GetCurrentProcess = Nothing
		exit function
	end if
	
	GetCurrentProcess = strTmp
end function
'----------------------------------------------------------------------
' Author:	高玉涵
' Created:  2019/4/7
' Version:  0.1
' Name:		remote_assembly_upload_file
' Declare:  远程组装上转文件
' parameter:
'           svcs                 	计算机SWbemServices对象
'           ftp_command_template	FTP命令模板 
'           ftp_command_file		组装到的远程目标文件(全路径)
' return:   成功,TRUE 失败,FALSE
'----------------------------------------------------------------------
function remote_assembly_upload_file(svcs,ftp_command_template,ftp_command_file)
	dim result,process,processid,packages,pack

	on error resume next

	set process = svcs.Get("Win32_Process")
	
	result = process.Create("cmd /c echo.>" & ftp_command_file, null, null, processid)
	output_log output_log_file, ForAppending, "remote_assembly_upload_file:Method returned result = " & result & " " & "Id of new process is " & processid
	packages = split(ftp_command_template, vbcrlf)

	for each pack in packages
		if not package_team(svcs, pack, ftp_command_file) then
			exit for
		end if
	next

	if err <> 0 then
		if BUG then WScript.Echo "remote_assembly_upload_file():" & Err.Description, "0x" & Hex(Err.Number)
		output_log output_log_file, ForAppending, "remote_assembly_upload_file():" & Err.Description, "0x" & Hex(Err.Number)

		remote_assembly_upload_file = False
		exit function
	end if
	remote_assembly_upload_file = True
end function
'----------------------------------------------------------------------
' Author:	高玉涵
' Created:  2019/4/7
' Version:  0.1
' Name:		package_team
' Declare:  包装小队 -           remote_assembly_upload_file函数的调用
' parameter:
'           svcs                计算机SWbemServices对象
'           ftp_command_file	组装到的远程目标文件(全路径)
' return:   成功,True 失败,False
'----------------------------------------------------------------------
function package_team(svcs,pack,ftp_command_file)
	dim result,process,processid

	on error resume next

	set process = svcs.Get("Win32_Process")
	
	result = process.Create("cmd /c echo " & pack & ">>" & ftp_command_file,null,null,processid)
	output_log output_log_file, ForAppending, "package_team:Method returned result = " & result & " " & "Id of new process is " & processid

	if err <> 0 then
		if BUG then WScript.Echo "package_team():" & Err.Description, "0x" & Hex(Err.Number)
		output_log output_log_file, ForAppending, "package_team():" & Err.Description, "0x" & Hex(Err.Number)

		package_team = False
		exit function
	end if
	package_team = True
end function
'----------------------------------------------------------------------
' Author:	高玉涵
' Created:  2019/4/8
' Version:  0.1
' Name:		ftp_upload
' Declare:  FTP上转
' parameter:
'           svcs                计算机SWbemServices对象
'           ftp_command_file 	FTP配置文件(全路径)
' return:   成功,True 失败,False
'----------------------------------------------------------------------
function ftp_upload(svcs,ftp_command_file)
	dim result,process,processid

	on error resume next

	set process = svcs.Get("Win32_Process")
	
	result = process.Create("cmd /c ftp -i -s:" & ftp_command_file,null,null,processid)
	output_log output_log_file, ForAppending, "ftp_upload:Method returned result = " & result & " " & "Id of new process is " & processid

	if err <> 0 then
		if BUG then WScript.Echo "ftp_upload():" & Err.Description, "0x" & Hex(Err.Number)
		output_log output_log_file, ForAppending, "ftp_upload():" & Err.Description, "0x" & Hex(Err.Number)

		ftp_upload = False
		exit function
	end if
	ftp_upload = True
end function
'----------------------------------------------------------------------
' Author:	高玉涵
' Created:  2019/4/6
' Version:  0.1
' Name:		IPAddress
' Declare:  获取IP地址
' parameter:
'           svcs        计算机SWbemServices对象
'           ip_prefix   IP前缀
' return:   成功,返回指定前缀的IP。失败,返回NULL
'----------------------------------------------------------------------
function IPAddress(svcs, ip_prefix)
	dim interface,inter,ip,i

	on error resume next
	
	set interface = svcs.InstancesOf("Win32_NetworkAdapterConfiguration")
	
	for each inter in interface
		if not isnull(inter.IPAddress) then
			for each ip in inter.IPAddress
				if instr(ip, ip_prefix) then 
					IPAddress = ip
					exit function
				end if
			next
		end if
	next

	if err <> 0 then
		if BUG then WScript.Echo "IPAddress():" & Err.Description, "0x" & Hex(Err.Number)
		output_log output_log_file, ForAppending, "IPAddress():" & Err.Description, "0x" & Hex(Err.Number)
	end if
	IPAddress = Nothing
 end function
'----------------------------------------------------------------------
' Author:	高玉涵
' Created:  2019/4/6
' Version:  0.1
' Name:		generate_Upload_Template
' Declare:  生成FTP上转模板
' parameter:
'           LocalIPAddress   本地IP
'           arrayProcess     本地进程数组
'           ftp_host         FTP服务器
'           ftp_user         FTP用户名
'           ftp_password     FTP密码
' return:   成功,返回组装后的模板。失败,未知
'----------------------------------------------------------------------
function generate_upload_template(LocalIPAddress,arrayProcess,ftp_host,ftp_user,ftp_password)
	dim template,process

	template = template & "open " & ftp_host & vbcrlf
	template = template & ftp_user & vbcrlf
	template = template & ftp_password & vbcrlf 
	template = template & "mkdir " & LocalIPAddress & vbcrlf
	template = template & "cd " & LocalIPAddress & vbcrlf
	template = template & "BINARY" & vbcrlf

	for each process in arrayProcess
		if not process = " " then
			template = template & "put " & process & vbcrlf
		end if
	next

	generate_Upload_Template = template
end function


dim arrayProcess,LocalIPAddress,template,ftp_command_file,result
ftp_command_file = "c:\\upload.txt"

if manage(computer, username, password) then
	result = GetCurrentProcess(svcs)
	if not result = vbEmpty then
		output_log output_log_file, ForAppending, "GetCurrentProcess():" & result

		arrayProcess = split(result, ",")
		LocalIPAddress = IPAddress(svcs, "192")
		template = generate_Upload_Template(LocalIPAddress,arrayProcess,"192.168.0.x","ftp01","ftp01")
		remote_assembly_upload_file svcs,template,ftp_command_file
		ftp_upload svcs,ftp_command_file
	end if
end if
wscript.echo "exit"




写在最后

 

最后,向和我一样为确保全省IT系统安全,奋斗在基层一线的全体同仁致敬!

不抱怨的世界。

只是别让时间,

消磨了我们心中的火焰......

 

2019/4/9

 

你可能感兴趣的:(Windows技术)