例如对于一个句子,I love my country.
那么2-gram得到的词集为:
["I love","love my","my country"]
代码如下:
检测webshell的第一种方式的思路为,将php webshell文件按照单词分词后(正则\b\w+\b),按照2-gram算法得到词集,从而得到文件每一行在该词集上的分布情况,得到特征向量;然后将正常的php文件也按照如上方法在如上词集上得到特征向量。
webshell文件的行标记为1,正常php文件的行标记为0,特征向量和标记在一起组成数据集。再在朴素贝叶斯模型上使用交叉验证的方式得的准确度。
代码如下:
#coding:utf-8
import os
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.model_selection import cross_val_score
from sklearn.naive_bayes import GaussianNB
DATAPATH = os.path.dirname(os.path.abspath(__file__)) + "/data"
BLACKPATH = DATAPATH + "/black"
WHITEPATH = DATAPATH + "/white"
def parse_files(path,rtn):
files = os.listdir(path)
for item in files:
if item in ['.', '..']:
continue
cpath = path + "/" + item
if os.path.isdir(cpath):
parse_files(cpath, rtn)
else:
if cpath.endswith(".php"):
with open(cpath, "r") as f:
for line in f.readlines():
line = line.strip()
rtn.append(line)
if __name__ == '__main__':
black_lines = list()
parse_files(BLACKPATH, black_lines)
white_lines = list()
parse_files(WHITEPATH, white_lines)
webshell_vectorizer = CountVectorizer(ngram_range=(2,2), decode_error="ignore", token_pattern=r'\b\w+\b')
x1 = webshell_vectorizer.fit_transform(black_lines).toarray()
vocabulary = webshell_vectorizer.vocabulary_
y1 = len(x1)*[1]
white_vectorizer = CountVectorizer(ngram_range=(2,2), decode_error="ignore", token_pattern=r'\b\w+\b', vocabulary=vocabulary)
x2 = white_vectorizer.fit_transform(white_lines).toarray()
y2 = len(x2)*[0]
x = np.concatenate((x1, x2))
y = np.concatenate((y1, y2))
model = GaussianNB()
score = cross_val_score(model, x, y, cv=10)
print score
print "precision:", np.mean(score)*100
代码执行的效果如下:
检测webshell的第二种方式的思路为,将php webshell文件按照函数调用或者字符串常量分词后(正则\b\w+\b(|\'\w+\'),按照1-gram算法得到词集(1-gram应该就是指的单个词了),从而得到文件每一行在该词集上的分布情况,得到特征向量;然后将正常的php文件也按照如上方法在如上词集上得到特征向量。
webshell文件的行标记为1,正常php文件的行标记为0,特征向量和标记在一起组成数据集。再在朴素贝叶斯模型上使用交叉验证的方式得的准确度。
代码如下:
#coding:utf-8
import os
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.model_selection import cross_val_score
from sklearn.naive_bayes import GaussianNB
DATAPATH = os.path.dirname(os.path.abspath(__file__)) + "/data"
BLACKPATH = DATAPATH + "/black"
WHITEPATH = DATAPATH + "/white"
def parse_files(path,rtn):
files = os.listdir(path)
for item in files:
if item in ['.', '..']:
continue
cpath = path + "/" + item
if os.path.isdir(cpath):
parse_files(cpath, rtn)
else:
if cpath.endswith(".php"):
with open(cpath, "r") as f:
for line in f.readlines():
line = line.strip()
rtn.append(line)
if __name__ == '__main__':
black_lines = list()
parse_files(BLACKPATH, black_lines)
white_lines = list()
parse_files(WHITEPATH, white_lines)
webshell_vectorizer = CountVectorizer(ngram_range=(1,1), decode_error="ignore", token_pattern=r'\b\w+\b\(|\'\w+\'')
x1 = webshell_vectorizer.fit_transform(black_lines).toarray()
vocabulary = webshell_vectorizer.vocabulary_
y1 = len(x1)*[1]
white_vectorizer = CountVectorizer(ngram_range=(1,1), decode_error="ignore", token_pattern=r'\b\w+\b\(|\'\w+\'', vocabulary=vocabulary)
x2 = white_vectorizer.fit_transform(white_lines).toarray()
y2 = len(x2)*[0]
x = np.concatenate((x1, x2))
y = np.concatenate((y1, y2))
model = GaussianNB()
score = cross_val_score(model, x, y, cv=10)
print score
print "precision:", np.mean(score)*100
代码执行的效果如下:
文章还提到了用朴素贝叶斯算法识别DGA域名(将域名使用2-gram分词后,得到每个域名在词集上的分布向量,然后使用朴素贝叶斯算法),这个思路还是用得比较多的。另外提到的就是用朴素贝叶斯识别验证码(将验证码的灰度图的每一个像素点的值作为特征向量的一维,再使用朴素贝叶斯算法),不过我之前已经用卷积神经网络识别过验证码(Caffe的LeNet-5模型上修改),且准确率高达99.996%,一个验证码识别比赛的结果,所以就不再展开。