前言
Yara是一個能夠幫助惡意軟件研究人員識別和分類惡意軟件樣本的工具(類似正則表達式)。
規則可以通過文本或二進制的模式被創建,並且每個規則均由一組字符串和一個布爾表達式組成。

1 //示例規則 2 rule Test : Trojan 3 { 4 //規則描述 5 meta: 6 author = "Sunset" 7 date = "2020-04-08" 8 description = "Trojan Detection" 9 10 //規則字符串 11 strings: 12 $a = {6A 40 68 00 30 00 00 6A 14 8D 91} 13 $b = {8D 4D B0 2B C1 83 C0 27 99 6A 4E 59 F7 F9} 14 $c = "UVODFRYSIHLNWPEJXQZAKCBGMT" 15 16 //條件表達式 17 condition: 18 $a or $b or $c 19 }
編譯下載
項目:https://github.com/virustotal/yara
releases:https://github.com/VirusTotal/yara/releases

1 --atom - quality - table = FILE // 2 - C, --compiled - rules //加載編譯規則 3 - c, --count // 只打印命中的規則數量 4 - d, --define = VAR = VALUE //定義外部變量 5 --fail - on - warnings //失敗警告 6 - f, --fast - scan //快速匹配模式 7 - h, --help //顯示幫助並退出 8 - i, --identifier = IDENTIFIER // 匹配指定名稱的規則(使用指定名稱的規則進行匹配) 9 - l, --max - rules = NUMBER //匹配多個規則后中止掃描 10 --max - strings - per - rule = NUMBER //設置每個規則的最大字符串數量(默認 = 10000) 11 - x, --module - data = MODULE = FILE //將文件內容作為額外數據傳遞給模塊 12 - n, --negate // 只打印不匹配的規則 13 - w, --no - warnings //禁用警告 14 - m, --print - meta // 打印元數據(在命中結果中顯示:規則元數據) 15 - D, --print - module - data // 打印模塊數據(在命中結果中顯示:規則名稱與樣本名稱) 16 - e, --print - namespace //打印規則的名稱空間 17 - S, --print - stats //打印規則的統計信息 18 - s, --print - strings // 打印匹配的字符串 19 - L, --print - string - length //打印匹配的字符串長度(字符串在文件中的偏移與長度) 20 - g, --print - tags // 打印標簽(顯示命中規則的標簽) 21 - r, --recursive // 遞歸搜索目錄(匹配該目錄下的所有樣本文件) 22 - k, --stack - size = SLOTS //設置最大堆棧大小(默認值為16384) 23 - t, --tag = TAG // 匹配指定標簽的規則(使用指定規則標簽進行匹配,標簽區分大小寫) 24 - p, --threads = NUMBER //指定多少線程數來掃描目錄 25 - a, --timeout = SECONDS //指定多少秒后中止掃描 26 - v, --version //顯示版本信息
規則編寫
Yara規則語法類似於C語言,易於編寫和理解,每個規則都以關鍵字“rule”開頭,后面跟着一個規則標識符。
標識符必須遵循與C語言相同的詞法約定,它們可以包含任何字母數字和下划線,但第一個字符不能是數字。
規則標識符區分大小寫,並且不能超過128個字符。以下關鍵字是保留的,不能用作標識:
注釋
你可以像編寫C語言一樣,在Yara規則中添加注釋:

1 // 單行注釋 2 3 /* 4 多行注釋 5 */
字符串
Yara中有三種類型的字符串:
十六進制串:定義原始字節序列

1 //通配符:可以代替某些未知字節,與任何內容匹配 2 rule WildcardExample 3 { 4 strings: 5 //使用‘?’作為通配符 6 $hex_string = { 00 11 ?? 33 4? 55 } 7 8 condition: 9 $hex_string 10 } 11 12 //跳轉:可以匹配長度可變的字符串 13 rule JumpExample 14 { 15 strings: 16 //使用‘[]’作為跳轉,與任何長度為0-2字節的內容匹配 17 $hex_string1 = { 00 11 [2] 44 55 } 18 $hex_string2 = { 00 11 [0-2] 44 55 } 19 //該寫法與string1作用完全相同 20 $hex_string3 = { 00 11 ?? ?? 44 55 } 21 22 condition: 23 $hex_string1 and $hex_string2 24 } 25 26 //也可以使用類似於正則表達式的語法 27 rule AlternativesExample1 28 { 29 strings: 30 $hex_string = { 00 11 ( 22 | 33 44 ) 55 } 31 /* 32 可以匹配以下內容: 33 00 11 22 55 34 00 11 33 44 55 35 */ 36 37 condition: 38 $hex_string 39 } 40 41 //還可以將上面介紹的方法整合在一起用 42 rule AlternativesExample2 43 { 44 strings: 45 $hex_string = { 00 11 ( 33 44 | 55 | 66 ?? 88 ) 99 } 46 47 condition: 48 $hex_string 49 }
文本字符串:定義可讀文本的部分

