针对工业控制系统中最常用的Modbus协议,爬取了约1万条数据,利用wireshark工具对Modbus协议结构进行了初步分析,初步得到了modbus协议的特征,modbus协议的功能字在协议中的出现的位置是可以推算出来的,我们选取modbus协议的功能字和功能字后连续的两位字节码总共三位字节码作为modbus协议的特征,如下图所示被红框圈出来的即我们选择的三位字节码,使用Random Forest,SVM和GBDT三种分类算法,对约10000条随机数据进行训练,并用约20000条随机数据进行验证。

Random Forest分类器
Random Forest即随机森林就是通过集成学习的思想将多棵树集成的一种算法,它的基本单元是决策树,而它的本质属于机器学习的一大分支——集成学习(Ensemble Learning)方法。

正确率为(17541+7780)/(18402+7780)*100%=96.7%
召回率为17541/(17541+0)*100%=100%
SVM分类器
支持向量机(Support Vector Machine)是Cortes和Vapnik于1995年首先提出的,它在解决小样本、非线性及高维模式识别中表现出许多特有的优势,并能够推广应用到函数拟合等其他机器学习问题中。
支持向量机方法是建立在统计学习理论的VC 维理论和结构风险最小原理基础上的,根据有限的样本信息在模型的复杂性(即对特定训练样本的学习精度,Accuracy)和学习能力(即无错误地识别任意样本的能力)之间寻求最佳折衷,以期获得最好的推广能力(或称泛化能力)。

正确率为(17541+7606)/(18576+7606)*100%=96%
召回率为17541/(17541+0)*100%=100%
GBDT分类器
GBDT是boosting算法的一种,按照boosting的思想,在GBDT算法的每一步,用一棵决策树去拟合当前学习器的残差,获得一个新的弱学习器。将这每一步的决策树组合起来,就得到了一个强学习器。

