签名模式解析效率

时间:2018-05-31 13:04:46

标签: c# design-patterns hex byte signatures

我将二进制文件转换为十六进制字符串,以搜索用户提供的特定模式,就像反病毒处理其签名数据库一样。如果找到模式,则返回true。

我面临的一个难点是通配符和扫描速度慢。用户有数千种模式,每种模式最多200个字符,甚至更多。

例如,此模式用于验证文件是否是在C ++下编译的,而"?" character是一个通配符(可以匹配任何一个字符):

  

55 8B EC 53 8B 5D 08 56 8B 75 0C 85 F6 57 8B 7D 10 ?? ?? ?? ?? ?? ??   ?? ?? ?? ?? ?? ?? ?? 01

类似于那个的模式都堆放在一个长度不等的文件中,所以我猜你得到了一般的想法。

这是我正在使用的代码(工作正常,但与其他只需几秒钟进行模式扫描的工具相比速度极慢,如ExeInfoPE或Die)

        static bool compare(string[] mask, byte[] buffer, int position)
    {
        var i = 0; // index
        foreach (string x in mask) // loop through the mask
        {
            if (x.Contains("?")) // is current mask position a wildcard?
            {
            }// if so skip comparison
            else if (byte.Parse(x, System.Globalization.NumberStyles.HexNumber) == buffer[position + i]) // else try to compare
            {
            }// succeeded, move onto next byte
            else
                return false; // failed, pattern not found
            ++i; // increment the index.
        }
        return true; // pattern was found
    }

关于如何大幅提高速度,同时保持对通配符的支持以便我的工具可以在现实世界中使用的任何想法?

1 个答案:

答案 0 :(得分:0)

如果你有多个文件,你可以将掩码预先转换为byte?[](或者更简单地将byte[]加上bool[] isWildcard,如果有通配符则为真)比赛。如果你有1000个文件,这个byte.Parse(x, System.Globalization.NumberStyles.HexNumber)是无用的重复1000次。

另一个问题...... buffer有多大?我希望你只能阅读高达4kb(甚至更少......你可以预先检查所有面具,看看哪一个是最大的)来自每个文件的数据,而且你还没有阅读整个文件。

你可以尝试索引模式的第二件事,至少是模式的第一个字节(但请记住,你必须处理以?开头的模式的情况。)

一些随机评论:

  • 它并不清楚你真正想要做什么。还需要一些更多的信息。您需要扫描多少个文件? 1或2或多(10 +,100 +?)?

  • 您的模式从文件中的固定位置开始,或者至少始终存在于文件的某个位置(如exe文件的MZ签名,即文件的前两个字符) ,还是他们可以在任何地方?
    许多节目"作弊":他们没有加载整个文件。他们装小件。例如,第一个4kb和最后一个4kb。他们知道"他们的模式必须在那里。因此,如果您加载整个文件,您肯定会变慢。

  • 你的模式的第一个字节,如何统计分布?例如......您有1000个模式,并且有一个字节有256个可能的值。模式的第一个字节是否均等地分配给所有可能的值?所以平均有4个模式以一个字节的每个可能值开始(4个模式以' A'开头,4个以' B'等等开头),或者那里是一些更多的字节(例如,有100个模式以' A'开头),因为在第一种情况下,可以通过第一个字节索引模式并快速选择一个小子集只有第一个字节的模式,在第二种情况下,第一个字节不足以判断要检查的模式子集。

一般来说,我会有两种结构:

Dictionary<byte, List<Pattern>> PatternsByFirstByte

List<Pattern> PatternsWithFirstCharacterWildcard

这样,对于每个字节,您必须检查PatternsByFirstByte中的少量模式以及PatternsWithFirstCharacterWildcard的所有模式。但如果第一个字节足够判别,则可以正常工作。更高级的是创建一个完整的trie结构来保持/索引模式,和/或以不同的方式处理位置零(?? ?? ?? xx yy)的通配符。很明显,(??? ?? xx yy)相当于(xx yy),起始位置&gt; = 2.然后你可以在字典中放入模式xx yy并在一个位置必须放置一个注释be&gt; = 2,就像Pattern类本身一样,那就是:

class Pattern
{
    public readonly byte?[] Bytes;
    public int MinimumStartingPosition;
}