<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    基于LSTM的二進制代碼相似性檢測

    VSole2022-03-22 16:09:57

    前言

    近年來自然語言處理的快速發展,推出了一系列相關的算法和模型。比如用于處理序列化數據的RNN循環神經網絡、LSTM長短期記憶網絡、GRU門控循環單元網絡等,以及用于計算詞嵌入的word2vec、ELMo和BERT預訓練模型等。

    近幾年也出現了一些論文研究這些模型和算法在二進制代碼相似性分析上的應用,可以實現跨平臺的二進制代碼相似性檢測。本文根據上述模型和算法實現了一個基于word2vec和LSTM的簡單模型用于判斷兩個函數或者兩個指令序列是否相似。

    總體框架

    函數嵌入

    LSTM是RNN的一個變體,由于RNN容易梯度消失無法處理長期依賴的問題。LSTM在RNN的基礎上增加了門結構,分別是輸入門、輸出門和遺忘門,在一定程度上可以解決梯度消失的問題,學習長期依賴信息。LSTM的結構如下:

     

    運算規則如下:

    W和b都是LSTM待學習的參數,具體參數細節可以參考pytorch的官方文檔。

    指令嵌入

    指令嵌入的目的是也為了獲得指令的向量化表示,方便LSTM等其它模型進行計算。這里使用word2vec的skip-gram模型實現。word2vec是谷歌公司開源的一個用于計算詞嵌入的工具,包含cbow和skip-gram兩個模型。指令嵌入具體實現細節如下:

    (1)操作碼、寄存器、加減乘符號以及中括號都看成一個詞。比如mov dowrd ptr [0x123456+eax*4], ebx這條指令可以得到mov,dowrd,ptr,[,0x123456,+,eax,*,4,],ebx。然后這條指令看成一個句子送入word2vec進行訓練,進而得到每一個詞的向量化表示。

    (2)為了減小詞庫的大小。操作數中超過0x5000的數值用mem,disp,imm代替。

    [0xXXXXXXXX] -> [mem][0xXXXXXXXX + index*scale + base] -> [disp + index*scale + base]0xXXXXXXXX -> imm
    

    (3)指令向量由一個操作碼對應的向量和兩個操作數對應的向量三部分組成,操作數不夠的指令添加0向量補齊。對于超過兩個操作數的指令,則最后兩個操作數的向量求和取平均。操作數里面有多個詞的情況下,各個詞向量求和取平均表示當前操作數的向量。

    代碼實現

    模型的代碼實現用的是深度學習框架pytorch,word2vec的實現用的gensim庫。word2vec的調用參數在insn2vec.py實現如下:

    model = Word2Vec(tokensList, vector_size=wordDim, negative=15, window=5, min_count=1, workers=1, epochs=10, sg=1)   model.save('insn2vec.model')
    

    tokensList的元素是一個列表,保存的是一條指令分詞(tokenization)后的各個詞序列。word2vec訓練完成后保存到insn2vec.model文件,方便后續進行進一步的微調。

    指令嵌入的實現在lstm.py文件中,實現如下:

    class instruction2vec(nn.Module):    def __init__(self, word2vec_model_path:str):        super(instruction2vec, self).__init__()        word2vec = Word2Vec.load(word2vec_model_path)        self.embedding = nn.Embedding.from_pretrained(torch.from_numpy(word2vec.wv.vectors))        self.token_size = word2vec.wv.vector_size#維度大小        self.key_to_index = word2vec.wv.key_to_index.copy()    #dict        self.index_to_key = word2vec.wv.index_to_key.copy()    #list        del word2vec     def keylist_to_tensor(self, keyList:list):        indexList = [self.key_to_index[token] for token in keyList]        return self.embedding(torch.LongTensor(indexList))     def InsnStr2Tensor(self, insnStr:str) -> torch.tensor:        insnStr = RefineAsmCode(insnStr)        tokenList = re.findall('\w+|[\+\-\*\:\[\]\,]', insnStr)        opcode_tensor =  self.keylist_to_tensor(tokenList[0:1])[0]        op_zero_tensor = torch.zeros(self.token_size)        insn_tensor = None        if(1 == len(tokenList)):            #沒有操作數            insn_tensor = torch.cat((opcode_tensor, op_zero_tensor, op_zero_tensor), dim=0)        else:            op_token_list = tokenList[1:]            if(op_token_list.count(',') == 0):                #一個操作數                op1_tensor = self.keylist_to_tensor(op_token_list)                insn_tensor = torch.cat((opcode_tensor, op1_tensor.mean(dim=0), op_zero_tensor), dim=0)#tensor.mean求均值后變成一維             elif(op_token_list.count(',') == 1):                #兩個操作數                dot_index = op_token_list.index(',')                op1_tensor = self.keylist_to_tensor(op_token_list[0:dot_index])                op2_tensor = self.keylist_to_tensor(op_token_list[dot_index+1:])                insn_tensor = torch.cat((opcode_tensor, op1_tensor.mean(dim=0), op2_tensor.mean(dim=0)), dim=0)             elif(op_token_list.count(',') == 2):                #三個操作數                dot1_index = op_token_list.index(',')                dot2_index = op_token_list.index(',', dot1_index+1)                op1_tensor = self.keylist_to_tensor(op_token_list[0:dot1_index])                op2_tensor = self.keylist_to_tensor(op_token_list[dot1_index+1:dot2_index])                op3_tensor = self.keylist_to_tensor(op_token_list[dot2_index+1:])                 op2_tensor = (op2_tensor.mean(dim=0) + op3_tensor.mean(dim=0)) / 2                insn_tensor = torch.cat((opcode_tensor, op1_tensor.mean(dim=0), op2_tensor), dim=0)         if(None == insn_tensor):            print("error: None == insn_tensor")            raise         insn_size = insn_tensor.shape[0]        if(self.token_size * 3 != insn_size):            print("error: (token_size)%d != %d(insn_size)" % (self.token_size, insn_size))            raise         return insn_tensor  #[len(tokenList), token_size]     def forward(self, insnStrList:list) -> torch.tensor:        insnTensorList = [self.InsnStr2Tensor(insnStr) for insnStr in insnStrList]        return torch.stack(insnTensorList) #[insn_count, token_size]
    

    instruction2vec類的作用就是指令嵌入,token_size是詞的維度大小,指令維度的大小為token_size*3。初始過程中主要是加載word2vec訓練好的詞向量word2vec.wv.vectors,方便InsnStr2Tensor把字符串形式的指令轉換到向量。

    函數嵌入的代碼實現如下:

    class SiameseNet(nn.Module):    def __init__(self, hidden_size=60, n_layers=2, bidirectional = False):        super(SiameseNet, self).__init__()        self.insn_embedding = instruction2vec("./insn2vec.model")        input_size = self.insn_embedding.token_size * 3        #input_size為指令的維度, hidden_size為整個指令序列的維度        self.lstm = nn.LSTM(input_size, hidden_size, n_layers, batch_first=True, bidirectional = bidirectional)         self.D = int(bidirectional)+1         self.w_omega = nn.Parameter(torch.Tensor(hidden_size * self.D, hidden_size * self.D))        self.b_omega = nn.Parameter(torch.Tensor(hidden_size * self.D))        self.u_omega = nn.Parameter(torch.Tensor(hidden_size * self.D, 1))         nn.init.uniform_(self.w_omega, -0.1, 0.1)        nn.init.uniform_(self.u_omega, -0.1, 0.1)     def attention_score(self, x):        #x:[batch_size, seq_len, hidden_size*D]        u = torch.tanh(torch.matmul(x, self.w_omega))        #u:[batch_size, seq_len, hidden_size*D]        att = torch.matmul(u, self.u_omega)        #att:[batch_size, seq_len, 1]        att_score = F.softmax(att, dim=1)#得到每一個step的hidden權重        #att_score:[batch_size, seq_len, 1]        scored_x = x*att_score  #類似矩陣倍乘        return torch.sum(scored_x, dim=1)#加權求和     def forward_once(self, input:list) -> torch.tensor:        lengths = []#記錄每個指令序列的長度        out = []        for insnStrList in input:            insnVecTensor = self.insn_embedding(insnStrList)#把指令轉換到向量            out.append(insnVecTensor)            lengths.append(len(insnStrList))         pad_out = pad_sequence(out, batch_first=True)#填充0使所有handler的seq_len相同        pack_padded_out = pack_padded_sequence(pad_out, lengths, batch_first=True, enforce_sorted=False)        packed_out,(hn,_) = self.lstm(pack_padded_out)#input shape:[batch_size, seq_len, input_size]        #hn:[D*num_layers,batch_size,hidden_size]        #out:[batch_size, seq_len, hidden_size*D],此時out有一些零填充        out,lengths = pad_packed_sequence(packed_out, batch_first=True)        out = self.attention_score(out)        return out     def forward(self, input1, input2):        out1 = self.forward_once(input1)#out1:[batch_size,hidden_size]        out2 = self.forward_once(input2)        out = F.cosine_similarity(out1, out2, dim=1)        return out
    

    因為函數嵌入的輸入是一對函數,所以該模型也是一個共享參數的孿生神經網絡。hidden_size是函數的維度大小,這里設置成60維。attention_score對應的是注意力機制,w_omega是W矩陣,u_omega是U矩陣。pytorch的LSTM輸入類型為[batch_size, seq_len, input_size]的張量,相當于是一個batch_sizeseq_leninput_size的矩陣,batch_size對應是函數個數,seq_len對應的是指令的個數。

    雖然LSTM可以處理任意長度的序列,但是為了加速運算,pytorch的lstm輸入需要seq_len相同,所以需要添加0向量對齊。因為添加了0向量,對整個模型可能會有一定的影響。在經過W和H的點乘后,也就是torch.tanh(torch.matmul(x, self.w_omega))運算后需要一個特殊處理,需要把這些添加的0向量弄到負無窮大,這樣在注意力機制的softmax運算中會使這部分向量對應的權重趨近于0,也就是注意力不應該放在這些0向量身上。這個處理我沒有加,大家感興趣的話自己改一改。

    模型評估

    指令的向量維度為30,函數的向量維度為60。數據集使用了6個二進制文件:

    ntdll_7600_x64.dllntoskrnl_7600_x64.exewin32kfull_17134_x64.sysntdll_7600_x32.dllntoskrnl_7600_x32.exewin32kfull_17134_x32.sys
    

    x86和x64各三個文件,使用angr總共提取出4437個函數,函數名相同的x86和x64函數構成一個相似的正例。x86函數中隨機選取一個不同名的x64函數構造一個負例,或者x64函數中隨機選取一個不同名的x86函數構造一個負例。數據集樣本的正負比例為1:1,總的樣本數為4437*2,再按8:1:1劃分為訓練集、驗證集和測試集。其實正負樣本里應該還要加一些x86對應x86或者x64對應x64的正負樣本,使數據分布的更均勻些。隨機梯度下降法的學習率設置為0.09,批度大小8,迭代次數為50。

    前面兩張圖片分別是訓練集和驗證集隨著迭代次數的損失loss下降情況。可以看到根據訓練集的loss還沒收斂的情況下,驗證集的loss就已經收斂不怎么下降。再訓練下去的話,大概率是會過擬合(overfitting),主要原因還是數據太少了。

    第三張圖是ROC曲線,該曲線的AUC(Area Under Curve)為0.91,AUC越接近1越好。根據ROC曲線可以得出當兩個函數的余弦相似度的閾值設置0.24時,驗證集和測試集的準確度都可以達到84%。

    總結

    模型準確度達不到90%以上的主要原因還是數據量不夠,深度學習的核心在于足夠多且有效的數據量。其次word2vec無法處理一詞多義的問題,基于word2vec實現的指令嵌入,同樣的指令計算出同樣的向量化表示,即使有不同的上下文。比如有以下兩個指令序列:

    mov eax, [0x12345678]        add eax, [0x12345678]shl eax, 2                   shl eax, 2ret                          inc eax
    

    上述兩條shl eax, 2指令有不同的上下文,應需要不同的向量化表示。最后,函數的處理應以基本塊為單位,函數中的指令序列受控制流的影響不完全是順序執行,控制流圖的向量化表示可以引入一個圖神經網絡獲取。

    參考資料

    SAFE: Self-Attentive Function Embeddings for Binary Similarity;

    A simple function embedding approach for binary similarity detection;

    Understanding LSTM Networks

    word2veclstm
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    本文根據上述模型和算法實現了一個基于word2vecLSTM的簡單模型用于判斷兩個函數或者兩個指令序列是否相似。總體框架函數嵌入LSTM是RNN的一個變體,由于RNN容易梯度消失無法處理長期依賴的問題。
    從本專欄開始,作者正式研究Python深度學習、神經網絡及人工智能相關知識。一.RNN文本分類1.RNN循環神經網絡英文是Recurrent Neural Networks,簡稱RNN。假設有一組數據data0、data1、data2、data3,使用同一個神經網絡預測它們,得到對應的結果。RNN常用于自然語言處理、機器翻譯、語音識別、圖像識別等領域。本文將采用詞向量、TFIDF兩種方式進行實驗。
    機器學習模型對這種變化稱為概念漂移,使用舊數據訓練的模型在處理前所未見的新樣本時挑戰極大。為了構建有效且穩健的分類器,必須能夠檢測同一惡意軟件家族中漂移的 IoT 變種,并解釋漂移的成因。通過 VirusTotal 的分析報告,使用 AVClass 對其進行處理聚合家族歸屬。一共確定了 44 個 Mirai 的變種與 11 個 Gafgyt 的變種。相比 Gafgyt 來說,Mirai 的連接更為緊密。
    同時購買這兩種食品的消費者將會在墨西哥食品和亞洲食品集群之間形成一種嵌入。商店和客戶的行為定期訓練這類嵌入,以便在推薦和其他個性化應用程序中使用。
    6G移動通信網絡將通信的領域邊界從物理世界進一步拓展至數字世界,通過在物理世界和數字世界之間提供即時、高效和智能的超連接來重塑世界,這一趨勢將開啟移動通信的新篇章。6G網絡超大規模的全局性連接將給網絡的運營和管理帶來巨大挑戰,亟待革命性的理論和技術創新。
    一.文本分類文本分類旨在對文本集按照一定的分類體系或標準進行自動分類標記,屬于一種基于分類體系的自動分類。牛亞峰老師將傳統的文本分類流程歸納如下圖所示。在傳統的文本分類中,基本上大部分機器學習方法都在文本分類領域有所應用。本文將采用詞向量、TFIDF兩種方式進行實驗。
    https://capev2.readthedocs.io/en/latest/安全廠商沙箱二.基于邏輯回歸的惡意家族檢測前面的系列文章詳細介紹如何提取惡意軟件的靜態和動態特征,包括API序列。接下來將構建機器學習模型學習API序列實現分類。基本流程如下:1.數據集整個數據集包括5類惡意家族的樣本,每個樣本經過先前的CAPE工具成功提取的動態API序列。
    這篇技術干貨 帶你了解深信服的AI技術
    缺陷定位在軟件維護中起著重要的作用。目前有研究者基于CFG開展錯誤定位的研究,然而單純使用CFG作為源代碼的中間表示很難表達源代碼完整的語義。因為CFG中相鄰的節點在語義上可能完全不相關;而且位于CFG上方的節點會影響執行路徑上的后續節點的語義。在本文中,作者提出需要考慮流的特征,使用基于流的GRU從CFG中學習特征。基于流的GRU利用由CFG表示的程序結構來沿著執行路徑傳播語句的語義,很好地反映
    論文證明了利用僅有少量超參數的CNN在多個NLP任務上取得較好的成果;預訓練的向量是可用于各種分類任務的“通用”特征提取器。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类