Skip to content

Latest commit

 

History

History
488 lines (311 loc) · 27.2 KB

File metadata and controls

488 lines (311 loc) · 27.2 KB

Использование YARA из Python

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', если применимо, иначе None
  • namespace: пространство имён

И возвращает запрошенные исходные тексты правил в виде одной строки.

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

yara.compile(...)

Компилирует исходные тексты 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: Если произошла ошибка.

yara.load(...)

Изменено в версии 3.4.0

Загружает скомпилированные правила из пути или файлового объекта. Должен быть указан либо filepath, либо file.

Параметры:

Параметр Тип Описание
filepath str Путь к файлу скомпилированных правил.
file file-object Файловый объект, поддерживающий метод read.

Возвращает: Объект скомпилированных правил.

Тип возвращаемого значения: yara.Rules

Исключения:

  • yara.Error: Если произошла ошибка при загрузке файла.

yara.set_config(...)

Устанавливает конфигурационные переменные, доступные через 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: Если произошла ошибка.

Класс Rules

Экземпляры этого класса возвращаются функцией 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: Если произошла ошибка во время сканирования.

Rules.save(...)

Изменено в версии 3.4.0

Сохраняет скомпилированные правила в файл. Должен быть указан либо filepath, либо file.

Параметры:

Параметр Тип Описание
filepath str Путь к файлу.
file file-object Файловый объект, поддерживающий метод write.

Исключения:

  • yara.Error: Если произошла ошибка при сохранении файла.

Класс Match

Добавлено в версии 4.3.0

Объекты, возвращаемые методом yara.Rules.match(), представляющие совпадение.

Атрибут rule

Имя совпавшего правила.

Атрибут namespace

Пространство имён, связанное с совпавшим правилом.

Атрибут tags

Массив строк, содержащий теги, связанные с совпавшим правилом.

Атрибут meta

Словарь, содержащий метаданные, связанные с совпавшим правилом.

Атрибут strings

Список объектов StringMatch.


Класс StringMatch

Добавлено в версии 4.3.0

Объекты, представляющие совпадения строк.

Атрибут identifier

Имя совпавшей строки.

Атрибут instances

Список объектов StringMatchInstance.

Метод is_xor()

Возвращает булево значение, указывающее, использует ли строка модификатор xor.


Класс StringMatchInstance

Добавлено в версии 4.3.0

Объекты, представляющие экземпляры совпавших строк.

Атрибут matched_data

Байты совпавших данных.

Атрибут matched_length

Длина совпавших данных.

Атрибут offset

Смещение совпавших данных.

Атрибут xor_key

Ключ XOR, найденный для строки.

Метод plaintext()

Возвращает текстовую версию строки после применения ключа XOR. Если строка не является XOR-строкой, модификация не производится.