• 我们在哪一颗星上见过 ,以至如此相互思念 ;我们在哪一颗星上相互思念过,以至如此相互深爱
  • 我们在哪一颗星上分别 ,以至如此相互辉映 ;我们在哪一颗星上入睡 ,以至如此唤醒黎明
  • 认识世界 克服困难 洞悉所有 贴近生活 寻找珍爱 感受彼此

恶意代码技术理论:YARA规则

恶意代码技术理论 云涯 3年前 (2021-06-27) 2967次浏览

官方网址:https://yara.readthedocs.io/

github地址:https://github.com/VirusTotal/yara/releases

1 概述

YARA 是一种旨在(但不限于)帮助恶意软件研究人员识别和分类恶意软件样本的工具。使用 YARA,您可以基于文本或二进制模式创建恶意软件系列(或任何您想描述的内容)的描述。每个描述,也就是规则,由一组字符串和一个确定其逻辑的布尔表达式组成。

举例:任何包含三个字符串之一的文件都必须报告为 Silent_banker

rule silent_banker : banker
{
    meta:
        description = "This is just an example"
        threat_level = 3
        in_the_wild = true
    strings:
        $a = {6A 40 68 00 30 00 00 6A 14 8D 91}
        $b = {8D 4D B0 2B C1 83 C0 27 99 6A 4E 59 F7 F9}
        $c = "UVODFRYSIHLNWPEJXQZAKCBGMT"
    condition:
        $a or $b or $c
}

1.1 yara支持的格式

字符串格式:$my_text_string = “text here”

十六进制格式:$my_hex_string = { E2 34 A1 C8 23 FB }

正则表达式格式:$re1 = /md5: [0-9a-fA-F]{32}/

2 YARA规则

YARA 中的每条规则都以关键字开头,rule 后跟规则标识符。

标识符必须遵循与 C 编程语言相同的词汇约定,它们可以包含任何字母数字字符和下划线字符,但第一个字符不能是数字规则标识符区分大小写,不能超过 128 个字符。

规则通常由两部分组成:字符串定义和条件。

如果规则不依赖于任何字符串,则可以省略字符串定义部分,但始终需要条件部分。字符串定义部分是定义将成为规则一部分的字符串的地方。

2.1 字符串定义部分

每个字符串都有一个标识符,由 $ 字符后跟一系列字母数字字符和下划线组成,这些标识符可用于条件部分以引用相应的字符串。例如$a = {6A 40 68 00 30 00 00 6A 14 8D 91}

字符串可以以文本或十六进制形式定义,例如:

$my_text_string = “text here”

$my_hex_string = { E2 34 A1 C8 23 FB }

2.2 条件定义部分

条件部分是规则逻辑所在的地方。该部分必须包含一个布尔表达式,说明在何种情况下文件或进程满足规则。

通常,条件将通过使用它们的标识符来引用先前定义的字符串。在这种情况下,字符串标识符充当布尔变量,如果在文件或进程内存中找到字符串,则该变量评估为真,否则为假。

例如:

condition:

$my_text_string or $my_hex_strins

2.3 注释

单行://

多行:/* */

2.4 字符串

YARA 中有三种类型的字符串:

  • 十六进制字符串
  • 文本字符串
  • 正则表达式。

2.4.1 十六进制字符串

十六进制字符串允许使用三种特殊结构:

  • 通配符:放入字符串中的占位符,表明某些字节是未知的,它们应该匹配任何内容。占位符是问号 (?),例如:$hex_string = { E2 34 ?? C8 A? FB }
  • 跳转:不知道长度时,使用跳转。例如:$hex_string = { F4 23 [4-6] 62 B4 }。这个跳转表示任何 4 到 6 个字节的任意序列都可以占据跳转的位置。任何跳转 [XY] 都必须满足条件 0 <= X <= Y。

将匹配以下:

F4 23 01 02 03 04 62 B4
F4 23 00 00 00 00 00 62 B4
F4 23 15 82 A3 04 45 22 62 B4

