分享

YARA 反恶意软件的利器

 求知_时光 2020-01-31

YARA最初是由Virustotal的VictorAlvarez开发的。

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

Yara规则与C语言语法十分相像, 以下是一个简单的规则, 这个规则没有进行任何操作:

1

2

3

4

5

rule HelloRule

{

condition:

false

}

规则标识符

规则标识符是上面简单规则示例中跟在rule后的词, 比如单词'dummy'也可以是一个规则标识符,标识符命名有如下要求:

  • 是由英文字母或数字组成的字符串

  • 可以使用下划线字符

  • 第一个字符不能是数字

  • 对大小写敏感

  • 不能超出128个字符长度

Yara关键字

下面这些词不能用作规则标识符, 因为这些单词在yara语言里有特定用处

all, and, any, ascii,at, condition, contains entrypoint, false, filesize, fullword, for, global, inimport, include, int8, nt16, int32, int8be, int16be int32be, matches, meta,nocase, not, or, of private, rule, strings, them, true, uint8, uint16 uint32,int8be, uint16be, uint32be, wide

通常yara规则有两部分: 字符串定义条件

1

2

3

4

5

6

7

8

9

rule HelloRule2    // This is an example

{

    strings:

        $my_text_string = 'text here'

        $my_hex_string = { E2 34 A1 C8 23 FB }

    condition:

        $my_text_string or $my_hex_string

}

当发现有规则里定义的任意字符串, 规则就会生效. 如你所见, 你还可以在规则里添加注释.

十六进制字符串

通配符

十六进制字符串可以用通配符表示, 通配符符号用'?'表示

1

2

3

4

5

6

7

8

rule GambitWildcard

{

    strings:

       $hex_string = { EF 44 ?? D8 A? FB }

    condition:

       $hex_string

}

这个规则可以匹配下面的两个字符串

1

2

EF 44 01 D8 AA FB

EF 44 AA D8 AB FB

不定长通配符

不定长的字符串可以用下面这个方法表示

1

2

3

4

5

6

7

8

rule MarioJump

{

        strings:

           $hex_string = { F4 23 [4-6] 62 B4 }

        condition:

           $hex_string

}

这个规则可以匹配下面的两个字符串

1

2

F4 23 01 02 03 04 62 B4

F4 23 AA BB CC DD EE FF 62 B4

当然无限长的字符串也是可以的.

1

2

3

4

5

6

7

8

rule BuzzLightyear

{

        strings:

           $hex_string = { F4 23 [-] 62 B4 }

        condition:

           $hex_string

}

这个规则可以匹配下面的两个字符串

1

2

F4 23 AA FF 62 B4

F4 23 AA AA AA AA AA...FF FF 62 B4

有条件的字符串

你可以创建一个字符串应对多种情况

1

2

3

4

5

6

7

8

rule WorriedRabbit

{

    strings:

       $hex_string = { BA 21 ( DA BC | C6 ) A5 }

    condition:

       $hex_string

}

这个规则可以匹配下面的两个字符串

1

2

BA 21 DA BC A5

BA 21 C6 A5

混合

当然, 你也可以将上面这几种方法结合起来.

1

2

3

4

5

6

7

8

rule WorriedGabmitLightyearJump

{

    strings:

       $hex_string = { BA ?? ( DA [2-4] | C6 ) A5 }

    condition:

       $hex_string

}

这个规则可以匹配下面的三个字符串

1

2

3

BA 01 DA 01 02 03 04 A5

BA AA C6 A5

BA FF DA 01 02 A5

修饰符

不区分大小写的字符串

Yara规则默认对大小写敏感, 但你可以使用修饰符将其关闭

1

2

3

4

5

6

7

8

rule ThickSkin

{

    strings:

        $strong_string = 'Iron' nocase

    condition:

        $strong_string

}

宽字符串

wide修饰符可以用来搜寻以2字节表示1字符这种方式编码的字符串, 这种宽字符串在许多二进制文件中都有出现. 如果字符串'FatTony'以2字节表示1字符的方式编码并在二进制文件中出现, 我们就可以使用wide修饰符将其捕获. 因为'FatTony'也可能是'fattony', 我们也可以添加nocase修饰符以免错过.

1

2

3