正确率为(17541+8618)/(18576+7606)*100%=99.9%
召回率为17541/(17541+0)*100%=100%
综合对比三种分类器的分类结果,三种分类器都可以做到召回率100%,即可以将所有的modbus协议正确识别出来,但对于非modbus协议都存在的误判,其中GBDT分类器的正确率最高。
代码如下,使用了Python中的sklearn包。
import pyshark
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.svm import SVC
import re
import numpy as np
#切割字符串
def cut_text(text, lenth): # lenth 表示切割的子字符串的长度
textArr = re.findall('.{'+str(lenth)+'}', text)
textArr.append(text[(len(textArr)*lenth):])
if textArr[-1] =='': textArr.pop()
return textArr
#SVC分类器
def Classifier1(X,y,XX):
model = SVC(C=5.0)
#用X(输入),y(输出)来训练
model.fit(X,y)
#对XX进行预测
predicted = model.predict(XX)
return predicted
#RandomForest分类器
def Classifier2(X,y,XX):
model = RandomForestClassifier()
model.fit(X,y)
predicted = model.predict(XX)
return predicted
#GBDT分类器
def Classifier3(X,y,XX):
model = GradientBoostingClassifier()
model.fit(X,y)
predicted = model.predict(XX)
return predicted
train=[]
test=[]
y=[]
target_test=[]
#训练集1
cap=pyshark.FileCapture("./train/train.pcap",include_raw=True,use_json=True)
for cap_ in cap:
strr=str(cap_.layers[-1].value)
if(strr[0]=='[' or strr[0]=='\'' ):
newstr=strr[2:8].ljust(6,'0')
else:
newstr=strr[0:6].ljust(6,'0')
traindata=cut_text(newstr,2)
print(traindata)
a= [int(x,16) for x in traindata]
train.append(a)
y.append(1)
cap.close()
#训练集2
cap=pyshark.FileCapture("./train/train2.pcapng",include_raw=True,use_json=True)
for cap_ in cap:
strr=str(cap_.layers[-1].value)
if(strr[0]=='[' or strr[0]=='\'' ):
newstr=strr[2:8].ljust(6,'0')
else:
newstr=strr[0:6].ljust(6,'0')
traindata=cut_text(newstr,2)
print(traindata)
a= [int(x,16) for x in traindata]
train.append(a)
y.append(0)
cap.close()
traindataz=np.array(train)
target=np.array(y)
print(traindataz)
print(target)
#测试集1
cap=pyshark.FileCapture("./test/test.pcap",include_raw=True,use_json=True)
for cap_ in cap:
if(cap_.highest_layer=='MODBUS_RAW'):
target_test.append(1)
else:
target_test.append(0)
strr=str(cap_.layers[-1].value)
if(strr[0]=='[' or strr[0]=='\'' ):
newstr=strr[2:8].ljust(6,'0')
else:
newstr=strr[0:6].ljust(6,'0')
traindata=cut_text(newstr,2)
a= [int(x,16) for x in traindata]
test.append(a)
cap.close()
#测试集2
cap=pyshark.FileCapture("./test/test2.pcapng",include_raw=True,use_json=True)
for cap_ in cap:
if(cap_.highest_layer=='MODBUS_RAW'):
target_test.append(1)
else:
target_test.append(0)
strr=str(cap_.layers[-1].value)
if(strr[0]=='[' or strr[0]=='\'' ):
newstr=strr[2:8].ljust(6,'0')
else:
newstr=strr[0:6].ljust(6,'0')
traindata=cut_text(newstr,2)
a= [int(x,16) for x in traindata]
test.append(a)
cap.close()
#测试集3
cap=pyshark.FileCapture("./test/test3.pcap",include_raw=True,use_json=True)
for cap_ in cap:
if(cap_.highest_layer=='MODBUS_RAW'):
target_test.append(1)
else:
target_test.append(0)
strr=str(cap_.layers[-1].value)
if(strr[0]=='[' or strr[0]=='\'' ):
newstr=strr[2:8].ljust(6,'0')
else:
newstr=strr[0:6].ljust(6,'0')
traindata=cut_text(newstr,2)
a= [int(x,16) for x in traindata]
test.append(a)
cap.close()
#测试集4
cap=pyshark.FileCapture("./test/test4.pcap",include_raw=True,use_json=True)
for cap_ in cap:
if(cap_.highest_layer=='MODBUS_RAW'):
target_test.append(1)
else:
target_test.append(0)
strr=str(cap_.layers[-1].value)
if(strr[0]=='[' or strr[0]=='\'' ):
newstr=strr[2:8].ljust(6,'0')
else:
newstr=strr[0:6].ljust(6,'0')
traindata=cut_text(newstr,2)
a= [int(x,16) for x in traindata]
test.append(a)
cap.close()
#测试集5
cap=pyshark.FileCapture("./test/test5.pcap",include_raw=True,use_json=True)
for cap_ in cap:
if(cap_.highest_layer=='MODBUS_RAW'):
target_test.append(1)
else:
target_test.append(0)
strr=str(cap_.layers[-1].value)
if(strr[0]=='[' or strr[0]=='\'' ):
newstr=strr[2:8].ljust(6,'0')
else:
newstr=strr[0:6].ljust(6,'0')
traindata=cut_text(newstr,2)
a= [int(x,16) for x in traindata]
test.append(a)
cap.close()
#测试集6
cap=pyshark.FileCapture("./test/test6.pcap",include_raw=True,use_json=True)
for cap_ in cap:
if(cap_.highest_layer=='MODBUS_RAW'):
target_test.append(1)
else:
target_test.append(0)
strr=str(cap_.layers[-1].value)
if(strr[0]=='[' or strr[0]=='\'' ):
newstr=strr[2:8].ljust(6,'0')
else:
newstr=strr[0:6].ljust(6,'0')
traindata=cut_text(newstr,2)
a= [int(x,16) for x in traindata]
test.append(a)
cap.close()
testdataz=np.array(test)
target_test=np.array(target_test)
print(testdataz)
TP=0
FP=0
TN=0
FN=0
#这里选择使用的分类器
result=Classifier3(traindataz,target,testdataz)
print(result)
for index in range(0,len(result)):
if(result[index]==target_test[index]):
if(target_test[index]==1):
TP=TP+1
else:
TN=TN+1
else:
if(target_test[index]==1):
FN=FN+1
else:
FP=FP+1
print(TP,FP)
print(FN,TN)
本文地址: 工控协议数据处理(四):Python分类算法-Random Forest,SVM,GBDT