一、安裝
官方文檔(含python調用yara):https://yara.readthedocs.io/en/v4.1.1/gettingstarted.html
開源yara規則庫:https://github.com/Yara-Rules/rules
git clone https://github.com/VirusTotal/yara.git cd yara ./bootstrap.sh ./configure make # 最后可以看到安裝到的路徑,不配置默認應該是/usr/local/bin sudo make install
二、規則的基本寫法
將如下結果保存為test_rule.yar:
/* 塊注釋 https://yara.readthedocs.io/en/v4.1.1/writingrules.html */ // 行注釋 // rule_name為設置的規則名 // rule_tag為規則標簽,方便后邊設置只啟用隸屬某個tag的規則集;可省略(冒號和tag一起) rule rule_name1 : rule_tag1 rule_tag2 { // 一條規則一般由strings + condition組成,meta節區可省略 // meta節區主要用於放置一些備注、規則說明,並不用於實際匹配 meta: rule_desc = "this just a rule comment." // 基礎規則一般有十六進制字符串、字符串、正則三種類型 strings: // 其中十六進字符串內也可以用正則,但匹配元素只能是十六進制字符 // $hex_string = { E2 34 A1 C? 23 FB } $text_string = "root" // 雖然yara不再使用PCRE庫,但支持的正則寫法和PCRE基本一致 // $re_string = /md5: [0-9a-fA-F]{32}/ // 配置條件。由基礎規則進行邏輯運算而得,運算結果為true則命中,為false則未命中 condition: $text_string } // 一個文件內可以寫多個規則,但rule_name不要重復 rule rule_name2 { // condition: false }
三、命令行使用
上邊我們寫了一個規則文件,按rule_name1這條規則的condition,只要被審查文件中出現“md5: 加空格 加一個md5值”的字符串就會命中。
我們來准備一個會命中和一個不會命中的文件,然后看實際如何使用yara及命不命中會是什么現像。
# 使用test_rule.yar中的規則去匹配/etc/passwd文件的內容 # /etc/passwd有root字符串,會打印出匹配的規則,即rule_name1 yara test_rule.yar /etc/passwd # 可以使用-s參數打印出具體匹配的位置 yara -s test_rule.yar /etc/passwd # /etc/profile沒有root字符串,沒有匹配的規則,什么都不會打印 yara test_rule.yar /etc/profile
四、通過python調用yara
python調用yara我們可以通過python執行系統命令的方式調用,但這種方式比較丑,建議還是通過作者提供的yara-python庫去調用(雖然我們還是得先安裝yara)。
pip install yara-python
4.1 匹配字符串
import yara # 編譯規則 # 當規則文件編寫有語法錯誤時,compile會報錯,但不會具體指出是哪一行出了什么錯 # 此時建議用命令行來查看具體錯誤。如yara ./test_rule.yar /etc/passwd rules = yara.compile(filepath='./test_rule.yar') # 使用data參數來指定要匹配的字符串 matches = rules.match(data="root:toor") # matches是一個匹配的規則名對象列表,形如[rule_name1] print(matches) # 對象屬性包括rule/namespace/tags/meta/strings print(f"{matches[0].rule}--{matches[0].strings}")
4.2 匹配文件
import yara # 編譯規則 # 當規則文件編寫有語法錯誤時,compile會報錯,但不會具體指出是哪一行出了什么錯 # 此時建議用命令行來查看具體錯誤。如yara ./test_rule.yar ./be_test_file1.txt rules = yara.compile(filepath='./test_rule.yar') # 匹配文件可以是文本文件 # 使用filepath來指定要進行匹配的文件,由於filepath是第一個參數所以也可以省略 matches = rules.match(filepath='/etc/passwd') # matches是一個命中的規則對象列表 print(matches) print(f"{matches[0].rule}--{matches[0].strings}") # 匹配文件也可以是二進制文件 # 使用filepath來指定要進行匹配的文件,由於filepath是第一個參數所以也可以省略 matches = rules.match('/usr/bin/passwd') print(matches) print(f"{matches[0].rule}--{matches[0].strings}")
4.3 即時處理
上邊的rules.match()返回的只是一個命中的規則對象列表,我們可以對他進行處理;但有時我們可能想完成一條規則匹配就進行處理,這可借助回調函數實現。
import yara # 編譯規則 rules = yara.compile(filepath="./test_rule.yar") # 回調函數,默認一 def match_callback(data): """ :param data: { 'matches': False, # 表示該條規則是否有匹配內容 'rule': 'rule_name2', # 該條規則規則名 'namespace': 'default', 'tags': [], # 該條規則所屬標簽 'meta': {}, # 該條規則的meta節區內容 'strings': [] # 該條規則匹配的內容列表 } :return: """ # 打印匹配信息 print(data) # 指示程序繼續進行 return yara.CALLBACK_CONTINUE # filepath--要進行匹配的文件。可以是文本文件,也可以是二進制文件 # callback--回調函數,默認匹配完一條規則回調一次 # which_callbacks--回調函數過濾參數,yara.CALLBACK_ALL(默認)、yara.CALLBACK_MATCHES(規則有匹配回調)、 # yara.CALLBACK_NON_MATCHES(規則不匹配時回調) matches = rules.match(filepath='/etc/passwd', callback=match_callback, which_callbacks=yara.CALLBACK_ALL) # 還是一樣,matches只是最終的匹配規則名列表 print(matches)