使用深度学习识别webshell

本文探讨了使用词向量、TF-IDF、字节分布和灰度图化等方法在Webshell样本(5000黑样本+10000白样本)上进行恶意脚本识别的过程。实验中,TF-IDF特征表现出最佳性能,达到约95%的识别精度。
摘要由CSDN通过智能技术生成

在做毕设的时候选的这个题目,实际在完成的过程中也有了一些收获,在这里记录下
首先是样本,webshell黑样本主要来源于github上的webshell收集项目,白样本来自于github上的开源框架。我也尝试过asp,jsp语言的恶意脚本识别,其实识别效果也很不错,能有95%左右,但是asp,jsp这些语言的恶意脚本数量太少,只有大约1000个左右,说服力不是很强。php样本的数量和质量都要高一些,最终我所搜集到了5000个webshell,以及10000个php白样本
样本链接:https://pan.baidu.com/s/1AdpfAgL3sT2C77RYLwImaQ
提取码:dj4w
完整代码链接:https://pan.baidu.com/s/13sBlnuSbatsdNEkPoDJg9Q
提取码:3tym

词向量提取特征方法:用的是sklearn自带的词向量化器,提词方法是用正则匹配来匹配单词边界,最后生成两个numpy数组,x里存放提取的词向量,y里存放黑白样本的标记。实际实验下来,词向量提取特征识别webshell正确率只有70%左右,和其他的方法相比还是不行。

def get_feature_by_bag_tfidf():
    global white_count
    global black_count
    global max_features
    print("max_features=%d" % max_features)
    webshell_files_list = load_files(webshell_dir)
    y1 = [1] * len(webshell_files_list)
    black_count = len(webshell_files_list)

    wp_files_list = load_files(whitefile_dir)
    y2 = [0] * len(wp_files_list)
    white_count = len(wp_files_list)

    x = webshell_files_list + wp_files_list
    y = y1 + y2
    CV = CountVectorizer(ngram_range=(1, 1), max_features=10000,
                         token_pattern=r'\b\w+\b', min_df=1, max_df=1.0)
    x = CV.fit_transform(x).toarray()

    transformer = TfidfTransformer(smooth_idf=False)
    x_tfidf = transformer.fit_transform(x)
    x = x_tfidf.toarray()
    print("黑样本", black_count, "白样本", white_count)
    x = np.array(x)
    y = np.array(y)
    return x, y

tf-idf算法,即逆词频统计,即是在词向量提取特征的基础上进行逆词频统计,可以看到实际代码也就比词向量提取特征多了个tf-idf转换。这里的ngram_range其实用处不大,特别是限定最大长度为10000的时候,因为实际webshell里词与词的组合变化非常多,就算只计算连续两个词的组合也有很多种,所以在词库上限定死为10000的情况下,实际n-gram和1-gram是没有区别的,我的实验结果也说明了这一点。实际实验下来,tf-idf提取特征识别webshell正确率还是可以的差不多能有95%左右

def get_feature_by_bag_tfidf():
    global white_count
    global black_count
    global max_features
    print("max_features=%d" % max_features)
    webshell_files_list = load_files(webshell_dir)
    y1 = [1] * len(webshell_files_list)
    black_count = len(webshell_files_list)

    wp_files_list = load_files(whitefile_dir)
    y2 = [0] * len(wp_files_list)
    write_txt_byline(all_file_name)
    white_count = len(wp_files_list)

    x = webshell_files_list + wp_files_list
    y = y1 + y2
    CV = CountVectorizer(ngram_range=(1, 1), max_features=10000,
                         token_pattern=r'\b\w+\b', min_df=1, max_df=1.0)
    x = CV.fit_transform(x).toarray()

    transformer = TfidfTransformer(smooth_idf=False)
    x_tfidf = transformer.fit_transform(x)
    x = x_tfidf.toarray()
    print("黑样本", black_count, "白样本", white_count)
    x = np.array(x)
    y = np.array(y)
    return x, y