FE 39 45 [6-6] 89 00 等于  FE 39 45 ?? ?? ?? ?? ?? ?? 89 00

FE 39 45 [10] 89 00  10-无穷大

FE 39 45 [] 89 00      0-无穷大

  • 替代:十六进制有不同的替代方案。例如:$hex_string = { F4 23 ( 62 B4 | 56 ) 45 }

 

2.4.2 文本字符串

例如: $text_string = “foobar”

可以包括:ASCII 编码、区分大小写的字符串

文本字符串可以附带一些有用的修饰符,这些修饰符可以改变字符串的解释方式。这些修饰符附加在由空格分隔的字符串定义的末尾,如下所述。

\" 双引号
\\ 反斜杠
\r 回车
\t Tab
\n 换行
\xdd 十六进制表示法中的任何字节

2.4.2.1 不区分大小写的字符串

YARA 中的文本字符串默认区分大小写,但是您可以通过nocase在字符串定义的末尾附加修饰符来将字符串转换为不区分大小写的模式

例如: $text_string = “foobar” nocase

2.4.2.2 宽字符串

该wide修改器可以用于搜索与每个字符两个字节,事中许多可执行二进制码典型的编码字符串。

如果您想同时搜索 ASCII 和宽格式的字符串,您可以将ascii修饰符与wide结合使用,例如:$wide_and_ascii_string = “Borland” wide ascii

2.4.2.3 异或字符串

xor关键字可以搜索该字符串的异或,例如:$xor_string = “This program cannot” xor,搜索“This program cannot”的明文以及,每个单字节异或后结果。

以上就等效于:

$xor_string_00 = “This program cannot”

$xor_string_01 = “Uihr!qsnfs`l!b`oonu”

$xor_string_02 = “Vjkq\”rpmepco\”acllmv”

甚至可以结合使用:

$xor_string = “This program cannot” xor wide ascii

如果要设定范围,则: $xor_string = “This program cannot” xor(0x01-0xff)=》在搜索时将从 0x01 到 0xff 的字节应用到字符串中。

2.4.2.4 Base64字符串

base64关键字搜索该字符串base64后的结果。

例如:$a = “This program cannot” base64

会搜索三排

VGhpcyBwcm9ncmFtIGNhbm5vd
RoaXMgcHJvZ3JhbSBjYW5ub3
UaGlzIHByb2dyYW0gY2Fubm90

2.4.2.5 搜索完整词

修饰符fullword,保证字符串仅在出现在由非字母数字字符分隔的文件中时才匹配。

例如将domain定义为fullword,则在www.mydomain.com中无法匹配,以为不是以非字母分割的,但是在www.my-domain.com和www.domain.com中匹配。

2.4.3 正则表达式

正则表达式用”/”括起来,例如$re1 = /md5: [0-9a-fA-F]{32}/

$re2 = /state: (on|off)/

正则表达式还可以接着nocase,ascii,wide,和fullword修饰就像在文本字符串。这些修饰符的语义在两种情况下都是相同的。
\ 引用下一个元字符
^ 匹配文件的开头
$ 匹配文件末尾
| 交替
() 分组
[] 带括号的字符类
* 匹配 0 次或多次
+ 匹配 1 次或多次
? 匹配 0 或 1 次
{n} 完全匹配 n 次
{n,} 至少匹配 n 次
{,m} 最多匹配 m 次
{n,m} 匹配 n 到 m 次
*? 匹配 0 次或多次,非贪婪
+? 匹配 1 次或多次,非贪婪
?? 匹配 0 次或 1 次,非贪婪
{n}? 精确匹配 n 次,非贪婪
{n,}? 匹配至少 n 次,非贪婪
{,m}? 最多匹配 m 次,非贪婪
{n,m}? 匹配 n 到 m 次,非贪婪
\t 标签 (HT, TAB)
\n 新线 (LF, NL)
\r 返回 (CR)
\f 换页 (FF)
\a 警钟
\xNN 序数为给定十六进制数的字符
\w 匹配一个单词字符(字母数字加“_”)
\W 匹配一个非单词字符
\s 匹配一个空白字符
\S 匹配一个非空白字符
\d 匹配一个十进制数字字符
\D 匹配一个非数字字符
\b 匹配单词边界
\B 除了在单词边界处匹配

