
Regipy — это кроссплатформенная библиотека Python для разбора офлайн-кустов реестра.
⚠️ Критические изменения в v6.0.0
Версия 6.0.0 включает значительные изменения по модернизации:
- Требуется Python 3.9+ — прекращена поддержка Python 3.6, 3.7 и 3.8
- Библиотека
attrsудалена — теперь классы данных используют встроенный модуль Pythondataclasses- Если ваш код импортирует внутренние классы (
Cell,VKRecord,Value,Subkey) и использует функцииattrsнаподобиеattr.asdict(), переключитесь наdataclasses.asdict()Полные сведения см. в CHANGELOG.
Regipy — это библиотека Python для разбора офлайн-кустов реестра (файлы кустов с заголовком REGF). Regipy предоставляет множество возможностей:
Требуется Python 3.9 или выше.
Последнюю версию regipy можно установить из PyPI:
pip install regipy[full]
ПРИМЕЧАНИЕ: regipy[full] устанавливает зависимости, требующие средств компиляции, и может занять некоторое время.
Можно установить версию с облегчёнными зависимостями, опустив [full].
Также возможна установка из исходного кода путём клонирования репозитория и выполнения:
pip install --editable .[full]
Опциональная реализация основного парсера REGF на Rust доступна как
подключаемый бэкенд, опубликованный отдельно на PyPI как
regipy-rs:
pip install regipy[rust]
from regipy.registry_rs import RegistryHive # вместо regipy.registry
reg = RegistryHive('/tmp/NTUSER.dat')
# Тот же API: get_key, iter_values, recurse_subkeys, плагины — всё
# работает без изменений, включая все плагины regipy.
Это взаимозаменяемая замена, проверенная 1:1 с чистым Python-парсером на
всём корпусе тестовых кустов — каждый путь ключа, временная метка, значение
и вывод плагина заверены совпадающими SHA-256 дайджестами обхода (см.
regipy_tests/comparison_test.py и раздел Forensic parity evidence
в regipy-rs/BENCHMARKS.md).
Полный обход со значениями (recurse_subkeys), лучший из 3 запусков:
cProfile показывает причину: в Python-бэкенде время обхода определяется
разбором структур construct для каждой записи и декодированием значений;
с Rust-бэкендом парсер полностью исчезает из профиля, и единственной
оставшейся затратой Python является конструирование возвращаемых dataclass'ов
Subkey. Полные профили, дайджесты для каждого куста и заявление о
нескольких намеренных расхождениях (типы исключений на повреждённых кустах,
поведение защиты от циклов) находятся в
regipy-rs/BENCHMARKS.md;
python regipy-rs/benchmark.py перегенерирует весь отчёт.
Чистый Python-парсер остаётся по умолчанию и не затрагивается, если Rust-бэкенд не установлен.
regipy-parse-header ~/Documents/TestEvidence/Registry/SYSTEM
Пример вывода:
╒════════════════════════╤══════════╕
│ signature │ b'regf' │
├────────────────────────┼──────────┤
│ primary_sequence_num │ 11639 │
├────────────────────────┼──────────┤
│ secondary_sequence_num │ 11638 │
├────────────────────────┼──────────┤
│ last_modification_time │ 0 │
├────────────────────────┼──────────┤
│ major_version │ 1 │
├────────────────────────┼──────────┤
│ minor_version │ 5 │
├────────────────────────┼──────────┤
│ file_type │ 0 │
├────────────────────────┼──────────┤
│ file_format │ 1 │
├────────────────────────┼──────────┤
│ root_key_offset │ 32 │
├────────────────────────┼──────────┤
│ hive_bins_data_size │ 10534912 │
├────────────────────────┼──────────┤
│ clustering_factor │ 1 │
├────────────────────────┼──────────┤
│ file_name │ SYSTEM │
├────────────────────────┼──────────┤
│ checksum │ 0 │
╘════════════════════════╧══════════╛
[2019-02-09 13:46:12.111654] WARNING: regipy.cli: Hive is not clean! You should apply transaction logs
regipy-dump ~/Documents/TestEvidence/Registry/NTUSER-CCLEANER.DAT -o /tmp/output.json
Утилита regipy-dump также может выводить временную шкалу вместо JSON, добавив флаг -t.
regipy-plugins-run ~/Documents/TestEvidence/Registry/SYSTEM -o /tmp/plugins_output.json
Тип куста будет определён автоматически, и будут выполнены соответствующие плагины. См. раздел о плагинах для получения дополнительной информации
Сравните кусты реестра одного типа и выведите результат в CSV (если -o не указан, вывод будет на экран):
regipy-diff NTUSER.dat NTUSER_modified.dat -o /tmp/diff.csv
Пример вывода:
[2019-02-11 19:49:18.824245] INFO: regipy.cli: Comparing NTUSER.DAT vs NTUSER_modified.DAT
╒══════════════╤══════════════╤════════════════════════════════════════════════════════════════════════════════╤════════════════════════════════════════════════╕
│ difference │ first_hive │ second_hive │ description │
╞══════════════╪══════════════╪════════════════════════════════════════════════════════════════════════════════╪════════════════════════════════════════════════╡
│ new_subkey │ │ 2019-02-11T19:46:31.832134+00:00 │ \Software\Microsoft\legitimate_subkey │
├──────────────┼──────────────┼────────────────────────────────────────────────────────────────────────────────┼────────────────────────────────────────────────┤
│ new_value │ │ not_a_malware: c:\temp\legitimate_binary.exe @ 2019-02-11 19:45:25.516346+00:00 │ \Software\Microsoft\Windows\CurrentVersion\Run │
╘══════════════╧══════════════╧════════════════════════════════════════════════════════════════════════════════╧════════════════════════════════════════════════╛
[2019-02-11 19:49:18.825328] INFO: regipy.cli: Detected 2 differences
regipy-process-transaction-logs NTUSER.DAT -p ntuser.dat.log1 -s ntuser.dat.log2 -o recovered_NTUSER.dat
После восстановления сравните кусты с помощью registry-diff, чтобы увидеть, что изменилось.
from regipy.registry import RegistryHive
reg = RegistryHive('/Users/martinkorman/Documents/TestEvidence/Registry/Vibranium-NTUSER.DAT')
for entry in reg.recurse_subkeys(as_json=True):
print(entry)
for sk in reg.get_key('Software').iter_subkeys():
print(sk.name, convert_wintime(sk.header.last_modified).isoformat())
Adobe 2019-02-03T22:05:32.525965
AppDataLow 2019-02-03T22:05:32.526047
McAfee 2019-02-03T22:05:32.526140
Microsoft 2019-02-03T22:05:32.526282
Netscape 2019-02-03T22:05:32.526352
ODBC 2019-02-03T22:05:32.526521
Policies 2019-02-03T22:05:32.526592
reg.get_key('Software\Microsoft\Internet Explorer\BrowserEmulation').get_values(as_json=True)
[{'name': 'CVListTTL',
'value': 0,
'value_type': 'REG_DWORD',
'is_corrupted': False},
{'name': 'UnattendLoaded',
'value': 0,
'value_type': 'REG_DWORD',
'is_corrupted': False},
{'name': 'TLDUpdates',
'value': 0,
'value_type': 'REG_DWORD',
'is_corrupted': False},
{'name': 'CVListXMLVersionLow',
'value': 2097211,
'value_type': 'REG_DWORD',
'is_corrupted': False},
{'name': 'CVListXMLVersionHigh',
'value': None,
'value_type': 'REG_DWORD',
'is_corrupted': False},
{'name': 'CVListLastUpdateTime',
'value': None,
'value_type': 'REG_DWORD',
'is_corrupted': False},
{'name': 'IECompatVersionHigh',
'value': None,
'value_type': 'REG_DWORD',
'is_corrupted': False},
{'name': 'IECompatVersionLow',
'value': 2097211,
'value_type': 'REG_DWORD',
'is_corrupted': False},
{'name': 'StaleCompatCache',
'value': 0,
'value_type': 'REG_DWORD',
'is_corrupted': False}]
from regipy.plugins.ntuser.ntuser_persistence import NTUserPersistencePlugin
NTUserPersistencePlugin(reg, as_json=True).run()
{
'Software\\Microsoft\\Windows\\CurrentVersion\\Run': {
'timestamp': '2019-02-03T22:10:52.655462',
'values': [{
'name': 'Sidebar',
'value': '%ProgramFiles%\\Windows Sidebar\\Sidebar.exe /autoRun',
'value_type': 'REG_EXPAND_SZ',
'is_corrupted': False
}]
}
}
from regipy.plugins.utils import run_relevant_plugins
reg = RegistryHive('/Users/martinkorman/Documents/TestEvidence/Registry/SYSTEM')
run_relevant_plugins(reg, as_json=True)
{
'routes': {},
'computer_name': [{
'control_set': 'ControlSet001\\Control\\ComputerName\\ComputerName',
'computer_name': 'DESKTOP-5EG84UG',
'timestamp': '2019-02-03T22:19:28.853219'
}]
}
Все новые плагины должны иметь один или несколько базовых проверочных случаев (которые могут быть расширены в будущем), например:
from regipy.plugins.system.bam import BAMPlugin
from regipy_tests.validation.validation import ValidationCase
class NTUserUserAssistValidationCase(ValidationCase):
# определите класс вашего плагина
plugin = BAMPlugin
# укажите имя тестового файла, который должен находиться в `regipy_tests/data`
test_hive_file_name = "SYSTEM_WIN_10_1709.xz"
# Используйте `expected_entries` для проверки наличия нескольких образцов из результатов плагина
expected_entries = [
{
"sequence_number": 9,
"version": 1,
"sid": "S-1-5-90-0-1",
"executable": "\\Device\\HarddiskVolume2\\Windows\\System32\\dwm.exe",
"timestamp": "2020-04-19T09:09:35.731816+00:00",
"key_path": "\\ControlSet001\\Services\\bam\\state\\UserSettings\\S-1-5-90-0-1",
}
]
# ИЛИ используйте `exact_expected_result` для проверки точного результата:
exact_expected_result = [
{
"sequence_number": 9,
"version": 1,
"sid": "S-1-5-90-0-1",
"executable": "\\Device\\HarddiskVolume2\\Windows\\System32\\dwm.exe",
"timestamp": "2020-04-19T09:09:35.731816+00:00",
"key_path": "\\ControlSet001\\Services\\bam\\state\\UserSettings\\S-1-5-90-0-1",
},
{
"sequence_number": 8,
"version": 1,
"sid": "S-1-5-90-0-1",
"executable": "\\Device\\HarddiskVolume2\\Windows\\System32\\cmd.exe",
"timestamp": "2020-04-19T09:09:34.544224+00:00",
"key_path": "\\ControlSet001\\Services\\bam\\state\\UserSettings\\S-1-5-90-0-1",
}
]
expected_entries_count = 2
# Клонируйте репозиторий
git clone https://github.com/mkorman90/regipy.git
cd regipy
# Установите в режиме разработки со всеми зависимостями
pip install -e ".[full,dev]"
# Установите pre-commit хуки
pre-commit install
# Запустите все тесты
pytest
# Запустите конкретные тестовые файлы
pytest regipy_tests/tests.py
pytest regipy_tests/cli_tests.py
# Запустите проверку плагинов
PYTHONPATH=. python regipy_tests/validation/plugin_validation.py
# Запустите линтер
ruff check .
# Запустите форматтер
ruff format .
# Запустите проверку типов
mypy regipy/
Чтобы протестировать изменения в CI workflow локально перед отправкой, используйте act:
# Установка act (Fedora)
sudo dnf install act-cli
# Установка act (macOS)
brew install act
# Установка act (другие системы)
# См. https://nektosact.com/installation/index.html
Убедитесь, что Docker запущен, затем:
# Список доступных задач
act -l
# Запустите задачу lint
act -j lint
# Запустите все задачи для события push
act push
# Запустите задачу test с определённой версией Python
act -j test
# Протестируйте задачу build из workflow publish (имитирует релиз)
act release -j build --eventpath /dev/stdin <<< '{"action": "published"}'
Примечание: Некоторые задачи могут требовать секреты. Вы можете указать их с помощью:
act -j publish --secret PYPI_API_TOKEN=your_token
MIT
| Hive | Keys | Python | Rust | Speedup |
|---|
| NTUSER.DAT | 1,812 | 173 ms | 5 ms | 38x |
| UsrClass.dat | 6,205 | 948 ms | 17 ms | 55x |
| amcache.hve | 2,105 | 837 ms | 12 ms | 67x |
| SYSTEM | 30,756 | 23.1 s | 91 ms | 253x |
| SYSTEM (Win10 1709) | 43,211 | 118.7 s | 111 ms | 1,068x |
| SOFTWARE | 117,488 | 745.6 s | 292 ms | 2,550x |