一、 基本思想
(1)检测某些名称的驱动是否存在,这一部分有个黑名单
(2)检测驱动中部分代码的特征是否匹配,这一部分用另外一个黑名单
每一个驱动都要经过以上两重检查,具体的算法实现就是计算驱动名称或部分代码的Hash值,然后在黑名单中进行匹配。
所以,你看不到任何敏感的字符串。具体的Hash算法就是变形的CRC32,如下:
ULONG GetStringCRCHash(BYTE *Str, int Length)
{
ULONG crc=0;
int i=0;
for (i=0;i<Length;i++)
{
crc = (Str[i] | (crc << 8)) ^( crc_32_tab[crc >> 24]);
}
return crc;
}
crc_32_tab就是标准CRC32算法所使用的那个表。
二、驱动名称黑名单
当驱动加载时,枚举系统所有已加载的模块(遍历PsLoadedModuleList和遍历\Driver对象目录两种方式,以及在LoadImageNotify中检测到有驱动加载时),获取驱动模块的名称。
根据名称计算时,传入的参数就是驱动模块名称和长度,比如像这样:
HashValue=GetStringCRCHash("IsDrv122.sys",strlen("IsDrv122.sys"));
三、驱动特征黑名单
枚举所有驱动,取驱动中某个固定偏移处的一段代码,用上面提到的Hash算法计算其Hash值,然后在黑名单中匹配。
特征的每一项是一个0x10大小的结构,如下:
typedef struct _HASH_INFO{
ULONG Offset;
ULONG HashValue;
WORD EndLen;
WORD HashLen;
ULONG Unknow1;
}HASH_INFO,*PHASH_INFO;
就是说,从驱动基址开始偏移Offset处,取长度为HashLen的代码计算其Hash,检查计算结果是否与HashValue匹配。
HashLen与EndLen相等的是精确匹配,就是说确定了就是Offset开始处长度为HashLen的代码的Hash
HashLen与EndLen不相等的是模糊匹配,表示从OffSet开始在一定范围内每次取HashLen长度的代码计算其Hash值
每一个驱动都要分别与这41个黑名单进行匹配,直至找到相匹配的特征项,都没有匹配到,当然就认为是没有非法模块啦~~
四、如何Anti这种检测?
方法一:涂抹黑名单中的Hash值
随便改成其它值,它计算完当然就匹配不到了,但是想找到黑名单不是太通用,毕竟特征不够明显
方法二:涂抹CRC32_Table
前面说了,这个表就是标准CRC32算法所使用的那张表,所以匹配起来特别容易~~
我们可以涂抹这张表,这样它永远无法计算出正确的Hash,所有的黑名单也就失去意义了,哈哈~~