杀毒扫描速度优化

Posted

技术标签:

【中文标题】杀毒扫描速度优化【英文标题】:Antivirus scan speed optimization 【发布时间】:2011-03-14 21:16:43 【问题描述】:

我一直在使用 vb.net 开发防病毒软件。病毒扫描程序工作正常,但我正在考虑优化扫描速度的方法(因为大文件需要很长时间)。

我用来检测病毒的算法是通过二进制(转换为十六进制)签名。我想我不必为了查找它是否是病毒而查看整个文件,我认为我应该扫描一个特定的位置和特定数量的字节,而不是扫描整个文件。无论如何,如果有人可以在这个主题上提供任何帮助,请提供帮助。

提前致谢。

顺便说一句,病毒签名来自 clamAv 防病毒软件的十六进制集合...

【问题讨论】:

获得更快的磁盘。取而代之的是,让它对用户不显眼。绝对不要唠叨“看我正在扫描!”动画。 @HansPassant:实际上,到目前为止,它只包含几个标签和两个按钮。我要加快的是扫描过程(搜索文件中的所有字节)。 @Seif:听起来您需要知道文件中要匹配签名的确切位置。 clamAv 不提供此信息吗? @PaulSasik:我是这么想的,但是在解压main.cvd文件并打开main.db文件后,我发现的只是名字和十六进制签名 你没有抓住重点。要更快地从硬盘读取文件,您需要一只旋转速度更快的仓鼠。他们花钱。 永远不要让用户看到读取 1 TB 数据需要多长时间。 【参考方案1】:

这一切都取决于,病毒签名的定义是什么? 我建议您解析可执行文件并仅使用 code-section。 但是多态病毒以加密形式将恶意代码保存在数据部分中。所以我不太确定。 你在使用某种 n-gram 技术吗?或者只是挖掘频繁的十六进制代码? 扫描时间是非常重要的问题! 一旦我编写了一个更健全的命令行,它就能在不到一秒钟的时间内找到一个文件——在一秒钟内感染大量文件。 该技术是frequent opcode mining.

【讨论】:

我正在使用的技术(或者自从我很久以前停止这个项目以来一直在使用的技术)是一种搜索和查找技术。我首先将要扫描的文件转换为十六进制,然后在转换后的十六进制代码中搜索十六进制字符串(从十六进制字符串或签名数组中获得)。我能够在不到一秒的时间内扫描小文件(几 KB),但是搜索更大的文件需要更多时间。 @SeifShawkat :使用 AVL 树来表示您在内存中的文件..可能对您有用。【参考方案2】:

也许您的模式扫描效率低下。我可以使用这样的代码在大约 1/20 秒内扫描 7 MB 文件中的模式。请注意,如果您真的想使用这样的代码,则必须进行更正。当您意识到您没有查看匹配项时,您不能总是将 MatchedLength 设置回 0,但它确实适用于这种特定模式。您必须对模式进行预处理,以便在找不到匹配项时知道要重置的内容,但这不会为算法增加大量时间。我可以努力正确完成算法,但如果您的问题只是关于性能,我现在不会这样做。我只是在证明,如果操作正确,可以快速扫描大文件。

Sub Main(ByVal args As String())
  If args.Length < 1 Then Return
  Dim startTime As Long = Stopwatch.GetTimestamp()
  Dim pattern As Byte()
  pattern = System.Text.Encoding.UTF8.GetBytes("SFMB")
  Dim bufferSize As Integer = 4096
  Using reader As New System.IO.FileStream(args(0), IO.FileMode.Open, _
     Security.AccessControl.FileSystemRights.Read, IO.FileShare.Read, bufferSize, IO.FileOptions.SequentialScan)
     Dim buffer(bufferSize - 1) As Byte
     Dim readLength = reader.Read(buffer, 0, bufferSize)
     Dim matchedLength As Integer = 0
     Dim searchPos As Integer = 0
     Dim fileOffset As Integer = 0
     Do While readLength > 0
        For searchPos = 0 To readLength - 1
           If pattern(matchedLength) = buffer(searchPos) Then
              matchedLength += 1
           Else
              matchedLength = 0
           End If
           If matchedLength = pattern.Length Then
              Console.WriteLine("Found pattern at position 0", fileOffset + searchPos - matchedLength + 1)
              matchedLength = 0
           End If
        Next
        fileOffset += readLength
        readLength = reader.Read(buffer, 0, bufferSize)
     Loop
  End Using
  Dim endTime As Long = Stopwatch.GetTimestamp()
  Console.WriteLine("Search took 0 seconds", (endTime - startTime) / Stopwatch.Frequency)
End Sub

编辑

以下是关于如何一次匹配多个模式的一些想法。这只是我的想法,我还没有尝试编译代码:

创建一个类以包含有关模式状态的信息:

Class PatternInfo
   Public pattern As Byte()
   Public matchedBytes As integer
End Class

声明一个变量来跟踪您需要检查的所有模式,并按模式的第一个字节对它们进行索引以便快速查找:

Dim patternIndex As Dictionary(Of Byte, IEnumerable(Of PatternInfo))

检查当前可能匹配的所有模式,看看下一个字节是否也匹配这些模式;如果没有,请停止在该位置查看该模式:

Dim activePatterns As New LinkedList(Of PatternInfo)
Dim newPatterns As IEnumerable(Of PatternInfo)

For Each activePattern in activePatterns.ToArray
   If activePattern.pattern(matchedBytes) = buffer(searchPos) Then
      activePattern.matchedBytes += 1
      If activePattern.matchedBytes >= activePattern.pattern.Length Then
         Console.WriteLine("Found pattern at position 0", searchPos - matchedBytes + 1)
      End If
   Else
      activePatterns.Remove(activePattern)
   End If
Next

查看当前字节是否看起来像您要搜索的新模式的开始;如果是这样,请将其添加到活动模式列表中:

If patternIndex.TryGetValue(buffer(searchPos), newPatterns) Then
   For Each newPattern in newPatterns
      activePatterns.Add(New PatternInfo() With  _
         .pattern = newPattern.pattern, .matchedBytes = 1 
   Next
End If

【讨论】:

您可以通过使用更好的算法(例如 Boyer-Moore)来进一步提高效率:en.wikipedia.org/wiki/… 这比我的代码慢...` Public Function FindSequence(ByVal list() As Byte, ByVal value() As Byte)As Integer Dim startIndex As Integer = Array.IndexOf(list , value(0)) 直到 startIndex = -1 否则 list.Length - startIndex list(startIndex + index) Then Exit For runLength += 1 Next If runLength = value.Length Then Return startIndex startIndex = Array.IndexOf(list, value(0), startIndex + runLength) Loop Return -1 End Function ` @SeifShawkat 你试过了吗?我不知道它怎么会变慢,它的循环比你的代码少。它在几分之一秒内运行。你的呢? 嗯,其实你一开始就有点对了,它有点慢,因为它正在搜索 28,784 个病毒签名...... @BlueMonkMN:我的扫描一个 13 字节的文件(包含所有签名)用了不到 1 秒的时间,而你的不知何故花了 4 秒。

以上是关于杀毒扫描速度优化的主要内容,如果未能解决你的问题,请参考以下文章

对sql server查询速度的优化

30种优化查询速度的方法

缓解电脑卡顿的方法

数据库查询速度优化之解决技巧

下载速度慢怎么解决?

为啥HDFS写入速度如此之慢