编写 YARA 规则 — yara 4.2.0 文档 YARA规则易于编写和理解,并且它们的语法是 类似于 C 语言。这是您可以编写的最简单的规则 YARA,它什么都不做: rule dummy{condition:false}
一、规则标识符
每个规则都以关键字“ rule”开头,后面跟着一个规则标识符。标识符必须遵循与C语言相同的词法约定,标识符命名有如下要求:
- 英文字母、数字、下划线组成的字符串
- 第一个字符不能是数字
- 对大小写敏感
- 不能超出128个字符长度
以下关键字是保留的,不能用作规则标识符:
二、注释
// 单行注释
/* 多行注释
*/ 三、字符串
Yara中有三种类型的字符串:
3.1、十六进制字符串
定义原始字节序列
// 通配符?:可以代替某些未知字节,与任何内容匹配 rule WildcardExample{strings:// 使用‘?’作为通配符$hex_string = { 00 11 ?? 33 4? 55 }condition:$hex_string}
这个规则可以匹配下面的两个字符串:
00 11 01 33 43 55 00 11 AA 33 4N 55
// 跳转:可以匹配长度可变的字符串 rule JumpExample {strings:// 使用‘[]’作为跳转,与任何长度为0-2字节的内容匹配$hex_string1 = { 00 11 [2] 44 55 }$hex_string2 = { 00 11 [0-2] 44 55 }// 该写法与string1作用完全相同$hex_string3 = { 00 11 ?? ?? 44 55 }condition:$hex_string1 and $hex_string2} 这个规则可以匹配下面的两个字符串: 00 11 01 22 44 55 00 11 AA 44 55
// 匹配无限长的字符串 rule BuzzLightyear{strings:$hex_string = { F4 23 [-] 62 B4 }condition:$hex_string} 这个规则可以匹配下面的两个字符串: F4 23 AA FF 62 B4 F4 23 AA AA AA AA AA...FF FF 62 B4
// 也可以使用类似于正则表达式的语法 rule AlternativesExample1{strings:$hex_string = { 00 11 ( 22 | 33 44 ) 55 }condition:$hex_string} 可以匹配以下内容
: 00 11 22 55 00 11 33 44 55
// 还可以将上面介绍的方法整合在一起用 rule AlternativesExample2 {strings:$hex_string = { 00 11 ( 33 44 | 55 | 66 ?? 88 ) 99 }condition:$hex_string} 这个规则可以匹配下面的三个字符串: 00 11 33 44 99 00 11 55 99 00 11 66 AG 88 99
3.2、文本字符串
定义可读文本的部分。
转义符: \" 双引号 \\ 反斜杠 \t 制表符 \n 换行符 \xdd 十六进制的任何字节
修饰符: nocase: 不区分大小写 wide: 匹配2字节的宽字符, 这种
宽字符串在许多二进制文件中都有出现 ascii: 匹配1字节的ascii字符 xor: 匹配异或后的字符串 fullword: 匹配完整单词,用于匹配那些前后没有附加其他字符的单词 private: 定义私有字符串 rule CaseInsensitiveTextExample{strings:// 不区分大小写$text_string = "foobar" nocase// 匹配宽字符串$wide_string = "Borland" wide// 同时匹配2种类型的字符串$wide_and_ascii_string = "Borland" wide ascii// 匹配所有可能的异或后字符串$xor_string = "This program cannot" xor// 匹配所有可能的异或后wide ascii字符串$xor_string = "This program cannot" xor wide ascii// 限定异或范围$xor_string = "This program cannot" xor(0x01-0xff)// 全词匹配(匹配:www.domain.com 匹配:www.my-domain.com 不匹配:www.mydomain.com)$wide_string = "domain" fullword// 私有字符串可以正常匹配规则,但是永远不会在输出中显示$text_string = "foobar" privatecondition:$text_string}
3.3、正则表达式
定义可读文本的部分。 yara规则允许使用正则表达式, 不过要用正斜杠而非双引号括起来使用(像Perl编程那样) rule RegularShow{strings:$re1 = /md5: [0-9a-fA-F]{32}/$re2 = /state: (on|off)/condition:$re1 and $re2} 该规则将捕获任何状态下找到的所有md5字符串。 你也可以在正则表达式中使用文本修饰符, 如nocase,ascii,wide和fullword。
四、条件表达式
你可以在条件表达中使用如下运算符:
all any them
all of them // 匹配规则中的所有字符串 any of them // 匹配规则中的任意字符串 all of ($a*) // 匹配标识符以$a开头的所有字符串 any of ($a,$b,$c) // 匹配a, b,c中的任意一个字符串 1 of ($*) // 匹配规则中的任意一个字符串
#
// 匹配字符串在文件或内存中出现的次数 rule CountExample
{ strings
: $a
= "dummy1" $b
= "dummy2" condition
: //a字符串出现6次,b字符串大于10次 #a == 6 and #b > 10
} @
//可以使用@a[i],获取字符串$a在文件或内存中,第i次出现的偏移或虚拟地址 //小标索引从1开始,并非0 //如果i大于字符串出现的次数,结果为NaN(not a number 非数值)
!
//可以使用!a[i],获取字符串$a在文件或内存中,第i次出现时的字符串长度 //下标索引同@一样都是从1开始 //!a 是 !a[1]的简写
at
// 匹配字符串在文件或内存中的偏移 rule AtExample
{ strings
: $a
= "dummy1" $b
= "dummy2" condition
: // a和b字符串出现在文件或内存的100和200偏移处 $a at 100
and $b at 200
} in
// 在文件或内存的某个地址范围内匹配字符串 rule InExample
{ strings
: $a
= "dummy1" $b
= "dummy2" condition
: $a
in (0..100
) and $b
in (100..filesize
) } filesize
// 使用关键字匹配文件大小 rule FileSizeExample
{ condition
: // filesize只在文件时才有用,对进程无效
// KB MB后缀只能与十进制大小一起使用 filesize
> 200KB
} entrypoint
// 匹配PE或ELF文件入口点
(高版本请使用PE模块的pe
.entry_point代替
) rule EntryPointExample1
{ strings
: $a
= { E8 00 00 00 00
} condition
: $a at entrypoint
} rule EntryPointExample2
{ strings
: $a
= { 9C 50 66 A1
?? ?? ?? 00 66 A9
?? ?? 58 0F 85
} condition
: $a
in (entrypoint
..entrypoint
+ 10
) } of
// 匹配多个字符串中的某几个 rule OfExample1
{ strings
: $a
= "dummy1" $b
= "dummy2" $c
= "dummy3" condition
: // 3个字符串只需匹配任意2个 2 of
($a
,$b
,$c
) } for xxx of xxx :(xxx)
功能:对多个字符串匹配相同的条件 格式:
for AAA of BBB
: ( CCC
) 含义: 在BBB字符串集合中,至少有AAA个字符串,满足了CCC的条件表达式,才算匹配成功。 在CCC条件表达式中,可以使用'$'依次代替BBB字符串集合中的每一个字符串。
// for..of其实就是of的特别版,所以下面2个例子作用相同
any of
($a
,$b
,$c
) for any of
($a
,$b
,$c
) : ( $
) // 在abc这3个字符串集合中,至少有1个字符串,必须满足字符串内容与entrypoint相同的条件。$表示集合中的所有字符串. 本例中, 它是字符串$a, $b和$c.
for 1 of
($a
,$b
,$c
) : ( $ at entrypoint
) for any of
($a
,$b
,$c
) : ( $ at entrypoint
) // 所有字符串,在文件或内存中出现的次数必须大于3,才算匹配成功。
for all of them
: ( # > 3
) // 所有以$a开头的字符串,在文件或内存中第2次出现的位置必须小于9
for all of
($a
*) : (@[2
] < 0x9
) 引用其它规则
rule Rule1
{ strings
: $a
= "dummy1" condition
: $a
} rule Rule2
{ strings
: $a
= "dummy2" condition
: $a and Rule1
} 全局规则
// 全局规则(
global rule)可以在匹配其他规则前
优先筛选,
// 比如在匹配目标文件之前需要先筛选出小于2MB的文件,在匹配其他规则
global rule SizeLimit
{ condition
: filesize
< 2MB
} 私有规则
//私有规则(private rule)可以避免规则匹配结果的混乱,
//比如使用私有规则进行匹配时,YARA不会输出任何匹配到的私有规则信息
//私有规则单独使用意义不大,一般可以配合"引用其它规则"的功能一起使用。比如为了判断文件是否恶意, 有这样一条私有规则, 要求文件必须是ELF文件. 一旦满足这个要求, 随后就会执行下一条规则. 但我们在输出里想看的并不是该文件它是不是ELF, 我们只想知道文件是否恶意, 那么私有规则就派上用场了.
//私有规则也可以和全局规则一起使用,只要添加“Private”、“
global”关键字即可 private rule PrivateRuleExample
{ ... } 规则标签
// 规则标签,
可以让你在YARA输出的时候只显示你感兴趣的规则,而过滤掉其它规则的输出信息(yara -t tagname
) // 你可以为规则添加多个标签 rule TagsExample1
: Foo Bar Baz { ... } rule TagsExample2
: Bar { ... } 导入模块
// 使用“
import”导入模块
// 你可以自己编写模块,也可以使用官方或其它第三方模块
// 导入模块后,就可以开始使用模块导出的变量或函数
import "pe"
import "cuckoo" pe
.entry_point
== 0x1000 cuckoo
.http_request
(/someregexp
/) 外部变量
// 外部变量允许你在使用YARA
-d命令时指定一个自定义数据,
// 外部变量可以是int, str或boolean类型
// ext_var是一个外部变量, 它在运行时会分配有一个值 rule ExternalVariableExample2
{ condition
: ext_var == 10
} /* 外部变量可以和操作符contains和matches一起使用 contains:如果字符串包含指定的子字符串,返回True matches: 如果字符串匹配给定的正则表达式时,返回True */ rule ExternalVariableExample3
{ condition
: string_ext_var contains "text"
} rule ExternalVariableExample4
{ condition
: string_ext_var matches
/[a
-z
]+/ } // 也可以将matches操作符和正则表达式一起使用 rule ExternalVariableExample5
{ condition
: // [a-z]+/is中的i表示匹配时不区分大小写. s表示是在单行(single line)模式 string_ext_var matches
/[a
-z
]+/is } 文件包含
// 作用于C语言一样,可以包含其它规则到当前文件中 include "other.yar"
// 相对路径 include "./includes/other.yar" include "../includes/other.yar"
// 全路径 include "/home/plusvic/yara/includes/other.yar"
五、参考
编写 YARA 规则 — yara 4.2.0 文档