我将二进制文件转换为十六进制字符串,以搜索用户提供的特定模式,就像反病毒处理其签名数据库一样。如果找到模式,则返回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
}
关于如何大幅提高速度,同时保持对通配符的支持以便我的工具可以在现实世界中使用的任何想法?
答案 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。他们知道"他们的模式必须在那里。因此,如果您加载整个文件,您肯定会变慢。
一般来说,我会有两种结构:
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;
}