签名模式解析效率



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

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

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

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
}

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

如果您有多个文件要匹配,则可以将掩码预转换为byte?[](或者更简单地说,是一个byte[]加上一个bool[] isWildcard,如果有通配符,则为真(。这个byte.Parse(x, System.Globalization.NumberStyles.HexNumber)是工作,如果你有 1000 个文件,将被无用地重复 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(,起始位置为>= 2。然后,您可以将模式xx yy放入字典中,并在位置必须为>= 2 的地方放置一个注释,就像在Pattern类本身中一样,然后是:

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

相关内容

  • 没有找到相关文章

最新更新