2.4.4 私有字符串

YARA 中的所有字符串都可以标记为private,这意味着它们永远不会包含在 YARA 的输出中。
例如:$text_string = “foobar” private

2.4.5 字符串修饰符总结

关键词 支持的字符串类型 概括 限制
nocase 文本,正则表达式 忽略大小写 不能与xor、base64、 或base64wide一起使用
wide 文本,正则表达式 通过交错空 (0x00) 字符来模拟 UTF16
ascii 文本,正则表达式 匹配 ASCII 字符,仅在wide使用时才需要
xor 文本 匹配具有单字节键的 XOR 文本字符串 不能与nocase、base64、 或base64wide一起使用
base64 文本  base64 编码的字符串(分割成3条) 不能与nocase、xor、 或fullword一起使用
base64wide 文本  base64 编码的字符串(分割成3条),然后交错空字符,如 wide 不能与nocase、xor、 或fullword一起使用
fullword 文本,正则表达式 匹配前后没有字母数字挨着的字符(串) 不能与base64或一起使用base64wide一起使用
private 十六进制、文本、正则表达式 匹配不包含在输出中

2.5 适应性

所有运算符的优先级如下:
优先级 操作 描述 性质
1

[]

.

Array subscripting   数组下标

Structure member access  结构成员访问

从左到右
2

~

Unary minus  按位减

Bitwise not  按位非

从右到左
3

*

\

%

Multiplication  乘法

Division  除法

Remainder  取余

从左到右
4

+

Addition  加法

Subtraction  减法

从左到右
5

<<

>>

Bitwise left shift  按位左移

Bitwise right shift  按位右移

从左到右
6 & Bitwise AND  按位与 从左到右
7 ^ Bitwise XOR  按位异或 从左到右
8 | Bitwise OR  按位或 从左到右
9

<

<=

>

>=

Less than  小于

Less than or equal to  小于等于

Greater than  大于

Greater than or equal to  大于等于

从左到右
10

==

!=

contains

icontains

startswith

istartswith

endswith

iendswith

matches

Equal to  等于

Not equal to  不等于

String contains substring  包含

Like contains but case-insensitive  包含不区分大小写

String starts with substring  以开始字符串

Like startswith but case-insensitive 以开始字符串不区分大小写

String ends with substring  以结尾字符串

Like endswith but case-insensitive  以结尾字符串区分大小写

String matches regular expression  正则表达式

从左到右
11 not Logical NOT  逻辑非 从右到左
12 and Logical AND  逻辑与 从左到右
13 or Logical OR  逻辑或 从左到右

例如:

rule Example
{
    strings:
        $a = "text1"
        $b = "text2"
        $c = "text3"
        $d = "text4"

    condition:
        ($a or $b) and ($c or $d)
}

2.5.1 字符串计数

有时候我们不仅需要知道字符串是否存在,还需要知道该字符串在文件或进程内存中出现了多少次。
每个字符串出现的次数由一个变量表示,该变量的名称是字符串标识符,但用 # 字符代替 $ 字符。
例如:字符串$a正好匹配6次,$b出现十次以上
rule CountExample
{
    strings:
        $a = "dummy1"
        $b = "dummy2"

    condition:
        #a == 6 and #b > 10
}

2.5.2 字符串偏移或虚拟地址