4

5

6

7

8

rule FatTony

{

    strings:

        $fat_villain = 'FatTony' wide nocase

    condition:

        $fat_villain

}

Fullwords修饰符

该修饰符可用于匹配那些前后没有附加其他字符的单词(全词匹配).

1

2

3

4

5

6

7

8

rule ShadyDomain

{

    strings:

        $shady_domain = 'faceebook' fullword

    condition:

       $shady_domain

}

这个规则可以匹配下面的三个字符串

1

2

3

www.

www.myportal.

https://secure.

但这个规则不能匹配以下的字符串:

1

2

www.my

the

两者区别在于匹配的全词前后可以附加特殊字符, 不能是普通字符.

正则表达式

yara规则允许使用正则表达式, 不过要用正斜杠而非双引号括起来使用(像Perl编程那样)

1

2

3

4

5

6

7

8

9

rule RegularShow

{

    strings:

        $re1 = /md5: [0-9a-fA-F]{32}/

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

    condition:

        $re1 and $re2

}

该规则将捕获任何状态下找到的所有md5字符串.

你也可以在正则表达式中使用文本修饰符, 如nocase,ascii,wide和fullword.

元字符

元字符是一个字符对计算机程序有特定含义(而非字面含义)的字符. 在正则表达式中, 有以下含义:

1

2

3

4

5

6

** 引用下一个元字符

^ 匹配文件的开头

$ 匹配文件的末尾

| 多选

() 分组

[] 方括号字符类

也可以使用以下量词:

1

2

3

4

5

6

7

* 匹配0次或多次

+ 匹配1次或多次

? 匹配0次或1次

{n} 只匹配n次

{n, } 至少匹配n次

{ ,m} 至多匹配m次

{n,m} 匹配n到m次

也可以使用以下的转义符:

1

2

3

4

5

6

\t 水平制表符 (HT, TAB)

\n 换行符 (LF, NL)

\r 回车符 (CR)

\f 换页符 (FF)

\a 响铃

\xNN 十六进制代码为NN的字符

也可以使用以下字符类:

1

2

3

4

5

6

7

8

\w 匹配单词字符 (单词可由字母数字加'_'组成)

\W 匹配非单词字符

\s 匹配空白符

\S 匹配非空白字符

\d 匹配一个十进制数字字符

\D 匹配一个非数字字符

\b 匹配单词边界

\B 匹配非单词边界

字符串集

如果你想要中列表中选择一定数量的字符串, 你可以执行以下操作:

1

2

3

4

5

6

7

8

9

10

rule MigosPresent

{

    strings:

        $m1 = 'Quavo'

        $m2 = 'Offset'

        $m3 = 'Takeoff'

    condition:

        2 of ($m1,$m2,$m3)

}

如果$m1, $m2和$m3任意存在两个, 那么就满足上述规则中的条件.

你还可以使用通配符来表示一个字符集. 像如下这样使用通配符*

1

2

3

4

5

6

7

8

9

10

rule MigosPresent

{

    strings:

        $m1 = 'Quavo'

        $m2 = 'Offset'

        $m3 = 'Takeoff'

    condition:

        2 of ($m*)

}

要表示strings中的所有变量, 你可以使用关键字them

1

2

3

4

5

6

7

8

9

10

11

rule ThreeRappersPresent

{

    strings:

        $m1 = 'Quavo'

        $m2 = 'Offset'

        $m3 = 'Takeoff'

        $q1 = 'Cardi B'

    condition:

        3 of them // equivalent to 3 of ($*)

}

你可以使用任何返回数值的表达式. 以下是使用关键字any和all的一个示例

1

2

3

4

5

6

7

8

9

10

11

12

13

rule Squad

{

    strings:

        $m1 = 'Quavo'

        $m2 = 'Offset'

        $m3 = 'Takeoff'

        $q1 = 'Cardi B'

    condition:

        3 of them // equivalent to 3 of ($*)

        all of them

        any of ($*) and 2 of ($*)    // Fancy way of  using any in a rule that requires 3.

}

带有of和for...of的匿名字符串

如果你没有专门引用字符串的事件, 你可以仅使用$来将它们全部引用.

1

2

3

4

5

6

7

8

9

rule AnonymousStrings