1 //轉義符: 2 \" 雙引號 3 \\ 反斜杠 4 \t 制表符 5 \n 換行符 6 \xdd 十六進制的任何字節 7 8 //修飾符: 9 nocase: 不區分大小寫 10 wide: 匹配2字節的寬字符 11 ascii: 匹配1字節的ascii字符 12 xor: 匹配異或后的字符串 13 fullword:匹配完整單詞 14 private: 定義私有字符串 15 16 rule CaseInsensitiveTextExample 17 { 18 strings: 19 //不區分大小寫 20 $text_string = "foobar" nocase 21 //匹配寬字符串 22 $wide_string = "Borland" wide 23 //同時匹配2種類型的字符串 24 $wide_and_ascii_string = "Borland" wide ascii 25 //匹配所有可能的異或后字符串 26 $xor_string = "This program cannot" xor 27 //匹配所有可能的異或后wide ascii字符串 28 $xor_string = "This program cannot" xor wide ascii 29 //限定異或范圍 30 $xor_string = "This program cannot" xor(0x01-0xff) 31 //全詞匹配(匹配:www.domain.com 匹配:www.my-domain.com 不匹配:www.mydomain.com) 32 $wide_string = "domain" fullword 33 //私有字符串可以正常匹配規則,但是永遠不會在輸出中顯示 34 $text_string = "foobar" private 35 36 condition: 37 $text_string 38 }
正則表達式:定義可讀文本的部分
條件表達式
你可以在條件表達中使用如下運算符:
all any them

1 all of them // 匹配規則中的所有字符串 2 any of them // 匹配規則中的任意字符串 3 all of ($a*) // 匹配標識符以$a開頭的所有字符串 4 any of ($a,$b,$c) // 匹配a, b,c中的任意一個字符串 5 1 of ($*) // 匹配規則中的任意一個字符串
#

1 //===匹配字符串在文件或內存中出現的次數 2 rule CountExample 3 { 4 strings: 5 $a = "dummy1" 6 $b = "dummy2" 7 8 condition: 9 //a字符串出現6次,b字符串大於10次 10 #a == 6 and #b > 10 11 }
@

1 //可以使用@a[i],獲取字符串$a在文件或內存中,第i次出現的偏移或虛擬地址 2 //小標索引從1開始,並非0 3 //如果i大於字符串出現的次數,結果為NaN(not a number 非數值)
!

1 //可以使用!a[i],獲取字符串$a在文件或內存中,第i次出現時的字符串長度 2 //下標索引同@一樣都是從1開始 3 //!a 是 !a[1]的簡寫
at

1 //===匹配字符串在文件或內存中的偏移 2 rule AtExample 3 { 4 strings: 5 $a = "dummy1" 6 $b = "dummy2" 7 8 condition: 9 //a和b字符串出現在文件或內存的100和200偏移處 10 $a at 100 and $b at 200 11 }
in

1 //===在文件或內存的某個地址范圍內匹配字符串 2 rule InExample 3 { 4 strings: 5 $a = "dummy1" 6 $b = "dummy2" 7 8 condition: 9 $a in (0..100) and $b in (100..filesize) 10 }
filesize

1 //===使用關鍵字匹配文件大小 2 rule FileSizeExample 3 { 4 condition: 5 //filesize只在文件時才有用,對進程無效 6 //KB MB后綴只能與十進制大小一起使用 7 filesize > 200KB 8 }
entrypoint

1 //===匹配PE或ELF文件入口點(高版本請使用PE模塊的pe.entry_point代替) 2 rule EntryPointExample1 3 { 4 strings: 5 $a = { E8 00 00 00 00 } 6 7 condition: 8 $a at entrypoint 9 } 10 11 rule EntryPointExample2 12 { 13 strings: 14 $a = { 9C 50 66 A1 ?? ?? ?? 00 66 A9 ?? ?? 58 0F 85 } 15 16 condition: 17 $a in (entrypoint..entrypoint + 10) 18 }
intxxx uintxxx

1 //===從指定的文件或內存偏移處讀取數據 2 //小端: 有符號整數 3 int8(<offset or virtual address>) 4 int16(<offset or virtual address>) 5 int32(<offset or virtual address>) 6 7 //小端: 無符號整數 8 uint8(<offset or virtual address>) 9 uint16(<offset or virtual address>) 10 uint32(<offset or virtual address>)
intxxxbe uintXXXbe

1 //大端: 有符號整數 2 int8be(<offset or virtual address>) 3 int16be(<offset or virtual address>) 4 int32be(<offset or virtual address>) 5 6 //大端: 無符號整數 7 uint8be(<offset or virtual address>) 8 uint16be(<offset or virtual address>) 9 uint32be(<offset or virtual address>) 10 11 //應用示例 12 rule IsPE 13 { 14 condition: 15 //判斷是否PE文件 16 uint16(0) == 0x5A4D and 17 uint32(uint32(0x3C)) == 0x00004550 18 }
of

1 //===匹配多個字符串中的某幾個 2 rule OfExample1 3 { 4 strings: 5 $a = "dummy1" 6 $b = "dummy2" 7 $c = "dummy3" 8 9 condition: 10 //3個字符串只需匹配任意2個 11 2 of ($a,$b,$c) 12 }
for xxx of xxx :(xxx)