文件字节分布+区间熵:这个特征提取方法是从识别exe文件参考来的,一般来说恶意exe文件,比如勒索软件一类的,因为难以提取直接的静态文本特征所以采用这种方法,但是webshell有直接的文本特征,而且大小相比于exe文件要小很多。字节分布就是文件以二进制读入时,0-255个字节出现的次数,区间熵就是计算每1024字节的熵,计算文件最后256个1024字节区间的熵,不够的补0,多了的话取最后256个,最后组合成512维的特征向量。实际实验下来,这种特征提取方法的识别准确率最高,在训练集:测试集大小为1:9的时候都能有97%的测试集正确率,缺点是有一定的不可解释性。

def generate_byte_feature(file_name):
    with open(file_name, mode='rb') as f:
        file_rb = np.fromfile(f, dtype=np.ubyte)
        byte_laymap = Counter(file_rb)
        file_length = len(file_rb)
        byte_layout = []  # 统计0-255个字节出现的次数
        for byte in range(0, 256):
            # 0-255字节出现的次数
            byte_layout.append(byte_laymap[byte])
        current_loc = 0  # 滑动窗口统计熵
        step = 1024  # 滑动窗口一次移动字节数
        entro_list = []
        while current_loc <= file_length:
            if current_loc + step > file_length:
                end = file_length
            else:
                end = current_loc + step
            entro_list.append(Entropy(file_rb[current_loc:end]))
            current_loc = current_loc + step
        final_result = byte_layout + entro_list
        if len(final_result) < 512:
            final_result = np.array(final_result)
            final_result = list(np.pad(final_result, (0, 512 - len(final_result)), 'constant', constant_values=(0, 0)))
            return final_result[0:512]
        else:
            return final_result[0:512]

文件灰度图化:本质上也是通过文件的二进制特征来识别webshell,只不过是把文件读取的字节转换成一维数组,然后再reshape成64乘64,128乘128,256乘256这样形式的二维数组,然后以灰度图的形式保存,就得到了webshell的灰度图,然后通过图像识别的方法来识别这些灰度图。实验下来发现识别效果还行,128*128大小的灰度图识别效果最好,能达到95%左右。

def myresize_image(myimage, padding_mode=1,size=data_pic_size ):
    # 两种填充方式,1和2,1为重复填充,2为补0填充
    pixel_num = myimage.shape[0]
    if pixel_num <= 5:
        # 如果文件大小极小,视作空文件处理
        return np.array([0]), -1
    total_pixel = size * size
    if total_pixel >= pixel_num:
        if padding_mode == 1:
            recycle_num = total_pixel // pixel_num
            result = myimage
            for temp in range(0, recycle_num - 1):
                result = np.hstack((result, myimage))
            result = np.hstack((result, myimage[0:total_pixel - result.shape[0]]))
            result = result.reshape(size, size)
            return result, 1
        else:
            result = np.pad(myimage, (0, total_pixel - pixel_num), 'constant', constant_values=(0, 0))
            result = result.reshape(size, size)
            return result,1
    if total_pixel < pixel_num:
        result = myimage[pixel_num - total_pixel:pixel_num]  # 如果字节过多,取最后的文本
        result = result.reshape(size, size)
        return result, 1

def generate_pic_data(dir, type):
    g = os.walk(dir)
    file_count = 0
    for path, d, filelist in g:
        # print d;
        for filename in filelist:
            # print os.path.join(path, filename)
            if filename.endswith('.php') or filename.endswith('.txt'):
                fulepath = os.path.join(path, filename)
                # print("正在转成图片 %s" % fulepath)
                file_count = file_count + 1
                f = open(fulepath, mode='rb')
                image = np.fromfile(f, dtype=np.ubyte)
                pic_array, flag = myresize_image(image)
                temp = random.randint(0, 100)
                if temp >= 90:
                    # >=n,表示n%的数据作为测试集
                    save_dir = "picdata/"
                else:
                    save_dir = "picdata_test/"
                if flag == 1:
                    save_path = save_dir + type + "/" + str(file_count) + ".png"
                    cv2.imwrite(save_path, pic_array)
                    print(save_path + "已保存")
                    if file_count >= max_sample_num:
                        cv2.waitKey(0)
                        return
    cv2.waitKey(0)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值