前言
繼續(xù)昨天的話題,使用Python實現(xiàn)機器學習算法對安卓APP進行檢測。準備工作已經差不多了向瓷,那么這篇文章就來詳細記錄如何將機器學習算法應用到安卓惡意軟件檢測上以及如何實現(xiàn)常見機器學習算法肠套。
準備工作
- Anaconda:Anaconda下載
- Anaconda是一款Python科學計算的環(huán)境包,包含了眾多的科學計算庫和原生Python環(huán)境猖任。這里我使用的是Python2的64位的Windows版你稚。將安裝包下載后,僅需要進行安裝即可朱躺。相應的包和庫都會自動集成刁赖,很方便。
- 利用上一篇文章對惡意軟件和正常軟件進行處理后生成的包含權限信息的txt文件各500條长搀。
- 這里正常軟件樣本采用之前文章中介紹的爬蟲下載即可乾闰,惡意軟件為了安全起見不提供下載方式,但在文章最后提供處理過后的txt實驗數(shù)據(jù)盈滴。需要注意的是正常的樣本收集過后要經過幾次查殺篩選涯肩,排除潛藏在正常軟件中的惡意軟件。
- 驗證環(huán)境:首先確保將安裝后的Anaconda中的python加入到環(huán)境變量中巢钓。接著cmd下調用Python并執(zhí)行
import numpy
病苗,如下圖沒有報錯即可:
基本思路
- 首先我們這次試用樸素貝葉斯作為分類核心算法。
- 采取先訓練分類器症汹,再使用分類器對位置樣本進行分類硫朦。
樸素貝葉斯
樸素貝葉斯是機器學習中最常見不過的一種算法,它簡單實用且在數(shù)據(jù)量較少的情況下依然有著出色的表現(xiàn)背镇。這里不再贅訴樸素貝葉斯的原理咬展,提供幾個鏈接供參考。
實現(xiàn)算法
話不多說瞒斩,接下來開始用Python實現(xiàn)樸素貝葉斯算法破婆。
- 我們使用權限(permission)作為特征,所以首先構建一個包含所有權限項的無重復列表胸囱。如:【權限1祷舀,權限2,……烹笔,權限n】
- 這里我是用了一個簡單直接的方法裳扯,讀遍所有的txt文件中的每個項,只要有之前不存在的項就追加到list中谤职。其實可以去安卓官網(wǎng)查看安卓開發(fā)者可以申請到的全部權限饰豺,直接構建出list。
- 接著需要將每個txt文件處理成向量的形式允蜈。舉個例子冤吨,如果樣本1對應的權限項為【權限1蒿柳,權限3,權限5锅很,權限7】其馏,則他的對應向量就是【1,0,1,0,1,0,1,0,0,0】——》假設全部權限的list長度為10項凤跑。
- 接著就是訓練函數(shù)爆安,其基本思想總結為如下偽代碼:
計算每個類別中文檔數(shù)目
對于每個txt文檔:
對于每個類別:
如果權限項出現(xiàn)在文檔中則增加該詞條計數(shù)值
增加所有權限項計數(shù)值
對于每個類別:
將該權限項數(shù)目除以總數(shù)得到條件概率
返回條件概率```
舉個例子,首先初始化一個全為0的list仔引,長度等于所有不重復權限項的數(shù)量和(假設為5)扔仓。【0,0,0,0,0】咖耘,接著針對正常的樣本翘簇,逐條輸入。假設第一條樣本為【1,1,0,0,1,】儿倒,第二條樣本為【1,1,1,1,1】版保,第三條為【0,0,0,0,0】則經過兩次輸入,我們的list變成【2,2,1,1,2】夫否,除以總數(shù)3得到P=【0.67 ,0.67 ,0.33 ,0.33 ,0.67】彻犁。那么根據(jù)樸素貝葉斯算法,認為每個權限項都是獨立的凰慈,則假設待測樣本為【1,0,0,1,0】汞幢,那么他屬于正常樣本的概率為P=1*0.67*1*0.33=0.2211
* 上面的例子針對正常樣本和惡意樣本都要做。分類算法較簡單微谓,只需要計算出P正常和P惡意森篷,然后比較哪個概率大。我們就將待測樣本分類到概率大的一類中豺型。
* 測試指標:我們使用檢測率仲智,就是分類正確的概率。在500條正常樣本和500條惡意樣本中姻氨,隨機選出400個正常樣本和400個惡意樣本作為訓練集坎藐,訓練出分類器。然后用剩下的200個樣本作為未知待測樣本哼绑,對其進行檢測岩馍。輸出分類錯誤的情況以及準確率。
#實現(xiàn)中注意事項
1. 由于要計算多個概率的乘積以獲得待測樣本屬于某個類別的概率抖韩,一旦其中一個概率為0蛀恩,則最后的結果必然為0.為了降低這種影響,可以將所有權限項出現(xiàn)的次數(shù)初始化為1茂浮,分母初始化為2.
2. 計算很多比較小的數(shù)相乘双谆,很容易造成下溢出壳咕,影響檢測的結果。所以我們利用對乘積取熙然對數(shù)的方式:ln(a * b) = ln(a) + ln(b)顽馋,這樣不會有任何損失谓厘。
# 執(zhí)行結果截圖
* 這里執(zhí)行10次取平均值,可以看到效果還是很不錯的寸谜,大概準確率有9成竟稳。并且誤報當中大部分是把好的APP判斷成了惡意的。
![檢測結果.png](http://upload-images.jianshu.io/upload_images/1863312-8efb3d95f311025b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
#完整代碼
```code
__author__ = 'Captainxero'
from numpy import *
import numpy as np
global p1
global p0
global numBad2Good
global numGood2Bad
global rateBad2Good
global rateGood2Bad
global Accuracy_Rate
Accuracy_Rate = 0
numBad2Good = 0
numGood2Bad = 0
def createVocabList(dataSet):
vocabSet = set([]) #create empty set
for document in dataSet:
vocabSet = vocabSet | set(document) #union of the two sets
return list(vocabSet)
def setOfWords2Vec(vocabList, inputSet):
returnVec = [0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] = 1
else: print "the word: %s is not in my Vocabulary!" % word
return returnVec
def trainNB0(trainMatrix,trainCategory):
numTrainDocs = len(trainMatrix)
numWords = len(trainMatrix[0])
pAbusive = sum(trainCategory)/float(numTrainDocs)
p0Num = ones(numWords); p1Num = ones(numWords) #change to ones()
p0Denom = 2.0; p1Denom = 2.0 #change to 2.0
for i in range(numTrainDocs):
if trainCategory[i] == 1:
p1Num += trainMatrix[i]
p1Denom += sum(trainMatrix[i])
else:
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
p1Vect = np.log(p1Num/p1Denom) #change to log()
p0Vect = np.log(p0Num/p0Denom) #change to log()
return p0Vect, p1Vect, pAbusive
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
global p1
global p0
p1 = sum(vec2Classify * p1Vec) + np.log(pClass1) #element-wise mult
p0 = sum(vec2Classify * p0Vec) + np.log(1.0 - pClass1)
if p1 > p0:
return 1
else:
return 0
def bagOfWords2VecMN(vocabList, inputSet):
returnVec = [0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] += 1
return returnVec
def textParse(bigString): #input is big string, #output is word list5
import re
listOfTokens = re.split(r'\W*', bigString)
# return [tok.lower() for tok in listOfTokens if len(tok) > 2]
return [tok for tok in listOfTokens if len(tok) > 2]
def spamTest():
global numBad2Good
global numGood2Bad
global Accuracy_Rate
docList=[]; classList = []; fullText =[]
for i in range(1,501):
wordList = textParse(open('D:/Sample/tmp/badSRC/%d.txt' % i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(1)
wordList = textParse(open('D:/Sample/tmp/goodSRC/%d.txt' % i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(0)
vocabList = createVocabList(docList)#create vocabulary
trainingSet = range(500); testSet=[] #create test set
for i in range(100):#random for testSet
randIndex = int(random.uniform(0,len(trainingSet)))
testSet.append(trainingSet[randIndex])
del(trainingSet[randIndex])
trainMat=[]; trainClasses = []
for docIndex in trainingSet:#train the classifier (get probs) trainNB0
trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))
trainClasses.append(classList[docIndex])
p0V,p1V,pSpam = trainNB0(array(trainMat),array(trainClasses))
errorCount = 0; GoodToBad = 0;BadToGood = 0
for docIndex in testSet: #classify the remaining items
wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])
# if classifyNB(array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:
if classifyNB(array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:
if classifyNB(array(wordVector),p0V,p1V,pSpam) != 1:
GoodToBad += 1
numGood2Bad += 1
# print 'GoodToBad:', docList[docIndex]
# print 'GoodToBad: NO.',docIndex
# print 'P-Good:', p0
# print 'P-Bad :', p1
# print 'Miss :', p0-p1
# print ''
else:
BadToGood += 1
numBad2Good += 1
# print 'BadToGood', docList[docIndex]
# print 'P-Good:', p0
# print 'P-Bad: ', p1
# print 'Miss :', p0-p1
# print 'BadToGood: NO.',docIndex
# print ''
errorCount += 1
# print "classification error",docList[docIndex]
# print 'the error rate is: ',float(errorCount)/len(testSet)
Accuracy_Rate = Accuracy_Rate+((1-float(errorCount)/len(testSet))*100)
print 'Accuracy Rate:%d%% '%((1-float(errorCount)/len(testSet))*100)
# print 'GoodToBad:', GoodToBad
# print 'BadToGood:', BadToGood
#return vocabList,fullText
if __name__ == "__main__":
for i in range(0,10):
spamTest()
print 'Accuracy_Rate',(Accuracy_Rate/10)
print 'BadToGood: ', (numBad2Good/10)
print 'GoodToBad: ', (numGood2Bad/10)
總結
- 對于手機惡意軟件的檢測熊痴,90%左右的概率離具體實用還差很多他爸。這篇文章主要就是記錄與分享下學習中經歷。
- 寫的時候側重了實現(xiàn)果善,更多的是給出了代碼诊笤。有興趣的朋友不妨親自體驗,至于惡意軟件沒有這個問題巾陕,在這里附上我除了過得樣本數(shù)據(jù)讨跟。
實驗數(shù)據(jù)下載 - 推薦一本書《機器學習實戰(zhàn)》Petet Harrington著,我的代碼是學習了這本書后改進利用到安卓APP檢測的鄙煤。
- 系列文章到此還沒結束晾匠,后面還會結合樸素貝葉斯和其他機器學習算法,提高檢測精確度馆类。
- 實在是表達能力不行混聊,講得不清楚見諒。還是那句話乾巧,有興趣的話不妨實際運行下程序句喜,再結合樸素貝葉斯算法就能理解了。