YARA также можно использовать из Python через библиотеку yara-python. После того как библиотека собрана и установлена, как описано в разделе Компиляция YARA, вы получите доступ ко всему потенциалу YARA из ваших Python-скриптов.
Первый шаг — импортировать библиотеку YARA:
import yaraЗатем вам нужно скомпилировать правила YARA перед их применением к данным. Правила можно скомпилировать, указав путь к файлу:
rules = yara.compile(filepath='/foo/bar/myrules')Аргумент по умолчанию — filepath, поэтому вам не нужно явно указывать его имя:
rules = yara.compile('/foo/bar/myrules')Вы также можете скомпилировать правила из файлового объекта:
fh = open('/foo/bar/myrules')
rules = yara.compile(file=fh)
fh.close()Или вы можете скомпилировать их непосредственно из строки Python:
rules = yara.compile(source='rule dummy { condition: true }')Если вы хотите скомпилировать группу файлов или строк одновременно, вы можете сделать это с помощью именованных аргументов filepaths или sources:
rules = yara.compile(filepaths={
'namespace1':'/my/path/rules1',
'namespace2':'/my/path/rules2'
})
rules = yara.compile(sources={
'namespace1':'rule dummy { condition: true }',
'namespace2':'rule dummy { condition: false }'
})Обратите внимание, что и filepaths, и sources должны быть словарями с ключами строкового типа. Ключи словаря используются как идентификатор пространства имён, что позволяет различать правила с одинаковыми именами из разных источников, как это происходит во втором примере с именем dummy.
Метод compile также имеет необязательный булев параметр includes, который позволяет управлять тем, должна ли директива include приниматься в исходных файлах, например:
rules = yara.compile('/foo/bar/my_rules', includes=False)Если исходный файл содержит директивы include, предыдущая строка вызовет исключение.
Если используются включения (include), можно установить Python-функцию обратного вызова для определения пользовательского источника импортируемых файлов (по умолчанию они считываются с диска). Эта функция обратного вызова задаётся через необязательный параметр include_callback. Она принимает следующие параметры:
requested_filename: файл, запрошенный с помощью 'include'filename: файл, содержащий директиву 'include', если применимо, иначе Nonenamespace: пространство имён
И возвращает запрошенные исходные тексты правил в виде одной строки.
import yara
import sys
if sys.version_info >= (3, 0):
import urllib.request as urllib
else:
import urllib as urllib
def mycallback(requested_filename, filename, namespace):
if requested_filename == 'req.yara':
uf = urllib.urlopen('https://pastebin.com/raw/siZ2sMTM')
sources = uf.read()
if sys.version_info >= (3, 0):
sources = str(sources, 'utf-8')
return sources
else:
raise Exception(filename+": Can't fetch "+requested_filename)
rules = yara.compile(source='include "req.yara" rule r{ condition: true }',
include_callback=mycallback)Если вы используете внешние переменные в ваших правилах, вы должны определить эти внешние переменные либо при компиляции правил, либо при применении правил к какому-либо файлу. Чтобы определить переменные в момент компиляции, вы должны передать параметр externals в метод compile. Например:
rules = yara.compile('/foo/bar/my_rules',
externals= {'var1': 'some string', 'var2': 4, 'var3': True})Параметр externals должен быть словарём с именами переменных в качестве ключей и связанными значениями строкового, целочисленного или булева типа.
Метод compile также принимает необязательные булевы аргументы, указывающие yara-python, как обрабатывать предупреждения. Первый аргумент такого рода — error_on_warning. Этот аргумент указывает YARA генерировать исключение при выдаче предупреждения во время компиляции. Такие предупреждения обычно выдаются, когда ваши правила содержат конструкции, которые могут замедлять сканирование. Значение по умолчанию для аргумента error_on_warning — False. Второй аргумент этого типа — ещё один булев параметр strict_escape, при включении которого YARA выдаёт предупреждение, когда правила содержат некорректно экранированные символы. Значение по умолчанию для аргумента strict_escape — False.
Во всех случаях compile возвращает экземпляр класса yara.Rules. Этот класс имеет метод save, который можно использовать для сохранения скомпилированных правил в файл:
rules.save('/foo/bar/my_compiled_rules')Скомпилированные правила можно загрузить позже с помощью метода load:
rules = yara.load('/foo/bar/my_compiled_rules')Начиная с YARA 3.4, и save, и load принимают файловые объекты. Например, вы можете сохранить ваши правила в буфер памяти с помощью следующего кода:
import io
buff = io.BytesIO()
rules.save(file=buff)Сохранённые правила можно загрузить из буфера памяти:
buff.seek(0)
rule = yara.load(file=buff)Результат load также является экземпляром класса yara.Rules.
Начиная с YARA 4.3.0, объекты Rules имеют атрибут warning, который содержит список предупреждений, сгенерированных компилятором. Это позволяет вам узнать, генерировал ли компилятор предупреждения, без необходимости делать их жёсткими ошибками с помощью аргумента error_on_warning.
Экземпляры Rules также имеют метод match, который позволяет применять правила к файлу:
matches = rules.match('/foo/bar/my_file')Но вы также можете применить правила к строке Python:
with open('/foo/bar/my_file', 'rb') as f:
matches = rules.match(data=f.read())Или к запущенному процессу:
matches = rules.match(pid=1234)Как и в случае с compile, метод match может принимать определения внешних переменных в аргументе externals.
matches = rules.match('/foo/bar/my_file',
externals= {'var1': 'some other string', 'var2': 100})Внешние переменные, определённые во время компиляции, не нужно определять повторно в последующих вызовах метода match. Однако вы можете переопределить любую переменную по мере необходимости или предоставить дополнительные определения, которые не были предоставлены при компиляции.
В некоторых ситуациях, связанных с очень большим набором правил или огромными файлами, метод match может выполняться слишком долго. В таких ситуациях вам может пригодиться аргумент timeout:
matches = rules.match('/foo/bar/my_huge_file', timeout=60)Если функция match не завершится до истечения указанного количества секунд, будет вызвано исключение TimeoutError.
Вы также можете указать функцию обратного вызова при вызове метода match. По умолчанию предоставленная функция будет вызываться для каждого правила, независимо от того, совпало оно или нет. Вы можете выбрать, когда будет вызываться ваша функция обратного вызова, установив параметр which_callbacks в одно из значений: yara.CALLBACK_MATCHES, yara.CALLBACK_NON_MATCHES или yara.CALLBACK_ALL. По умолчанию используется yara.CALLBACK_ALL. Ваша функция обратного вызова должна ожидать один параметр словарного типа и должна возвращать CALLBACK_CONTINUE для перехода к следующему правилу или CALLBACK_ABORT для прекращения применения правил к вашим данным.
Вот пример:
import yara
def mycallback(data):
print(data)
return yara.CALLBACK_CONTINUE
matches = rules.match('/foo/bar/my_file', callback=mycallback, which_callbacks=yara.CALLBACK_MATCHES)Передаваемый словарь будет выглядеть примерно так:
{
'tags': ['foo', 'bar'],
'matches': True,
'namespace': 'default',
'rule': 'my_rule',
'meta': {},
'strings': [StringMatch, StringMatch]
}Поле matches указывает, совпадает ли правило с данными или нет. Поле strings — это список объектов yara.StringMatch.
Метод match возвращает список экземпляров класса yara.Match. Экземпляры этого класса имеют те же атрибуты, что и словарь, передаваемый в функцию обратного вызова.
Вы также можете указать функцию обратного вызова для модулей при вызове метода match. Предоставленная функция будет вызываться для каждого импортированного модуля, который сканировал файл. Ваша функция обратного вызова должна ожидать один параметр словарного типа и должна возвращать CALLBACK_CONTINUE для перехода к следующему правилу или CALLBACK_ABORT для прекращения применения правил к вашим данным.
Вот пример:
import yara
def modules_callback(data):
print(data)
return yara.CALLBACK_CONTINUE
matches = rules.match('/foo/bar/my_file', modules_callback=modules_callback)Передаваемый словарь будет содержать информацию от модуля.
Вы также можете указать функцию обратного вызова для предупреждений при вызове метода match. Предоставленная функция будет вызываться для каждого предупреждения времени выполнения. Ваша функция обратного вызова должна ожидать два параметра. Первый — целое число, содержащее тип предупреждения, а второй — строка с сообщением предупреждения. Ваш обратный вызов должен возвращать CALLBACK_CONTINUE для продолжения сканирования или CALLBACK_ABORT для остановки.
Возможные значения типа:
CALLBACK_TOO_MANY_MATCHES
Содержимое сообщения обратного вызова зависит от типа обратного вызова.
Для CALLBACK_TOO_MANY_MATCHES сообщение представляет собой именованный кортеж, содержащий 3 элемента: namespace, rule и string. Все содержат строковые идентификаторы.
Вот пример:
import yara
def warnings_callback(warning_type, message):
if warning_type == yara.CALLBACK_TOO_MANY_MATCHES:
print(f"namespace:'{message.namespace}' rule:'{message.rule}' string:'{message.string}'")
return yara.CALLBACK_CONTINUE
matches = rules.match('/foo/bar/my_file', warnings_callback=warnings_callback)Если вы не используете обратный вызов для предупреждений, сообщение предупреждения будет отправлено в стандартную систему предупреждений Python, и сканирование продолжится.
В YARA 4.2.0 был представлен новый модуль console, который позволяет отправлять сообщения журнала внутри YARA. По умолчанию они выводятся в stdout в yara-python, но вы можете обрабатывать их в собственном обратном вызове, используя параметр console_callback.
Вот пример:
import yara
r = """
import "console"
rule a { condition: console.log("Hello from Python!") }
"""
def console(message):
print(f"Callback: {message}")
rules = yara.compile(source=r)
rules.match("/bin/ls", console_callback=console)
rules.match("/bin/ls")Тип параметра message — строка.
Вы также можете обнаружить, что размер стека по умолчанию для движка сопоставления в YARA или максимальное количество строк на правило слишком мало. В C API libyara вы можете изменить их с помощью переменных YR_CONFIG_STACK_SIZE и YR_CONFIG_MAX_STRINGS_PER_RULE через функцию yr_set_configuration_uint32 в libyara. Инструмент командной строки предоставляет их как аргументы командной строки --stack-size (-k) и --max-strings-per-rule. Чтобы установить эти значения через Python API, вы можете использовать yara.set_config, передав stack_size и/или max_strings_per_rule в качестве именованных аргументов. На момент написания этой документации размер стека по умолчанию составлял 16384, а максимальное количество строк на правило — 10000.
Кроме того, yara.set_config принимает аргумент max_match_data для управления максимальным количеством байтов, которые будут возвращены для каждой совпавшей строки. Это эквивалентно использованию YR_CONFIG_MAX_MATCH_DATA с yr_set_configuration_uint32 в C API. По умолчанию это значение установлено в 512.
Вот несколько примеров вызовов:
yara.set_config(stack_size=65536)
yara.set_config(max_strings_per_rule=50000, stack_size=65536)
yara.set_config(max_strings_per_rule=20000)
yara.set_config(max_match_data=128)Компилирует исходные тексты YARA.
Должен быть указан один из следующих параметров: filepath, source, file, filepaths или sources. Остальные аргументы являются необязательными.
Параметры:
| Параметр | Тип | Описание |
|---|---|---|
filepath |
str |
Путь к исходному файлу. |
source |
str |
Строка, содержащая код правил. |
file |
file-object | Исходный файл как файловый объект. |
filepaths |
dict |
Словарь, где ключи — пространства имён, а значения — пути к исходным файлам. |
sources |
dict |
Словарь, где ключи — пространства имён, а значения — строки с кодом правил. |
externals |
dict |
Словарь с внешними переменными. Ключи — имена переменных, значения — значения переменных. |
includes |
boolean |
True, если директивы include разрешены, или False в противном случае. Значение по умолчанию: True. |
error_on_warning |
boolean |
Если true, предупреждения рассматриваются как ошибки и вызывают исключение. |
Возвращает: Объект скомпилированных правил.
Тип возвращаемого значения: yara.Rules
Исключения:
yara.SyntaxError: Если обнаружена синтаксическая ошибка.yara.Error: Если произошла ошибка.
Изменено в версии 3.4.0
Загружает скомпилированные правила из пути или файлового объекта. Должен быть указан либо filepath, либо file.
Параметры:
| Параметр | Тип | Описание |
|---|---|---|
filepath |
str |
Путь к файлу скомпилированных правил. |
file |
file-object | Файловый объект, поддерживающий метод read. |
Возвращает: Объект скомпилированных правил.
Тип возвращаемого значения: yara.Rules
Исключения:
yara.Error: Если произошла ошибка при загрузке файла.
Устанавливает конфигурационные переменные, доступные через API yr_set_configuration.
Укажите один из параметров: stack_size, max_strings_per_rule или max_match_data. Эти именованные аргументы принимают беззнаковые целочисленные значения и присваивают предоставленное значение соответствующим переменным yr_set_configuration(...): YR_CONFIG_STACK_SIZE, YR_CONFIG_MAX_STRINGS_PER_RULE и YR_CONFIG_MAX_MATCH_DATA.
Параметры:
| Параметр | Тип | Описание |
|---|---|---|
stack_size |
int |
Размер стека для YR_CONFIG_STACK_SIZE. |
max_strings_per_rule |
int |
Максимальное количество строк на правило YARA. Будет сопоставлено с YR_CONFIG_MAX_STRINGS_PER_RULE. |
max_match_data |
int |
Максимальное количество байтов на совпадение YARA. Будет сопоставлено с YR_CONFIG_MAX_MATCH_DATA. |
Возвращает: None
Тип возвращаемого значения: NoneType
Исключения:
yara.Error: Если произошла ошибка.
Экземпляры этого класса возвращаются функцией yara.compile() и представляют набор скомпилированных правил.
Rules.match(filepath, pid, data, externals=None, callback=None, fast=False, timeout=None, modules_data=None, modules_callback=None, warnings_callback=None, which_callbacks=CALLBACK_ALL, console_callback=None)
Сканирует файл, память процесса или строку данных.
Должен быть указан один из следующих параметров: filepath, pid или data. Остальные аргументы являются необязательными.
Параметры:
| Параметр | Тип | Описание |
|---|---|---|
filepath |
str |
Путь к сканируемому файлу. |
pid |
int |
Идентификатор сканируемого процесса. |
data |
str/bytes |
Данные для сканирования. |
externals |
dict |
Словарь с внешними переменными. Ключи — имена переменных, значения — значения переменных. |
callback |
function |
Функция обратного вызова, вызываемая для каждого правила. |
fast |
bool |
Если true, выполняется сканирование в быстром режиме. |
timeout |
int |
Прерывает сканирование после истечения указанного количества секунд. |
modules_data |
dict |
Словарь с дополнительными данными для модулей. Ключи — имена модулей, значения — объекты bytes, содержащие дополнительные данные. |
modules_callback |
function |
Функция обратного вызова, вызываемая для каждого модуля. |
warnings_callback |
function |
Функция обратного вызова, вызываемая при предупреждении, например yara.CALLBACK_TOO_MANY_MATCHES. |
which_callbacks |
int |
Целое число, указывающее, в каких случаях должна вызываться функция обратного вызова. Возможные значения: yara.CALLBACK_ALL, yara.CALLBACK_MATCHES и yara.CALLBACK_NON_MATCHES. |
console_callback |
function |
Функция обратного вызова, вызываемая для каждого вызова модуля console. |
Исключения:
yara.TimeoutError: Если истёк тайм-аут.yara.Error: Если произошла ошибка во время сканирования.
Изменено в версии 3.4.0
Сохраняет скомпилированные правила в файл. Должен быть указан либо filepath, либо file.
Параметры:
| Параметр | Тип | Описание |
|---|---|---|
filepath |
str |
Путь к файлу. |
file |
file-object | Файловый объект, поддерживающий метод write. |
Исключения:
yara.Error: Если произошла ошибка при сохранении файла.
Добавлено в версии 4.3.0
Объекты, возвращаемые методом yara.Rules.match(), представляющие совпадение.
Имя совпавшего правила.
Пространство имён, связанное с совпавшим правилом.
Массив строк, содержащий теги, связанные с совпавшим правилом.
Словарь, содержащий метаданные, связанные с совпавшим правилом.
Список объектов StringMatch.
Добавлено в версии 4.3.0
Объекты, представляющие совпадения строк.
Имя совпавшей строки.
Список объектов StringMatchInstance.
Возвращает булево значение, указывающее, использует ли строка модификатор xor.
Добавлено в версии 4.3.0
Объекты, представляющие экземпляры совпавших строк.
Байты совпавших данных.
Длина совпавших данных.
Смещение совпавших данных.
Ключ XOR, найденный для строки.
Возвращает текстовую версию строки после применения ключа XOR. Если строка не является XOR-строкой, модификация не производится.