Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
YARA-Performance-Guidelines — Руководство по написанию быстрых и эффективных по памяти YARA-правил | Kitploit
Инструменты/GitHubGitHub/neo23x0/yara-performance-guidelines
Статический анализАнализ вредоносных программОбучение и Образование
GitHubneo23x0/yara-performance-guidelines

YARA-Performance-Guidelines

Руководство по написанию быстрых и эффективных по памяти YARA-правил

Репозиторий

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
174231 год назадПроверено Kitploit
Поделиться

Рекомендации по производительности YARA

Написание эффективных YARA-правил необходимо для поддержания быстрого и точного сканирования. Это руководство содержит ключевые принципы и лучшие практики, которые помогут вам оптимизировать правила, снизить ненужные вычисления и избежать типичных ошибок. Оно включает наработки экспертов индустрии, в том числе Виктора М. Альвареса (Victor M. Alvarez), WXS, а также вклад сообщества YARA.

  • Редакция 1.6, февраль 2025 года, применима ко всем версиям YARA выше 3.7

Ключевые выводы

В этом разделе приведено краткое резюме лучших практик производительности YARA. За подробными объяснениями и примерами обращайтесь к полному руководству ниже.

Понимание процесса сканирования YARA

"Представляйте YARA как двухэтапный процесс: сначала поиск всех шаблонов, перечисленных в строках, а затем оценка условий. Нельзя компенсировать плохо подобранные строки хорошо составленными условиями."
— Уэсли Шилдс (Wesley Shields)

При сканировании файла YARA выполняет четыре основных шага:

  1. Компиляция правил – извлечение атомов (4-байтовых подстрок) из заданных строк.
  2. Поиск Ахо — Корасик – сканирование файлов на наличие этих атомов.
  3. Движок байт-кода – проверка полных совпадений строк.
  4. Оценка условий – проверка дополнительной логики правила.

Выбор строк — самый важный фактор

YARA сначала ищет строки, поэтому выбор строк является самым важным фактором эффективности правила.

✅ Лучшие практики для строк:

  • Избегайте коротких строк (<4 байт) — они создают слишком много ложных срабатываний.
  • Используйте уникальные 4-байтовые атомы — YARA полагается на них для быстрого сканирования.
  • Минимизируйте подстановочные знаки в hex-строках — сохраняйте хотя бы один длинный конкретный сегмент.
  • Используйте регулярные выражения экономно — при необходимости включайте фиксированный 4-байтовый якорь для повышения эффективности.
  • Избегайте повторяющихся однобайтовых шаблонов — например, \x00\x00\x00\x00 встречается слишком часто.
  • Используйте nocase с осторожностью — это порождает экспоненциально больше вариантов поиска.

Оптимизация условий и сокращённые вычисления (short-circuit)

YARA вычисляет условия последовательно и останавливается при первой неудаче.

✅ Лучшие практики для условий:

  • Размещайте быстрые проверки первыми (например, filesize < X) перед дорогостоящими условиями.
  • Избегайте циклов по большим объёмам данных (for all i in (1..filesize) неэффективно).
  • Используйте прямые смещения (@) вместо регулярных выражений для проверки последовательностей.

⚠ Примечание: Условия с регулярными выражениями не поддерживают сокращённые вычисления и всегда оцениваются последними.

Модули — используйте с осторожностью

Такие модули, как pe, elf или magic, должны разобрать весь файл перед оценкой, что увеличивает время сканирования.

✅ Альтернативы:

  • Вместо pe.is_pe используйте uint16(0) == 0x5A4D для определения PE-файлов.
  • Избегайте использования модулей, если не требуется глубокий анализ файла.

Обработка слишком большого количества совпадений и медленного сканирования

Чрезмерное количество совпадений замедляет сканирование и может вызывать ошибки "too many matches" (слишком много совпадений).

✅ Исправление неэффективных совпадений:

  • Проверьте квантификаторы регулярных выражений — избегайте .*, .+ или {x,} без верхней границы.
  • Сократите количество подстановочных знаков в hex-строках.
  • Разделяйте альтернации на отдельные строки, где это возможно.