1 //功能: 2 對多個字符串匹配相同的條件 3 //格式: 4 for AAA of BBB : ( CCC ) 5 //含義: 6 在BBB字符串集合中,至少有AAA個字符串,滿足了CCC的條件表達式,才算匹配成功。 7 在CCC條件表達式中,可以使用'$'依次代替BBB字符串集合中的每一個字符串。 8 9 //for..of其實就是of的特別版,所以下面2個例子作用相同 10 any of ($a,$b,$c) 11 for any of ($a,$b,$c) : ( $ ) 12 13 //在abc3個字符串集合中,至少有1個字符串,必須滿足字符串內容與entrypoint相同的條件 14 for 1 of ($a,$b,$c) : ( $ at entrypoint ) 15 for any of ($a,$b,$c) : ( $ at entrypoint ) 16 17 //所有字符串,在文件或內存中出現的次數必須大於3,才算匹配成功。 18 for all of them : ( # > 3 ) 19 20 //所有以$a開頭的字符串,在文件或內存中第2次出現的位置必須小於9 21 for all of ($a*) : (@[2] < 0x9)
for xxx i in (xxx) :(xxx)

1 //格式: 2 for AAA BBB in (CCC) : (DDD) 3 //含義: 4 作用與for of類似,只是增加了下標變量與下標范圍,具體看示例 5 6 //$b在文件或內存中出現的前3次偏移,必須與$a在文件或內存中出現的前3次偏移+10相同 7 for all i in (1,2,3) : ( @a[i] + 10 == @b[i] ) 8 for all i in (1..3) : ( @a[i] + 10 == @b[i] ) 9 10 //$a每次在文件或內存中出現位置,都必須都小於100 11 for all i in (1..#a) : ( @a[i] < 100 ) 12 13 //其它示例 14 for any i in (1..#a) : ( @a[i] < 100 ) 15 for 2 i in (1..#a) : ( @a[i] < 100 )
引用其它規則

1 rule Rule1 2 { 3 strings: 4 $a = "dummy1" 5 6 condition: 7 $a 8 } 9 10 rule Rule2 11 { 12 strings: 13 $a = "dummy2" 14 15 condition: 16 $a and Rule1 17 }
全局規則

1 //全局規則(global rule)可以在匹配其他規則前優先篩選, 2 //比如在匹配目標文件之前需要先篩選出小於2MB的文件,在匹配其他規則 3 global rule SizeLimit 4 { 5 condition: 6 filesize < 2MB 7 }
私有規則

1 //私有規則(private rule)可以避免規則匹配結果的混亂, 2 //比如使用私有規則進行匹配時,YARA不會輸出任何匹配到的私有規則信息 3 //私有規則單獨使用意義不大,一般可以配合"引用其它規則"的功能一起使用 4 //私有規則也可以和全局規則一起使用,只要添加“Private”、“global”關鍵字即可 5 private rule PrivateRuleExample 6 { 7 ... 8 }
規則標簽

1 //規則標簽,可以讓你在YARA輸出的時候只顯示你感興趣的規則,而過濾掉其它規則的輸出信息 2 //你可以為規則添加多個標簽 3 rule TagsExample1 : Foo Bar Baz 4 { 5 ... 6 } 7 8 rule TagsExample2 : Bar 9 { 10 ... 11 }
導入模塊

1 //使用“import”導入模塊 2 //你可以自己編寫模塊,也可以使用官方或其它第三方模塊 3 //導入模塊后,就可以開始使用模塊導出的變量或函數 4 import "pe" 5 import "cuckoo" 6 7 pe.entry_point == 0x1000 8 cuckoo.http_request(/someregexp/)
外部變量

1 //外部變量允許你在使用YARA -d命令時指定一個自定義數據, 2 //該數據可以是整數、字符串、布爾變量,具體看以下示例 3 4 //使用布爾變量和一個整數變量作為判斷條件 5 rule ExternalVariableExample2 6 { 7 condition: 8 bool_ext_var or filesize < int_ext_var 9 } 10 11 //字符串變量可以與以下運算符一起使用: 12 contains:如果字符串包含指定的子字符串,返回True 13 matches: 如果字符串匹配給定的正則表達式時,返回True 14 15 rule ExternalVariableExample3 16 { 17 condition: 18 string_ext_var contains "text" 19 } 20 21 rule ExternalVariableExample4 22 { 23 condition: 24 string_ext_var matches /[a-z]+/ 25 }
文件包含

1 //作用於C語言一樣,可以包含其它規則到當前文件中 2 include "other.yar" 3 4 //相對路徑 5 include "./includes/other.yar" 6 include "../includes/other.yar" 7 8 //全路徑 9 include "/home/plusvic/yara/includes/other.yar"
參考資料
https://github.com/virustotal/yara
https://github.com/Yara-Rules/rules
https://yara.readthedocs.io/en/stable/
https://github.com/InQuest/awesome-yara
https://bbs.pediy.com/thread-226011.htm