从事产品技术支持多年, 我遇见过很多很多的场合, Event Log报错, 我们想要知道这个事件与我们正在排查的问题是如何关联起来的. 在某些情况下, Event Log错误本身就是我们要解决的问题. 所以, 手头上的问题就是如何得到从这个事件发生前一直到这个事件发生其间的网络通讯封包的记录(network trace).
过去, 我们有一个叫做EventMon的工具, 能做到这一点. 它是一个能够开启network trace的简单包装者, 并且还能够监视event log, 从中寻找特定的event. 所以, 这篇blog的目的就是使用NMCap, VBS, 还有CMD Batch wrapper, 来创建出一个相似的工具,
监视 Event Log
===================
WMI(Windows Management Interface)已经暴露出了方法, 允许我们监视Event Log. 这意味着我们能够创建简单的VBS脚本来帮助我们处理这一块. 指导思想是把我们感兴趣的Event Number和Event Log File(application, security, system, etc)传递给脚本, 让脚本运行直到这个event发生. 在我们的例子中, Event Log File这个参数是一个可选参数.
我们的脚本非常简单. 我们简单地为WMI创建一个对象, 这个对象允许我们得到Event Log Notification对象. 我们所查找的Notification Event对象是基于我们传递给脚本的参数的. 通过传递一个简单的类似SQL的查询, 我们缩小了我们寻找的notification的类型的范围. 一旦这个对象被创建, 我们就调用一个方法来等待我们期待的事件的发生. 一旦检测到事件发生了, 这个对象会返回指向特定的event information的点.
这就是我们谜题的第一个部分, EvtMon.VBS
'====================================================================== ' Print out the help when something is not typed in correctly or when ' nothing at all is typed in. Public Sub PrintHelp Wscript.Echo "Usage:" Wscript.Echo " EvtMon EventNumber [LogFileDisplayName]" Wscript.Echo " LogFile is optional. If used, the eventlog name" Wscript.Echo " file ie, application, system, security, etc..." End Sub ' Get the arguments. Check for event nubmer and log file as arugments Set objArgs = WScript.Arguments ' See how many arguments we have and colect them. if objArgs.Count < 1 OR objArgs.Count > 2 Then PrintHelp ElseIf objArgs.Count > 1 Then EventNumber = objArgs(0) LogFile = objArgs(1) Else EventNumber = objArgs(0) LogFile = "" End If If EventNumber <> "" Then strComputer = "." ' Attatch to the WMI Service Set objWMIService = GetObject("winmgmts:{(Security)}\\" & _ strComputer & "\root\cimv2") ' if the LogFile is populated add this to our query. Create a ' Event Log monitoring object and send it a query. If LogFile = "" Then Set colMonitoredEvents = objWMIService.ExecNotificationQuery _ ("Select * from __InstanceCreationEvent Where " _ & "TargetInstance ISA 'Win32_NTLogEvent' " _ & "and TargetInstance.EventCode = '" _ & EventNumber & "'") Else Set colMonitoredEvents = objWMIService.ExecNotificationQuery _ ("Select * from __InstanceCreationEvent Where " _ & "TargetInstance ISA 'Win32_NTLogEvent' " _ & "and TargetInstance.EventCode = '" _ & EventNumber _ & "' and TargetInstance.LogFile = '" _ & LogFile & "'") End If ' Create an object which returns when the next event occurs. Set objLatestEvent = colMonitoredEvents.NextEvent ' Print some info based on the event log we encountered. Wscript.Echo objLatestEvent.TargetInstance.User Wscript.Echo objLatestEvent.TargetInstance.TimeWritten Wscript.Echo objLatestEvent.TargetInstance.Message WScript.Echo objLatestEvent.TargetInstance.Logfile Wscript.Echo End If
用于控制的主CMD: EventMon.CMD
======================
上面的VBS脚本简单地监视对event log的写入. 但是我们还是需要一种方式来开启trace, 还需要再脚本结束的时候结束抓取. 我们将要使用一个能够孵化NMCap的CMD文件, 并且在脚本的结束部分通知NMCap去停止抓取. 我们还在Event Number和Event Log之前多添加了一个参数, 来允许你输入将要创建的抓取封包的文件名.
由于NMCap没有任何方式来直接通知他, 我们将会通过PING命令来产生某种网络通讯的数据包, 通过这个数据包来告诉NMCap来停抓trace.
CMD文件看起来像下面这样:
@echo off if "%1"=="" goto Usage if "%2"=="" goto Usage REM Following line is wrapped start cmd.exe /c nmcap /network * /capture /file %1 /stopwhen /frame "ipv4.DestinationAddress==4.3.2.1" /DisableConversations cscript //NoLogo EvtMon.vbs %2 %3 ping -n 1 4.3.2.1 goto :EOF :Usage echo Usage: echo %0 CaptureFile EventNumber [LogFile] echo Logfile is optional. If used, the eventlog name echo file ie, applicaiton, system, security, etc...
注意, 因为NMCap需要用一点时间来启动, 你最好让命令的执行在调用了NMCap之后sleep一会儿. 这样你就可以保证你在开始监视Event Log之前NMCap处于正常的运行状态.
这还假设NMCap在环境变量的路径中, 或者这个CMD文件运行在NM3的安装目录中. 当然了, 你永远可以为NMCap添加完整路径.
最后, 由于PING命令被用来停止network trace, 你必须保证这条PING命令不会被你的防火墙拦截, 要不然你的NMCap永远不会看到这条traffice. 我选择PING命令是因为通常你的防火墙是不会碰PING命令的, 但是你永远都可以用别的traffic替换PING作为触发器. 当然, 这个技巧就是创建检测那条traffice的filter.
停掉抓取: NMCap是怎么停下来的?
======================
我觉得, 在这样的一个上下文中, 理解NMCap是如何工作的挺重要. 除了验证参数, 这里发生的第一件事儿就是让NMCap带着一大堆参数运行起来. 让我们一起明明白白地过一遍这些参数吧.
第一个, “/network”, 声明我们要在哪块网卡上抓取网络包. 在这个例子里, 我们指定的是 " * ", 也就是所有的网卡都抓. 如果你需要的话, 你可以很容易地缩小范围到一个网卡.
下一个参数是“ /capture /file %1 " 告诉NMCap把什么过滤掉(什么都没过滤, 因为这里在/capture参数之后没有提供给它任何的filter), 还有如何命名抓取trace的结果文件. 文件名来自于传递给CMD批处理文件的第一个参数. 默认的抓取文件的尺寸上限是20兆, 而且是环形缓冲. 你可以修改这个设定为一个更大点的尺寸, 方法是在文件名后添加一个修饰符. 比如说, mystuff.cap:200M, 这会创建两百兆的环形缓冲作为抓取结果文件. 你可以产看NMCap的帮助来获得更多关于NMCap的参数的知识, 方式是输入“NMCap /?”,
参数的最后部分, “/stopwhen" 指令, 让我们确定何时NMCap停止抓取. 所以我们给他一个“/frame”参数, 告诉它寻找一个满足一个filter条件的traffic记录, 找到后停掉抓取并离开NMCap. 我们传给他一个filter, 这个filter寻找以4.3.2.1所谓目的IPv4地址的包. 当VBS脚本结束的时候, CMD文件会PING地址4.3.2.1的. 所以, 就是这个动作引起了抓包动作的结束.
最后, 有一个“/DisableConversations”开关, 它会告诉NMCap忽视掉conversation information. 因为我们的filter并不依赖conversation来正常工作. 我们可以为长时间运行的trace节省内存. 如果conversations启动的话, 我们会永远地保存状态信息, 这就会给长时间运行NMCap抓包的机器带来不利的影响.
译自:
EventMon: Stopping a Capture Based on an EventLog Event