9.4.2 特征化

1.元音字母个数

正常人通常在取域名的时候,都会偏向选取“好读”的几个字母组合,抽象成数学可以理解的语言,这使英文的元音字母比例会比较高。DGA生成域名的时候,由于时间因素是随机因素,所以元音字母这方面的特征不明显。下面我们通过数据分析来验证我们的想法。

读取alexa域名数据:


x1_domain_list = load_alexa("../data/top-1000.csv")

计算元音字母的比例:


def get_aeiou(domain_list):
    x=[]
    y=[]
    for domain in domain_list:
        x.append(len(domain))
        count=len(re.findall(r'[aeiou]',domain.lower()))
        count=(0.0+count)/len(domain)
        y.append(count)
    return x,y

分别获取两个僵尸网络DGA域名数据以及alexa域名数据,并计算元音字母比例:


x1_domain_list = load_alexa("../data/top-1000.csv")
x_1,y_1=get_aeiou(x1_domain_list)
x2_domain_list = load_dga("../data/dga-cryptolocke-1000.txt")
x_2,y_2=get_aeiou(x2_domain_list)
x3_domain_list = load_dga("../data/dga-post-tovar-goz-1000.txt")
x_3,y_3=get_aeiou(x3_domain_list)

以域名长度为横轴,元音字母比例为纵轴作图:


fig,ax=plt.subplots()
ax.set_xlabel('Domain Length')
ax.set_ylabel('AEIOU Score')
ax.scatter(x_3,y_3,color='b',label="dga_post-tovar-goz",marker='o')
ax.scatter(x_2, y_2, color='g', label="dga_cryptolock",marker='v')
ax.scatter(x_1, y_1, color='r', label="alexa",marker='*')
ax.legend(loc='best')
plt.show()

分析图9-14,不同家族之间具有明显聚合效果,正常域名与DGA之间具有一定的区分性。

图9-14 元音字母比例分布图

2 .去重后的字母数字个数与域名长度的比例

去重后的字母数字个数指的是域名中去掉重复的字母和数字后的个数,比如:

·baidu的个数为5;

·facebook个数为7;

·google的个数为4。

去重后的字母数字个数与域名长度的比例,从某种程度上反映了域名字符组成的统计特征。计算去重后的字母数字个数可以使用python的set数据结构:


def get_uniq_char_num(domain_list):
    x=[]
    y=[]
    for domain in domain_list:
        x.append(len(domain))
        count=len(set(domain))
        count=(0.0+count)/len(domain)
        y.append(count)
    return x,y

分别获取两个僵尸网络DGA域名数据以及alexa域名数据,并计算去重后的字母数字个数与域名长度的比例:


x1_domain_list = load_alexa("../data/top-1000.csv")
x_1,y_1=get_uniq_char_num(x1_domain_list)
x2_domain_list = load_dga("../data/dga-cryptolocke-1000.txt")
x_2,y_2=get_uniq_char_num(x2_domain_list)
x3_domain_list = load_dga("../data/dga-post-tovar-goz-1000.txt")
x_3,y_3=get_uniq_char_num(x3_domain_list)

以域名长度为横轴,去重后的字母数字占域名长度的比例为纵轴作图,结果如图9-15所示。

图9-15 唯一字母数字比例分布图

分析图9-15,不同家族之间具有明显聚合效果,正常域名与DGA之间具有一定的区分性。

3.平均jarccard系数

jarccard系数定义为两个集合交集与并集元素个数的比值,本例的jarccard系数是基于2-gram计算的。

计算两个域名之间的jarccard系数的方法为:


def count2string_jarccard_index(a,b):
    x=set(' '+a[0])
    y=set(' '+b[0])
    for i in range(0,len(a)-1):
        x.add(a[i]+a[i+1])
    x.add(a[len(a)-1]+' ')

    for i in range(0,len(b)-1):
        y.add(b[i]+b[i+1])
    y.add(b[len(b)-1]+' ')
    return (0.0+len(x-y))/len(x|y)

计算两个域名集合的平均jarccard系数的方法为:


def get_jarccard_index(a_list,b_list):
    x=[]
    y=[]
    for a in a_list:
        j=0.0
        for b in b_list:
            j+=count2string_jarccard_index(a,b)
        x.append(len(a))
        y.append(j/len(b_list))
    return x,y

分别获取两个僵尸网络DGA域名数据以及alexa域名数据,并计算jarccard系数比例:


x1_domain_list = load_alexa("../data/top-1000.csv")
x_1,y_1=get_jarccard_index(x1_domain_list,x1_domain_list)
x2_domain_list = load_dga("../data/dga-cryptolocke-1000.txt")
x_2,y_2=get_jarccard_index(x2_domain_list,x1_domain_list)
x3_domain_list = load_dga("../data/dga-post-tovar-goz-1000.txt")
x_3,y_3=get_jarccard_index(x3_domain_list,x1_domain_list)

以域名长度为横轴,平均jarccard系数为纵轴作图,结果如图9-16所示。

图9-16 平均jarccard系数分布图

分析图9-16,不同家族之间具有明显聚合效果,正常域名与DGA之间具有一定的区分性。

4.HMM系数

正常人通常在取域名的时候,都会偏向选取常见的几个单词组合,抽象成数学可以理解的语言,因此,以常见英文单词训练HMM模型,正常域名的HMM系数偏高,僵尸网络DGA域名由于是随机生成的,所以HMM系数偏低。由于HMM将会在后面章节专门介绍,所以这里只是以统计图介绍下,如图9-17所示。

图9-17 HMM系数分布图