{

    strings:

        $ = 'dummy1'

        $ = 'dummy2'

    condition:

        1 of them

}

条件

Yara规则允许通过and, or, 和not等相关运算符来表示布尔表达式, 算术运算符(+,-,*,%)和位运算符(&, |, <<,>>, ~, ^)也可用于数值表达式中.

布尔运算

字符串标识符也可在条件中充当布尔变量, 其值取决于文件中相关字符串是否存在.

1

2

3

4

5

6

7

8

9

10

11

rule Example

{

    strings:

        $hero1a = 'Batman'

        $hero1b = 'Robin'

        $hero2a = 'Edward'

        $hero2b = 'Alphonse'

    condition:

        ($hero1a or $hero1b) and ($hero2a or $hero2b)

}

计数字符串实例

有时我们不仅需要知道某个字符串是否存在, 还需要知道字符串在文件或进程内存中出现的次数. 每个字符串的出现次数由一个变量表示, 变量名是用#代替$的字符串标识符. 例如:

1

2

3

4

5

6

7

8

9

rule Ransomware

{

    strings:

        $a = 'encrypted'

        $b = 'btc'

    condition:

        #a == 2 and #b > 2

}

这个规则会匹配任何包含两个字符串$a以及出现至少两次字符串$b的文件或进程.

字符串偏移(虚拟地址)

在大多数情况下, 当在条件中使用字符串标识符, 我们都只需知道关联的字符串是否在文件或进程内存内就行了. 但有时我们还是需要知道该字符串是否在文件的某个特定偏移处, 或是在进程地址空间的某个虚拟地址处. 在这种情况下, 我们就需要操作符at.

1

2

3

4

5

6

7

8

9

rule Offset

{

    strings:

        $a = 'encrypted'

        $b = 'btc'

    condition:

        $a at 100 and $b at 200

}

如果在文件的偏移100处(或者在一个正在运行的进程中, 位于虚拟地址100位置)发现了字符串$a, 我们的规则就能捕获到该字符串. 当然字符串$b也要在偏移200位置上才行. 你也可以使用十六进制表示而不一定要十进制.

1

2

3

4

5

6

7

8

9

rule Offset

{

    strings:

        $a = 'encrypted'

        $b = 'btc'

    condition:

        $a at 0x64 and $b at 0xC8

}

at操作符指定到一个具体的偏移量, 而你可以使用操作符in来指定字符串的位置范围.

1

2

3

4

5

6

7

8

9

rule InExample

{

    strings:

        $a = 'encrypted'

        $b = 'btc'

    condition:

        $a in (0..100) and $b in (100..filesize)

}

字符串$a必须在偏移0-100之间才能找到, 而$b则必须是在偏移100到文件末尾位置(才能找到).

你也可以使用@a[i]来取得字符串$a第i个字符的偏移量或虚拟地址.字符串索引以1开头 , 故第1个字符是@a[1], 第2个是@[a2]并依此类推, 而不是以@a[0]开始. 如果你提供的索引值大过字符串总共出现的次数. 那结果就将是值NaN(Not a Number, 非数字).

匹配长度

对于包含跳转的许多正则表达式和十六进制字符串, 匹配长度用一个变量表示. 如果你有一个正则表达式/fo*/, 可以匹配字符串fo, foo和fooo, 那么各个的匹配长度都是不同的.

在字符串标识符前加一个!得到匹配长度, 你就可以将匹配长度作为你条件的一部分. 跟你获取偏移时使用字符@类似, !a[1]是第一个匹配到的字符串$a的长度, 而!a[2]就是第二个匹配到的字符串的长度, 依此类推. !a是!a[1]的缩写.

1

2

3

4

5

6

7

8

rule Hak5

{

    strings:

        $re1 = /hack*/    // Will catch on hacker, hacked, hack, hack*

    condition:

        !re1[1] == 4 and !re1[2] > 6

}

该规则可以匹配如下字符串:

1

We hack things. We are hackers.

第一个hack是re1[1]且其长度等于4. 第二个hack长度则至少为6

还有更多强大的语法和文件处理功能,请参看以下资源

http://virustotal./yara/

https://github.com/VirusTotal/yara

https://github.com/Yara-Rules/rules

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多