某个字符串在文件或进程的某个位置,用关键字at
例如:$a是否在文件100或者虚拟地址100处,以及 $b是否在文件100或者虚拟地址100处
rule AtExample
{
    strings:
        $a = "dummy1"
        $b = "dummy2"

    condition:
        $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)
}
$a必须位于0-100偏移处,$b必须位于100-文件末尾偏移处
还可以使用@a[i] 获取字符串 $a 第 i 次出现的偏移量或虚拟地址。所以第一次出现是@a[1],第二次是@a[2],依此类推。如果您提供的索引大于字符串出现的次数,则结果将为 NaN(非数字)值。

2.5.3 匹配长度

使用字符 ! 将匹配的长度用作条件的一部分。!a[1] 是 $a 第一次匹配的长度,!a[2] 是第二次匹配的长度,依此类推。!a 是 !a[1] 的缩写形式。

2.5.4 文件大小

关键字filesize是字符串大小,例如:
rule FileSizeExample
{
    condition:
        filesize > 200KB
}
该规则只能适用于文件,不能适用于进程。在进程中永远不会匹配。

2.5.5 可执行入口点

关键字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)
}
pe.entry_point规则中变量的存在意味着只有 PE 文件才能满足该规则。如果文件不是 PE ,则使用此变量的任何规则的计算结果为 false。

2.5.6 访问给定位置的数据

使用以下函数从给定偏移量的文件中读取数据:
int8(<offset or virtual address>)
int16(<offset or virtual address>)
int32(<offset or virtual address>)

uint8(<offset or virtual address>)
uint16(<offset or virtual address>)
uint32(<offset or virtual address>)

int8be(<offset or virtual address>)
int16be(<offset or virtual address>)
int32be(<offset or virtual address>)

uint8be(<offset or virtual address>)
uint16be(<offset or virtual address>)
uint32be(<offset or virtual address>)
这些intXX函数从 <offset or virtual address> 读取 8、16 和 32 位有符号整数,而函数则uintXX读取无符号整数。
16 位和 32 位整数都被认为是小端的。如果要读取大端整数,请使用以be. <offset or virtual address> 参数可以是任何返回无符号整数的表达式,包括uintXX函数本身的返回值
例如:
rule IsPE
{
    condition:
        // MZ signature at offset 0 and ...
        uint16(0) == 0x5A4D and
        // ... PE signature at offset stored in MZ header at 0x3C
        uint32(uint32(0x3C)) == 0x00004550
}

2.5.7 字符串集

关键字of代表至少包含
例如:字符串 ($a,$b,$c) 中至少有两个必须存在于文件中,但哪两个都无关紧要。
rule OfExample1
{
    strings:
        $a = "dummy1"
        $b = "dummy2"
        $c = "dummy3"

    condition:
        2 of ($a,$b,$c)
}
也可以使用通配符指定,例如:
rule OfExample2
{
    strings:
        $foo1 = "foo1"
        $foo2 = "foo2"
        $foo3 = "foo3"

    condition:
        2 of ($foo*)  // equivalent to 2 of ($foo1,$foo2,$foo3)
}
rule OfExample3
{
    strings:
        $foo1 = "foo1"
        $foo2 = "foo2"

        $bar1 = "bar1"
        $bar2 = "bar2"

    condition:
        3 of ($foo*,$bar1,$bar2)
}
甚至可以使用($*)来引用规则中的所有字符串,或者编写等效的关键字them以提高可读性。
rule OfExample4
{
    strings:
        $a = "dummy1"
        $b = "dummy2"
        $c = "dummy3"

    condition:
        1 of them
}
rule OfExample4
{
    strings:
        $a = "dummy1"
        $b = "dummy2"
        $c = "dummy3"

    condition:
        1 of ($*)
}
关键字any和all也可以使用。
all of them       // all strings in the rule
any of them       // any string in the rule
all of ($a*)      // all strings whose identifier starts by $a
any of ($a,$b,$c) // any of $a, $b or $c
1 of ($*)         // same that "any of them"

2.5.8 对多个字符串应用相同的条件

关键字for..of从到必须满足
例如:

for expression of string_set : ( boolean_expression )