Видеоурок

@herrcore создал полезный видеоурок, охватывающий темы, обсуждаемые в этом руководстве по производительности.

Introduction Into YARA - Writing Efficient YARA Rules

Основы

Чтобы лучше понять, что и где можно оптимизировать в производительности YARA, полезно разобраться в процессе сканирования. Он в основном разделён на 4 шага, которые будут объяснены очень упрощённо на примере этого правила:

root@kitploit:~
import "math"
rule example_php_webshell_rule
{
    meta:
        description = "Just an example php webshell rule"
        date = "2021/02/16"
    strings:
        $php_tag = "<?php"
        $input1   = "GET"
        $input2   = "POST"
        $payload = /assert[\t ]{0,100}\(/
    condition:
        filesize < 20KB and
        $php_tag and
        $payload and
        any of ( $input* ) and
        math.entropy(500, filesize-500) >= 5
}

1. Компиляция правил

Этот шаг выполняется до фактического сканирования. YARA ищет так называемые атомы в строках поиска, чтобы передать их автомату Ахо — Корасик. Подробности объяснены в главе атом, но пока достаточно знать, что их максимальная длина составляет 4 байта, и YARA выбирает их довольно умно, чтобы избежать слишком большого количества совпадений. В нашем примере YARA может выбрать следующие 4 атома:

  • <?ph
  • GET
  • POST
  • sser (из assert)

2. Автомат Ахо — Корасик

Здесь сканирование началось. Шаги 2–4 выполняются для всех файлов. YARA ищет в каждом файле 4 атома, определённые выше, с помощью префиксного дерева, называемого автоматом Ахо — Корасик. Все совпадения передаются движку байт-кода.

3. Движок байт-кода

Если, например, есть совпадение по sser, YARA проверит, предшествовала ли ему буква a, и продолжит с t. Если это так, он перейдёт к регулярному выражению [\t ]{0,100}\(. Благодаря такому умному подходу YARA не обрабатывает медленным регулярным выражением все файлы целиком, а выбирает только определённые части для более детального изучения.

4. Условия

После завершения сопоставления с шаблонами проверяются условия. В YARA есть ещё один механизм оптимизации: ресурсоёмкая проверка math.entropy из нашего примера выполняется только в том случае, если выполнены 4 предыдущих условия. Подробнее это объясняется в главе Условия и сокращённые вычисления

Если условия выполнены, сообщается о совпадении. Сканирование продолжается со следующим файлом на шаге 2.

Атомы

YARA извлекает из строк короткие подстроки длиной до 4 байт, которые называются "атомами". Эти атомы могут быть извлечены из любого места строки, и YARA ищет эти атомы при сканировании файла; если он находит один из атомов, то проверяет, действительно ли строка совпадает.

Например, рассмотрим такие строки:

root@kitploit:~
/abc.*cde/

=> возможные атомы — abc и cde, можно использовать любой из них. В настоящее время предпочтителен атом abc, поскольку они имеют одинаковое качество, и это первый из двух.

root@kitploit:~
/(one|two)three/

=> возможные атомы — one, two, thre и hree; можно искать только thre (или hree) либо оба one и two. Атом thre предпочтительнее, потому что он приведёт к меньшему числу потенциальных совпадений, чем one и two (они короче), и не содержит двойной e (чем уникальнее буква, тем лучше).

YARA прикладывает все усилия, чтобы выбрать лучшие атомы из каждой строки, например:

root@kitploit:~
{ 00 00 00 00 [1-4] 01 02 03 04 }

=> здесь YARA использует атом 01 02 03 04, потому что 00 00 00 00 слишком распространён

root@kitploit:~
{ 01 02 [1-4] 01 02 03 04 }

=> 01 02 03 04 предпочтительнее, чем 01 02, потому что он длиннее

Итак, важный момент: строки должны содержать хорошие атомы. Вот плохие строки, потому что они содержат либо слишком короткие, либо слишком распространённые атомы:

root@kitploit:~
{00 00 00 00 [1-2] FF FF [1-2] 00 00 00 00}
{AB  [1-2] 03 21 [1-2] 01 02}
/a.*b/
/a(c|d)/

Худшие строки — те, которые вообще не содержат атомов, например:

root@kitploit:~
/\w.*\d/
/[0-9]+\n/

Эти регулярные выражения не содержат ни одной фиксированной подстроки, которую можно было бы использовать в качестве атома, поэтому их необходимо проверять на каждом смещении файла, чтобы увидеть, есть ли там совпадение.

Слишком много итераций цикла

Ещё одна хорошая рекомендация — избегать циклов со слишком большим количеством итераций, особенно если оператор внутри цикла слишком сложный, например:

root@kitploit:~
strings:
	$a = {00 00}
condition:
	for all i in (1..#a) : (@a[i] < 10000)

У этого правила две проблемы. Первая — строка $a слишком распространена, вторая — из-за того, что $a слишком распространена, #a может быть слишком большим, и условие может вычисляться тысячи раз.

Следующее условие также неэффективно, потому что количество итераций зависит от размера файла, который также может быть очень большим:

root@kitploit:~
for all i in (1..filesize) : ($a at i)

Модуль Magic

Избегайте использования модуля "magic", который недоступен на платформе Windows. Использование модуля "magic" замедляет сканирование, но обеспечивает точные совпадения.

Пользовательское определение заголовка GIF:

root@kitploit:~
rule gif_1 {
  condition:
    (uint32be(0) == 0x47494638 and uint16be(4) == 0x3961) or
    (uint32be(0) == 0x47494638 and uint16be(4) == 0x3761)
}

С использованием модуля "magic":

root@kitploit:~
import "magic"
rule gif_2 {
  condition:
    magic.mime_type() == "image/gif"
}

Слишком короткие строки

Избегайте определения слишком коротких строк. Любая строка короче 4 байт, вероятно, встретится во множестве файлов ИЛИ как однородное содержимое в XOR-файле.

Однородное содержимое

Некоторые строки достаточно длинны, но не должны использоваться по другой причине — однородности. Вот несколько примеров строк, которые не следует использовать, так как они могут вызвать слишком много совпадений в файлах.

root@kitploit:~
$s1 = "22222222222222222222222222222222222222222222222222222222222222"
$s2 = "\x00\x20\x00\x20\x00\x20\x00\x20\x00\x20\x00\x20\x00\x20"  // широкие пробелы в UTF-16

Сообщение об ошибке будет выглядеть так:

root@kitploit:~
error scanning yara-killer.dat: string "$mz" in rule "shitty_mz" caused too many matches

Советы по строкам

Старайтесь описывать определения строк как можно более узко. По возможности избегайте атрибута "nocase", потому что будет сгенерировано и найдено множество атомов (более высокое использование памяти, больше итераций). Помните: при отсутствии модификаторов по умолчанию предполагается "ascii". Возможные комбинации:

НИЗКО — генерируется только один атом

root@kitploit:~
$s1 = "cmd.exe"		       // (только ascii)
$s2 = "cmd.exe" ascii          // (только ascii, то же, что и $s1)
$s3 = "cmd.exe" wide           // (только UTF-16)
$s4 = "cmd.exe" ascii wide     // (и ascii, и UTF-16) будет сгенерировано два атома 
$s5 = { 63 6d 64 2e 65 78 65 } // ascii-коды символов в hex

ВЫСОКО — все комбинации верхнего и нижнего регистра для 4 байт, выбранных YARA, будут сгенерированы как атомы

root@kitploit:~
$s5 = "cmd.exe" nocase      (все различные варианты регистра, например "Cmd.", "cMd.", "cmD." ..)

Если вы хотите сопоставлять команды сценариев, прежде чем использовать nocase, проверьте, является ли язык вообще регистронезависимым (например, PHP, пакетные файлы Windows). Если вам нужен другой регистр только для одной или двух букв, лучше использовать регулярное выражение, например:

root@kitploit:~
$re = /[Pp]assword/

Будьте осторожны с альтернациями, такими как:

root@kitploit:~
$re = /(a|b)cde/
$hex = {C7 C3 00 (31 | 33)}

Эти строки порождают короткие атомы, которые могут замедлить сканирование. В случаях, когда вариантов немного, рекомендуется записывать строки отдельно:

root@kitploit:~
$re1 = /acde/
$re2 = /bcde/
$hex1 = {C7 C3 00 31}
$hex2 = {C7 C3 00 33}

Регулярные выражения

Используйте регулярные выражения только при необходимости. Вычисление регулярных выражений по своей сути медленнее, чем простое сопоставление строк, и потребляет значительный объём памяти. Не используйте их, если задачу можно решить с помощью hex-строк с переходами и подстановочными знаками.

Если вам приходится использовать регулярные выражения, избегайте жадных .* и даже «ленивых» квантификаторов .*?. Вместо этого используйте точные числа, например .{1,30} или даже .{1,3000}. Также не забывайте про верхнюю границу (избегайте, например, .{2,}).

При использовании квантификаторов возможны две ситуации:

Если начало регулярного выражения привязано к одной позиции и может изменяться только суффикс, YARA найдёт максимально возможное совпадение. В случаях с .* и .+ или .{2,} это может привести к очень длинным строкам и замедлению сканирования.

Если у регулярного выражения есть несколько возможных начал, YARA найдёт все из них.

root@kitploit:~
$re1 = /Tom.{0,2}/		// найдёт Tomxx в "Tomxx"
$re2 = /.{0,2}Tom/      // найдёт Tom, xTom, xxTom в "xxTom"

Количество более коротких совпадений может легко превысить лимит и вызвать ошибку "too many matches" (слишком много совпадений).

Следующий пример — регулярное выражение для адреса электронной почты. При использовании [-a-z0-9._%+] с квантификаторами YARA будет сопоставлять один адрес несколько раз, что не идеально. В этом случае рекомендуется найти достаточно небольшое подмножество адресов, дающее достаточно информации для анализа.

ИСПОЛЬЗУЙТЕ

root@kitploit:~
/[-a-z0-9._%+]@[-a-z0-9.]{2,10}\.[a-z]{2,4}/
ИЛИ
/@[-a-z0-9.]{2,10}\.[a-z]{2,4}/ 

ИЗБЕГАЙТЕ

root@kitploit:~
/[-a-z0-9._%+]*@[-a-z0-9.]{2,10}\.[a-z]{2,4}/
/[-a-z0-9._%+]+@[-a-z0-9.]{2,10}\.[a-z]{2,4}/
/[-a-z0-9._%+]{x,y}@[-a-z0-9.]{2,10}\.[a-z]{2,4}/

Если вы хотите убедиться, что, например, за exec следует /bin/sh, можно использовать смещения, предоставляемые символом @. Это была бы медленная версия с регулярным выражением:

root@kitploit:~
$ = /exec.*\/bin\/sh/

Вот более быстрый способ со смещениями:

root@kitploit:~
strings:
  $exec = "exec" 
  $sh   = "/bin/sh"
conditions:
  $exec and $sh and
  @exec < @sh

Также старайтесь включать длинные последовательности строк, которые могут служить якорями в процессе сопоставления. Опять же, чем длиннее, тем лучше.

ПЛОХО

root@kitploit:~
$s1 = /http:\/\/[.]*\.hta/	// жадный [.]*

ЛУЧШЕ

root@kitploit:~
$s1 = /http:\/\/[a-z0-9\.\/]{3,70}\.hta/ 	// лучше, с верхней границей

НАИЛУЧШЕ

root@kitploit:~
$s1 = /mshta\.exe http:\/\/[a-z0-9\.\/]{3,70}\.hta/

Слишком много совпадений и ошибка замедления сканирования

Ошибки "too many matches" (слишком много совпадений) вызваны слишком общими строками, которые слишком часто встречаются во входных данных, либо YARA сопоставляет один экземпляр несколько раз.

Замедление сканирования вызвано строками, которые порождают слишком короткие атомы или не порождают их вовсе. В результате YARA использует наивный алгоритм сопоставления с шаблоном, что и вызывает замедление.

Обе эти проблемы в некоторых случаях можно исправить следующими шагами:

  1. Проверьте квантификаторы .* и .+, .*?
  2. Проверьте квантификаторы без верхней границы, например x{14,}
  3. Проверьте слишком большой диапазон (например, x{1,300000})
  4. Проверьте большие переходы в hex-строках
  5. Проверьте подстановочные символы — можно ли их задать более точно или разбить строку на 2 части, исключив подстановочные символы?
  6. Проверьте альтернации: можно ли разбить их на 2 или более строк?
  7. Попробуйте добавить спецификацию для сопоставления слов (fullword, \b,...)

Обратите внимание: в следующей главе Условия и сокращённые вычисления приведено несколько советов по условиям. Однако их изменение не решит проблемы "too many matches" и замедления сканирования.

Условия и сокращённые вычисления

Старайтесь записывать условия так, чтобы элементы, которые с наибольшей вероятностью дадут "False", располагались первыми. Условие вычисляется слева направо. Чем раньше движок определит, что правило не выполнено, тем быстрее он сможет пропустить текущее правило и перейти к следующему. Ускорение, вызванное таким порядком условий, зависит от разницы в необходимых тактах ЦП для обработки каждого из операторов. Если все операторы примерно одинаково затратны, изменение порядка не даст заметного улучшения. Если один из операторов может быть обработан очень быстро, рекомендуется поставить его первым, чтобы пропустить дорогостоящую оценку в случаях, когда первый оператор равен FALSE.

Изменение порядка в следующем выражении не даёт значительного улучшения:

root@kitploit:~
$string1 and $string2 and uint16(0) == 0x5A4D

Однако если время выполнения операторов сильно различается, изменение порядка для срабатывания сокращённых вычислений значительно ускорит сканирование:

МЕДЛЕННО

root@kitploit:~
// ДОРОГО и ДЁШЕВО
math.entropy(0, filesize) > 7.0 and uint16(0) == 0x5A4D

БЫСТРО

root@kitploit:~
// ДЁШЕВО и ДОРОГО
uint16(0) == 0x5A4D and math.entropy(0, filesize) > 7.0

Сокращённые вычисления были введены для оптимизации дорогостоящих конструкций, особенно циклов "for". Некоторые использовали условия, подобные примеру ниже:

root@kitploit:~
strings:
	$mz = "MZ"
	...
condition:
	$mz at 0 and for all i in (1..filesize) : ( whatever )

Поскольку filesize может быть очень большим числом, "whatever" может выполняться очень много раз, замедляя выполнение. Теперь, благодаря сокращённым вычислениям, цикл "for" будет выполняться только в том случае, если первая часть условия выполнена, поэтому это правило будет медленным только для MZ-файлов. Дополнительным улучшением может быть:

root@kitploit:~
$mz at 0 and filesize < 100KB and for all i in (1..filesize) : ( whatever )

Таким образом устанавливается верхняя граница количества итераций.

Начиная с версии 3.10, циклы по целочисленным диапазонам также были оптимизированы:

root@kitploit:~
for all i in (0..100): (false)
for any i in (0..100): (true)

Оба этих цикла прекратят итерации после первого прохода.

Нет сокращённых вычислений для регулярных выражений

К сожалению, это не работает с регулярными выражениями, потому что все они изначально передаются в движок сопоставления строк. Следующий пример замедлит поиск для любого файла, а не только для тех, чей размер меньше 200 байт:

root@kitploit:~
strings:
  $expensive_regex = /\$[a-z0-9_]+\(/ nocase
conditions:
  filesize < 200 and
  $expensive_regex

Эта "сокращённая" оценка применяется с версии YARA 3.4.

Метаданные

Любые данные в секции метаданных считываются YARA в оперативную память. (Это легко проверить, вставив 100 000 хешей в правило и сравнив использование RAM при сканировании YARA до и после.) Конечно, вы не хотите навсегда удалять метаданные из правил, но если у вас мало оперативной памяти, вы можете удалить некоторые ненужные части метаданных в своём рабочем процессе непосредственно перед сканированием.

Скачать инструмент