在集合string_set中,expression必须满足( boolean_expression )
例如:

for any of ($a,$b,$c) : ( $ at pe.entry_point )

布尔表达式中的 $ 符号不与任何特定字符串相关联,它将是 $a,然后是 $b等
甚至可以这样:
for all of them : ( # > 3 )  次数
for all of ($a*) : ( @ > @b )  第一个偏移量

2.5.9 使用匿名字符串of和for..of

当of和for..of后跟them时,可以不指定名称
例如:
rule AnonymousStrings
{
    strings:
        $ = "dummy1"
        $ = "dummy2"

    condition:
        1 of them
}

2.5.10 迭代字符串

可以使用以下语法访问给定字符串出现在文件或进程地址空间中的偏移量或虚拟地址:@a[i],其中 i 是一个索引,指示出现了你所指的字符串 $a 。(@a[1]、@a[2]、…)。
例如:
rule Occurrences
{
    strings:
        $a = "dummy1"
        $b = "dummy2"

    condition:
        for all i in (1,2,3) : ( @a[i] + 10 == @b[i] )
}
以上条件也可以写成:
for all i in (1..3) : ( @a[i] + 10 == @b[i]
另一个规则:
for all i in (1..#a) : ( @a[i] < 100 )   //#a 代表 $a 出现的次数
此规则指定 $a 的每次出现都应在文件的前 100 个字节内。
也可以写成:
for any i in (1..#a) : ( @a[i] < 100 )
for 2 i in (1..#a) : ( @a[i] < 100 )

2.5.11 迭代器

在 YARA 4.0 中,for..of运算符得到了改进,现在它不仅可以用于迭代整数枚举和范围(例如:1,2,3,4 和 1..4),还可以用于任何类型的可迭代数据类型,例如YARA 模块定义的数组和字典。例如,以下表达式在 YARA 4.0 中有效:
for any section in pe.sections : ( section.name == ".text")
以上规则等效于:
for any i in (0..pe.number_of_sections-1) : ( pe.sections[i].name == ".text" )
在迭代字典时,您必须提供两个变量名,它们将保存字典中每个条目的键和值,例如:
for any k,v in some_dict : ( k == "foo" and v == "bar" )

2.5.12 引用其他规则

例如:
rule Rule1
{
    strings:
        $a = "dummy1"

    condition:
        $a
}

rule Rule2
{
    strings:
        $a = "dummy2"

    condition:
        $a and Rule1
}

2.6 规则要求

2.6.1 全局规则

全局规则可以一次对所有规则施加限制
例如:
global rule SizeLimit
{
    condition:
        filesize < 2MB
}

2.6.2 私有规则

在匹配给定文件时 YARA 不会报告的规则
私有规则可以作为其他规则的构建块,同时防止用不相关的信息混淆 YARA 的输出。要将规则声明为私有,只需private在规则声明之前添加关键字。
private rule PrivateRuleExample
{
    ...
}

2.6.3 规则标签

可以向规则添加标签。
些标签可以稍后用于过滤 YARA 的输出并仅显示您感兴趣的规则。
rule TagsExample1 : Foo Bar Baz
{
    ...
}

rule TagsExample2 : Bar
{
    ...
}
只允许使用字母数字字符和下划线,并且标签不能以数字开头。它们也区分大小写。

2.6.4 元数据

除了字符串定义和条件部分,规则还可以有一个元数据部分,可以在其中放置有关规则的其他信息。它们的唯一目的是存储有关规则的附加信息。
使用关键字meta
rule MetadataExample
{
    meta:
        my_identifier_1 = "Some string data"
        my_identifier_2 = 24
        my_identifier_3 = true

    strings:
        $my_text_string = "text here"
        $my_hex_string = { E2 34 A1 C8 23 FB }

    condition:
        $my_text_string or $my_hex_string
}

2.7 模块

模块是 YARA 核心功能的扩展。一些模块,如PE 模块Cuckoo 模块 是由 YARA 官方发布的,其他模块可以由第三方甚至你自己创建。
关键字import
import "pe"
import "cuckoo"
导入模块后,您可以使用其功能,始终 用作模块导出的任何变量或函数的前缀。例如:
pe.entry_point == 0x1000
cuckoo.http_request(/someregexp/)

2.8 未定义的值

模块经常让变量处于未定义状态,例如当变量在当前上下文中没有意义时(考虑pe.entry_point 在扫描非 PE 文件时)。YARA 以允许规则保持其意义的方式处理未定义的值。
import "pe"

rule Test
{
    strings:
        $a = "some string"

    condition:
        $a and pe.entry_point == 0x1000
}
如果扫描的文件不是 PE,您不会期望此规则与文件匹配,即使它包含字符串,因为必须满足两个条件(字符串的存在和入口点的正确值)。

如果更改为

$a or pe.entry_point == 0x1000
则可以匹配文件(不限于PE)

2.9 外部变量

外部变量允许您定义依赖于外部提供的值的规则。
rule ExternalVariableExample1
{
    condition:
        ext_var == 10
}
在这种情况下ext_var是一个外部变量,其值在运行时分配。外部变量可以是以下类型:整数、字符串或布尔值;它们的类型取决于分配给它们的值。整数变量可以替代条件中的任何整数常量,布尔变量可以占据布尔表达式的位置。例如:
rule ExternalVariableExample2
{
    condition:
        bool_ext_var or filesize < int_ext_var
}
string类型的外部变量可以与以下运算符一起使用:contains、startswith、endswith及其不区分大小写的对应运算符:icontains、istartswith和iendswith`。它们还可以与“matches运算符一起使用,如果字符串与给定的正则表达式匹配,则返回true。
rule ContainsExample
{
    condition:
        string_ext_var contains "text"
}

rule CaseInsensitiveContainsExample
{
    condition:
        string_ext_var icontains "text"
}

rule StartsWithExample
{
    condition:
        string_ext_var startswith "prefix"
}

rule EndsWithExample
{
    condition:
        string_ext_var endswith "suffix"
}

rule MatchesExample
{
    condition:
        string_ext_var matches /[a-z]+/
}

2.10 包括文件

关键字include包含其他文件
include "other.yar"
include "./includes/other.yar"
include "../includes/other.yar"
include "/home/plusvic/yara/includes/other.yar"
include "c:/yara/includes/other.yar"
include "c:\\yara\\includes\\other.yar"

 

3 模块

3.1 PE模块

PE 文件格式的属性和特性

https://yara.readthedocs.io/en/latest/modules/pe.html

3.2 ELF模块

ELF 文件格式的属性和特性

https://yara.readthedocs.io/en/latest/modules/elf.html

3.3 Cuckoo模块

Cuckoo 模块使您能够根据Cuckoo 沙箱生成的行为信息创建 YARA 规则。

https://yara.readthedocs.io/en/latest/modules/cuckoo.html

3.4 Magic模块

https://yara.readthedocs.io/en/latest/modules/magic.html

3.5 Hash模块

Hash 模块允许您从文件的某些部分计算哈希值(MD5、SHA1、SHA256)并根据这些哈希值创建签名。

https://yara.readthedocs.io/en/latest/modules/hash.html

3.6 Math模块

数学模块允许您从文件的某些部分计算某些值并根据这些结果创建签名。

https://yara.readthedocs.io/en/latest/modules/math.html

3.7 Dotnet 模块

dotnet 模块允许您使用 .NET 文件格式的属性和功能为 .NET 文件创建更细粒度的规则。

https://yara.readthedocs.io/en/latest/modules/dotnet.html

3.8 Time 模块

Time 模块允许您在 YARA 规则中使用时间条件。

https://yara.readthedocs.io/en/latest/modules/time.html

 

 

 

 

 

 

 

 

 

 

 


云涯历险记 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:恶意代码技术理论:YARA规则
喜欢 (0)