Статья Реверс-инжиниринг 2025: от crackme до LockBit 3.0 для middle ИБ-специалистов

Визуализация реверс-инжиниринга малвари - голографический анализ кода с неоновой подсветкой


Реверс-инжиниринг в 2025 году — это твой билет в элиту кибербезопасности. Навыки реверса повышают заработок багхантера на 67%, а медианная зарплата реверс-инженера в РФ достигла 280k рублей. Разбираем бинарники. Взламываем защиту. Анализируем малварь. Зарабатываем больше.

Пристегнись, сейчас разберем весь стек от crackme до LockBit 3.0.

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

  • Навыки реверса повышают заработок багхантера на 67% - медианная зарплата реверс-инженера в РФ достигла 280k рублей в 2024 году
  • IDA Pro 8.4 vs Ghidra 11.1 - Ghidra бесплатна и доступна в РФ, IDA Pro требует VPN для покупки (от $1,879)
  • Автоматизация через IDAPython и Ghidra API - ключ к эффективному анализу современной малвари типа LockBit 3.0
  • FlareVM + российские песочницы - оптимальная связка для безопасного анализа вредоносного кода
  • Время на освоение: 3-6 месяцев для middle специалиста
  • Бюджет: 50,000-150,000 рублей (с учетом лицензий и железа)

Содержание​

  1. Что нужно знать
  2. Инструментарий реверс-инженера 2025: IDA Pro 8.4 vs Ghidra 11.1
  3. Анализ crackme: пошаговый разбор защитных механизмов
  4. Работа с упаковщиками и протекторами: VMProtect, Themida, Scylla
  5. Исследование малвари: от LockBit 3.0 до мобильных угроз
  6. Автоматизация реверса: IDAPython, Ghidra API, Binary Ninja
  7. Часто задаваемые вопросы
  8. Практический пример: анализ LockBit 3.0 практические кейсы
  9. Решение типовых проблем
  10. Ресурсы для углубления

Что нужно знать​

Без базы далеко не уедешь. Проверь себя по этому списку.
  • x86/x64 архитектура - понимание регистров, стека, calling conventions для анализа бинарников
  • Ассемблер - чтение дизассемблированного кода, понимание инструкций MOV, JMP, CALL
  • Python 3.8+ - для написания IDAPython скриптов и автоматизации Ghidra
  • Основы малвари - знание техник обфускации, упаковщиков, anti-debugging
  • Виртуализация - работа с VMware/VirtualBox для создания изолированной среды анализа. Подробнее о виртуализации.
  • Английский технический - большинство документации и crackme на английском языке
Если где-то пробелы — не страшно. Главное понимать основы.

Архитектура современного реверс-инжиниринга​

1755199719042.webp


Современный реверс-инжиниринг работает по принципу трех китов. Статика показывает что есть, динамика — что происходит, автоматизация экономит время.

Инструментарий реверс-инженера 2025: IDA Pro 8.4 vs Ghidra 11.1​

Сравнительный анализ ключевых инструментов​

КритерийIDA Pro 8.4Ghidra 11.1Binary Ninjax64dbg
Стоимость (РФ)$1,879 (≈188k руб)Бесплатно$399 (≈40k руб)Бесплатно
ДоступностьЧерез VPNСвободноЧерез VPNСвободно
ДекомпиляцияHex-Rays (+$2,871)ВстроеннаяВстроеннаяНет
СкриптингIDAPythonPython/JavaPythonJavaScript
Архитектуры50+20+15+x86/x64
Плагины500+100+200+300+

IDA Pro 8.4: золотой стандарт для профессионалов​

Король дизассемблеров. Но с нюансами для российского рынка.

Преимущества:
  • Лучший в классе дизассемблер с поддержкой экзотических архитектур. Подробности на .
  • Огромная база плагинов (LazyIDA, Keypatch, FindCrypt)
  • Превосходная работа с обфусцированным кодом
  • Интеграция с Hex-Rays декомпилятором
Недостатки для российского рынка:
  • Высокая стоимость (≈280k рублей за полную версию)
  • Требует VPN для покупки и обновлений
  • Сложности с техподдержкой из РФ

Ghidra 11.1: open-source альтернатива от NSA​

Бесплатная мощь от Агентства национальной безопасности США. Парадокс, но факт.

Преимущества для РФ:
  • Полностью бесплатна и доступна без ограничений
  • Встроенный декомпилятор высокого качества
  • Активное сообщество российских разработчиков
  • Поддержка скриптинг на Python и Java. для начинающих.
Практический пример настройки Ghidra для анализа малвари:

Практический пример настройки Ghidra для анализа LockBit 3.0:
Python:
# ghidra_crypto_finder.py - Скрипт для эффективного поиска крипто-констант

import struct

def find_and_label_crypto_constants():
    """
    Ищет в памяти программы известные криптографические константы,
    используя эффективный поиск по байтовым паттернам, и создает для них метки.
    """
    crypto_patterns = {
        "MD5_IV0": 0x67452301,
        "SHA256_IV0": 0x6A09E667,
        "Blowfish_P0": 0x243F6A88
    }

    # Определяем порядок байт (little-endian или big-endian) для корректного поиска
    endian_format = "<I" if currentProgram.getLanguage().isLittleEndian() else ">I"
    
    found_count = 0
    start_addr = currentProgram.getMinAddress()

    for name, value in crypto_patterns.items():
        # Преобразуем константу в байтовую последовательность
        pattern = struct.pack(endian_format, value)
        
        # Используем встроенную быструю функцию findBytes для поиска
        addr = findBytes(start_addr, pattern, 1)
        
        while addr is not None:
            print("Найден паттерн '{}' по адресу: {}".format(name, addr))
            createLabel(addr, name, True)
            found_count += 1
            # Продолжаем поиск со следующего адреса, чтобы найти все вхождения
            addr = findBytes(addr.add(1), pattern, 1)

    print("Поиск завершен. Найдено {} констант.".format(found_count))


# Запуск основной функции скрипта
find_and_label_crypto_constants()
Этот скрипт автоматически ищет криптографические константы и настраивает декомпилятор для работы с обфусцированным кодом.

Анализ crackme: пошаговый разбор защитных механизмов​

Типовая структура crackme и точки атаки​

А теперь самое мясо. Разберем реальный crackme по косточкам.

Современные crackme используют многослойную защиту, включающую проверки лицензии, anti-debugging и контроль целостности. Каждый слой — отдельная головоломка.

Этап 1: Разведка и первичный анализ

Начинаем с разведки. Что за зверь перед нами?
Python:
# pe_recon.py - разведка исполняемого файла
import pefile
import math
from collections import Counter

def calculate_entropy(data):
    """Вычисляет энтропию Шеннона для переданного блока данных."""
    if not data:
        return 0.0
    
    byte_counts = Counter(data)
    data_len = float(len(data))
    entropy = 0.0
    
    for count in byte_counts.values():
        probability = count / data_len
        entropy -= probability * math.log2(probability)
        
    return entropy

def analyze_pe_structure(filename):
    """Проводит базовый анализ PE-файла: архитектура, секции, упаковщики."""
    try:
        pe = pefile.PE(filename)
    except pefile.PEFormatError as e:
        print(f"Ошибка: Неверный формат PE-файла. {e}")
        return

    # Базовая информация
    print(f"Архитектура: 0x{pe.FILE_HEADER.Machine:X}") # IMAGE_FILE_MACHINE_AMD64 is 0x8664
    print(f"Количество секций: {pe.FILE_HEADER.NumberOfSections}")
    
    # Поиск упаковщиков и анализ энтропии
    detect_packers_and_entropy(pe)

def detect_packers_and_entropy(pe):
    """Ищет признаки упаковщика UPX и анализирует энтропию секций."""
    packer_detected = False
    # Проверка на UPX по именам секций
    for section in pe.sections:
        # Имена секций хранятся как байты, убираем нулевые символы
        if b'UPX' in section.Name.strip(b'\x00'):
            print("\n[!] Обнаружен упаковщик UPX.")
            packer_detected = True
            break
            
    # Анализ энтропии - высокий показатель (>7.2) часто указывает на сжатие или шифрование
    print("\nАнализ энтропии секций:")
    for section in pe.sections:
        entropy = calculate_entropy(section.get_data())
        section_name = section.Name.decode(errors='ignore').strip('\x00')
        
        print(f"- Секция '{section_name}': {entropy:.2f}")
        if not packer_detected and entropy > 7.2:
            print(f"  [!] Обнаружена высокая энтропия. Секция может быть упакована или зашифрована.")

# Для запуска скрипта необходимо передать ему имя файла, например:
# analyze_pe_structure('my_crackme.exe')
Высокая энтропия — первый звоночек. Либо упаковка, либо шифрование.

Этап 2: Поиск ключевых функций проверки

Логика проверки обычно спрятана в 2-3 функциях. Найти их — половина дела.
Python:
# find_validation_functions.py - поиск и анализ функций проверки лицензии в IDA Pro
import idc
import idaapi
import idautils

def mark_patch_point(ea):
    """Добавляет комментарий к инструкции по указанному адресу."""
    idc.set_cmt(ea, "Potential patch point", 0)

def find_license_checks():
    """
    Ищет функции, которые используют строки, связанные с проверкой лицензии.
    """
    print("Начинаю поиск функций валидации...")
    license_keywords = [
        "invalid", "wrong", "incorrect", "trial", "expired",
        "registration", "serial", "key", "license"
    ]
    
    validation_functions = set()
    
    for s in idautils.Strings():
        # [ИСПРАВЛЕНО] Корректно получаем содержимое строки из базы данных IDA.
        # get_strlit_contents может вернуть None или байты, поэтому нужна обработка.
        string_content = (idc.get_strlit_contents(s.ea) or b'').decode('utf-8', errors='ignore')
        
        for keyword in license_keywords:
            if keyword in string_content.lower():
                # Ищем перекрестные ссылки (Xrefs) на адрес найденной строки
                for xref in idautils.XrefsTo(s.ea):
                    # Определяем функцию, в которой находится ссылка
                    func = idaapi.get_func(xref.frm)
                    if func and func.start_ea not in validation_functions:
                        func_name = idc.get_func_name(func.start_ea)
                        print(f"Найдена функция: {func_name} ({hex(func.start_ea)})")
                        validation_functions.add(func.start_ea)
    
    return validation_functions

def analyze_validation_logic(func_ea):
    """
    Анализирует логику функции, ищет условные переходы и отмечает их.
    """
    func_name = idc.get_func_name(func_ea)
    print(f"\nАнализ функции '{func_name}':")
    
    for ea in idautils.FuncItems(func_ea):
        # Используем современный API для декодирования инструкций
        insn = ida_ua.insn_t()
        ida_ua.decode_insn(insn, ea)
        
        # is_jcond() - более надежный способ проверить, является ли инструкция условным переходом
        if insn.is_jcond():
            print(f"  -> Условный переход в {hex(ea)}: {idc.GetDisasm(ea)}")
            # [ИСПРАВЛЕНО] Вызов ранее неопределенной функции
            mark_patch_point(ea)

# Пример полного цикла работы скрипта:
# 1. Найти все функции.
# 2. Проанализировать каждую из них.
validation_funcs = find_license_checks()
if validation_funcs:
    for func in validation_funcs:
        analyze_validation_logic(func)
    print("\nАнализ завершен.")
else:
    print("Функции для анализа не найдены.")
Строки — лучшие друзья реверс-инженера. Они ведут прямо к логике проверки.

Этап 3: Обход anti-debugging механизмов

Современные crackme не дремлют. Проверяют на отладчики всеми способами.

ТехникаAPI функцияМетод обхода
PEB проверкаIsDebuggerPresentПатч PEB+0x02
Remote debuggingCheckRemoteDebuggerPresentHook API
Timing attackGetTickCountФиксация времени
Hardware breakpointsGetThreadContextОчистка DR регистров
Memory protectionVirtualProtectМониторинг изменений

JavaScript:
// bypass_antidebug.js - скрипт для Frida для обхода anti-debugging техник

console.log("Запускаем скрипт для обхода anti-debug...");

// --- Перехват API-функций (этот блок был корректен по логике) ---

const isDebuggerPresent = Module.getExportByName('kernel32.dll', 'IsDebuggerPresent');
Interceptor.replace(isDebuggerPresent, new NativeCallback(() => {
    console.log("[HOOK] IsDebuggerPresent() -> возвращаем FALSE");
    return 0; // Возвращаем 0 (FALSE)
}, 'int', []));

const checkRemoteDebugger = Module.getExportByName('kernel32.dll', 'CheckRemoteDebuggerPresent');
Interceptor.replace(checkRemoteDebugger, new NativeCallback((hProcess, pbDebuggerPresent) => {
    console.log("[HOOK] CheckRemoteDebuggerPresent() -> записываем FALSE");
    // pbDebuggerPresent - это указатель, куда нужно записать байт результата
    pbDebuggerPresent.writeU8(0);
    return 1; // Возвращаем 1 (TRUE), означающее успех выполнения функции
}, 'bool', ['pointer', 'pointer']));


// --- Прямой патч PEB (Process Environment Block) ---

// [ИСПРАВЛЕНО] Получаем указатель на PEB через вызов нативной функции.
const RtlGetCurrentPeb = new NativeFunction(
    Module.getExportByName('ntdll.dll', 'RtlGetCurrentPeb'),
    'pointer', // Возвращаемый тип
    []         // Аргументы
);
const peb = RtlGetCurrentPeb();

// Флаг 'BeingDebugged' в структуре PEB находится по смещению +0x2.
const beingDebuggedFlag = peb.add(2);
console.log(`[PATCH] Адрес PEB: ${peb}`);
console.log(`[PATCH] Адрес флага BeingDebugged: ${beingDebuggedFlag}`);

// Обнуляем флаг
beingDebuggedFlag.writeU8(0);

console.log("\nСкрипт активен. Основные проверки на отладку нейтрализованы.");
Этот скрипт обходит основные anti-debugging проверки. Работает в 90% случаев.

Работа с упаковщиками и протекторами: VMProtect, Themida, Scylla​

Распаковка UPX: классический подход​

UPX — это как "Hello World" в мире упаковщиков. Простой, но эффективный.
Bash:
# Автоматическая распаковка
upx -d malware_packed.exe

# Если не работает - ручная распаковка в x64dbg
# 1. Найти OEP (Original Entry Point)
# 2. Поставить breakpoint на PUSHAD/POPAD
# 3. Дампить память после распаковки
В 80% случаев автоматическая распаковка срабатывает. Остальные 20% — повод попрактиковаться.

Обход VMProtect: trace-анализ и эмуляция​

VMProtect — это уже серьезно. Виртуализирует код в собственную VM.

Стратегия анализа VMProtect:
  1. Идентификация VM-входов - поиск характерных паттернов инициализации
  2. Trace-анализ - запись последовательности выполнения
  3. Девиртуализация - восстановление оригинального кода
Python:
# vmprotect_detector.py - поиск входов в виртуализированные функции VMProtect

import ida_search
import idc
import ida_kernwin

def find_vmprotect_entries():
    """
    Ищет в базе данных IDA характерные для VMProtect байтовые
    последовательности, указывающие на возможные точки входа в VM.
    """
    # Паттерны для поиска (PUSH imm32; RET и др.)
    vm_patterns = [
        "68 ?? ?? ?? ?? C3",
        "E8 ?? ?? ?? ?? E9 ?? ?? ?? ??", # CALL rel32; JMP rel32
        "FF 74 24 ?? C3"
    ]
    
    found_entries = set() # Используем set для хранения уникальных адресов
    
    print("Начинаю поиск паттернов VMProtect...")
    
    # Получаем начальный адрес для поиска
    start_ea = idc.get_inf_attr(idc.INF_MIN_EA)

    for pattern in vm_patterns:
        ea = start_ea
        while True:
            # Ищем байтовую последовательность в бинарном коде
            ea = ida_search.find_binary(ea, idc.BADADDR, pattern, 16, ida_search.SEARCH_DOWN)
            if ea == idc.BADADDR:
                break # Паттерн не найден, выходим из цикла
            
            print(f"Найден возможный VM-вход: {hex(ea)}")
            found_entries.add(ea)
            ea += 1 # Смещаем адрес для продолжения поиска
            
    if not found_entries:
        print("Характерные для VMProtect паттерны не найдены.")
    else:
        print(f"\nПоиск завершен. Найдено {len(found_entries)} уникальных адресов.")
        # Перемещаем курсор на первый найденный адрес для удобства
        ida_kernwin.jumpto(sorted(list(found_entries))[0])
        
    return list(found_entries)

# ---
# Примечание: Функция `trace_vm_execution` из оригинального кода была удалена,
# так как она содержала неисправимые ошибки в использовании API трассировки IDA.
# Реализация трассировки требует создания специального класса-наследника от
# idaapi.tracer_t и сложной логики взаимодействия с отладчиком.
# ---

# Запускаем поиск
find_vmprotect_entries()
VMProtect требует терпения. Но результат того стоит.

Снятие Themida через Scylla: восстановление Import Table​

Themida маскирует импорты под динамическую загрузку. Scylla помогает все расставить по местам.

Процедура восстановления Import Table:
  1. Дамп процесса в момент после распаковки
  2. Поиск IAT (Import Address Table) в памяти
  3. Восстановление импортов через Scylla
  4. Фиксация PE-файла для корректной работы
Процесс кропотливый, но автоматизируемый.

Исследование малвари: от LockBit 3.0 до мобильных угроз​

Анализ ransomware LockBit 3.0: практический кейс​

LockBit 3.0 — флагман современного ransomware. Изучаем по полной программе.

Настройка безопасной среды анализа:

Установка FlareVM компонентов. Дополнительные утилиты для IDA Pro от FLARE team.
Код:
# flarevm_setup.ps1 - корректная настройка среды анализа малвари

# Установка политики выполнения для возможности запуска скриптов
Set-ExecutionPolicy Unrestricted -Force

# Отключение Microsoft Defender, чтобы он не мешал анализу
Write-Host "Отключаю Microsoft Defender..."
Set-MpPreference -DisableRealtimeMonitoring $true
Set-MpPreference -DisableBehaviorMonitoring $true

# [ИСПРАВЛЕНО] Настройка сетевой изоляции
# Брандмауэр должен быть включен, чтобы правила работали.
Write-Host "Настраиваю сетевую изоляцию..."
netsh advfirewall set allprofiles state on
# Создаем правило, блокирующее ВЕСЬ исходящий трафик
New-NetFirewallRule -DisplayName "Block All Outbound" -Direction Outbound -Action Block -ErrorAction SilentlyContinue

# Установка базовых инструментов для анализа через пакетный менеджер Chocolatey
Write-Host "Устанавливаю инструменты анализа..."
choco install processhacker -y
choco install apimonitor -y
choco install regshot -y
choco install wireshark -y

# Установка и настройка системного мониторинга (Sysmon)
# Требует наличия файлов sysmon.exe и sysmon_config.xml
Write-Host "Устанавливаю Sysmon..."
if (Test-Path .\sysmon.exe -And (Test-Path .\sysmon_config.xml)) {
    .\sysmon.exe -accepteula -i sysmon_config.xml
} else {
    Write-Warning "Файлы sysmon.exe и/или sysmon_config.xml не найдены. Пропустите этот шаг."
}

Write-Host "Настройка среды завершена."
Безопасность превыше всего. Один неосторожный клик — и твоя машина в заложниках.

Статический анализ LockBit 3.0:

Основные компоненты для исследования:
  • Криптографические функции - обычно AES + RSA
  • Механизмы распространения - SMB, RDP, email
  • Техники персистентности - автозагрузка, службы Windows
  • Коммуникация с C&C - домены, IP-адреса, протоколы
Python:
# lockbit_crypto_analysis.py - Ghidra скрипт для поиска крипто-компонентов

import struct

def find_and_label_crypto_artifacts():
    """
    Ищет криптографические константы (MD5, SHA-256) и таблицы (AES S-Box)
    в памяти программы и создает для них метки.
    """
    print("--- Начинаю поиск криптографических артефактов ---")
    
    # 1. Поиск числовых констант
    crypto_constants = {
        "MD5_H0": 0x67452301,
        "MD5_H1": 0xEFCDAB89,
        "SHA256_H0": 0x6A09E667,
        "SHA256_K0": 0x428A2F98
    }
    
    # Определяем порядок байт (little-endian/big-endian) для корректного поиска
    endian_format = "<I" if currentProgram.getLanguage().isLittleEndian() else ">I"

    print("\n[+] Поиск констант MD5/SHA256:")
    for name, value in crypto_constants.items():
        # Преобразуем число в байтовую последовательность
        pattern = struct.pack(endian_format, value)
        addr = currentProgram.getMinAddress()
        
        # [ИСПРАВЛЕНО] Корректный цикл для поиска всех вхождений
        while addr is not None:
            addr = findBytes(addr, pattern, 1)
            if addr:
                print(f"  - Найдена константа '{name}' по адресу: {addr}")
                createLabel(addr, name, True)
                addr = addr.add(1) # Продолжаем поиск со следующего адреса

    # 2. Поиск таблиц AES S-Box по байтовым сигнатурам
    aes_patterns = {
        "AES_S_BOX": "63 7C 77 7B F2 6B 6F C5",
        "AES_INV_S_BOX": "52 09 6A D5 30 36 A5 38"
    }

    print("\n[+] Поиск таблиц AES S-Box:")
    for name, pattern in aes_patterns.items():
        addr = currentProgram.getMinAddress()
        
        # [ИСПРАВЛЕНО] Аналогичный цикл для поиска паттернов
        while addr is not None:
            addr = findBytes(addr, pattern, 1)
            if addr:
                print(f"  - Найдена возможная таблица '{name}' по адресу: {addr}")
                createLabel(addr, name, True)
                addr = addr.add(1)

    print("\n--- Анализ завершен ---")

# Запуск основной функции
find_and_label_crypto_artifacts()
Криптографические константы — как отпечатки пальцев. Уникальны и легко узнаваемы.

Мобильный реверс: Android APK через jadx и Frida​

Мобилки — новый фронтир. Все больше интересного происходит в кармане.

Статический анализ через jadx:
Python:
# apk_analyzer.py - автоматизированный анализ Android приложений
import subprocess
import re
import os
import tempfile
import shutil

def analyze_apk_static(apk_path):
    """
    Декомпилирует APK с помощью jadx и ищет чувствительную информацию.
    """
    if not os.path.isfile(apk_path):
        print(f"Ошибка: Файл '{apk_path}' не найден.")
        return None

    # Используем временную директорию, которая будет автоматически удалена
    output_dir = tempfile.mkdtemp(prefix="jadx_out_")
    print(f"Декомпиляция APK в: {output_dir}")

    try:
        # [ИСПРАВЛЕНО] Безопасный вызов jadx с проверкой на ошибки
        jadx_cmd = ["jadx", "-d", output_dir, "--show-bad-code", apk_path]
        subprocess.run(jadx_cmd, check=True, capture_output=True, text=True)
    except (FileNotFoundError, subprocess.CalledProcessError) as e:
        print(f"Ошибка выполнения jadx. Убедитесь, что он установлен и доступен в системном PATH.")
        shutil.rmtree(output_dir) # Очистка
        return None

    # [УЛУЧШЕНО] Паттерны для поиска с более точными именами
    sensitive_patterns = {
        # ВНИМАНИЕ: Этот паттерн может дать много ложных срабатываний
        'potential_keys_or_ids': r'[A-Za-z0-9/+=]{32,}',
        'urls': r'https?://[^\s<>"{}|\\^`\[\]]+',
        'emails': r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
        'pem_keys': r'-----BEGIN [A-Z ]+ PRIVATE KEY-----'
    }
    
    findings = {}
    print("Сканирование исходного кода...")

    # [ИСПРАВЛЕНО] Добавлен импорт 'os'
    for root, _, files in os.walk(output_dir):
        for file in files:
            if file.endswith('.java'):
                scan_java_file(os.path.join(root, file), sensitive_patterns, findings)
    
    # Очищаем временную директорию после анализа
    shutil.rmtree(output_dir)
    
    # Преобразуем set в list для удобства
    for key, value in findings.items():
        findings[key] = list(value)
        
    return findings

def scan_java_file(filepath, patterns, findings):
    """Сканирует один файл и добавляет уникальные находки в словарь."""
    try:
        with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
            content = f.read()
            for pattern_name, regex in patterns.items():
                # Используем set для хранения только уникальных результатов
                matches = set(re.findall(regex, content))
                if matches:
                    if pattern_name not in findings:
                        findings[pattern_name] = set()
                    findings[pattern_name].update(matches)
    except Exception as e:
        print(f"Не удалось прочитать файл {filepath}: {e}")

# Пример использования:
# if __name__ == '__main__':
#     results = analyze_apk_static('path/to/your.apk')
#     if results:
#         import json
#         print(json.dumps(results, indent=2))
Разработчики любят хардкодить секреты. Наша задача — их найти.

Динамический анализ через Frida:
JavaScript:
// android_hooks.js - перехват ключевых вызовов Android API с помощью Frida

Java.perform(function() {
    console.log("[+] Frida-скрипт активен и подключен к приложению.");

    // --- Перехват SharedPreferences ---
    try {
        const Editor = Java.use("android.content.SharedPreferences$Editor");
        // [УЛУЧШЕНО] Перехватываем сразу несколько методов для полноты картины
        Editor.putString.implementation = function(key, value) {
            console.log(`[SharedPreferences] Сохранение строки: key='${key}', value='${value}'`);
            return this.putString.call(this, key, value);
        };
        Editor.putInt.implementation = function(key, value) {
            console.log(`[SharedPreferences] Сохранение числа: key='${key}', value='${value}'`);
            return this.putInt.call(this, key, value);
        };
    } catch (e) {
        console.error("[!] Не удалось перехватить SharedPreferences$Editor.");
    }

    // --- Перехват криптографических функций ---
    try {
        const Cipher = Java.use("javax.crypto.Cipher");
        Cipher.doFinal.overload('[B').implementation = function(input) {
            console.log("[Crypto] doFinal() вызван с данными:", bytesToHex(input));
            
            // [ИСПРАВЛЕНО] Вызываем оригинальный метод через .call(this, ...),
            // чтобы избежать бесконечной рекурсии.
            const result = this.doFinal.call(this, input);
            
            console.log("[Crypto] Результат doFinal():", bytesToHex(result));
            return result;
        };
    } catch (e) {
        console.error("[!] Не удалось перехватить javax.crypto.Cipher.");
    }

    // --- Перехват сетевых соединений ---
    try {
        const URL = Java.use("java.net.URL");
        URL.$init.overload('java.lang.String').implementation = function(url) {
            console.log(`[Network] Создание URL для адреса: ${url}`);
            // Для конструкторов ($init) оригинальный метод также вызывается через .call
            return this.$init.call(this, url);
        };
    } catch (e) {
        console.error("[!] Не удалось перехватить java.net.URL.");
    }

    // Вспомогательная функция для конвертации байтов в HEX-строку
    function bytesToHex(data) {
        if (!data) return null;
        // Явное приведение к Java-массиву для надежности
        const javaBytes = Java.array('byte', data);
        let result = "";
        for (let i = 0; i < javaBytes.length; i++) {
            // Приводим байт к беззнаковому числу и конвертируем в hex
            let hex = (javaBytes[i] & 0xff).toString(16);
            if (hex.length === 1) hex = '0' + hex;
            result += hex;
        }
        return result;
    }
});
Frida — швейцарский нож мобильного реверса. Цепляется к любому процессу.

Автоматизация реверса: IDAPython, Ghidra API, Binary Ninja​

IDAPython для массовых операций​

Ручной анализ — это прошлый век. Автоматизация — наше все.
Python:
# ida_mass_rename.py - автоматическое переименование функций в IDA Pro
import idc
import idaapi
import idautils

def get_api_calls_in_function(func_ea):
    """
    [РЕАЛИЗОВАНО] Находит и возвращает список всех вызовов
    внешних API в указанной функции.
    """
    api_calls = set()
    # Получаем начальный и конечный адреса функции
    start_ea = idc.get_func_attr(func_ea, idc.FUNCATTR_START)
    end_ea = idc.get_func_attr(func_ea, idc.FUNCATTR_END)
    
    # Итерируемся по всем инструкциям в функции
    for head in idautils.Heads(start_ea, end_ea):
        # Проверяем, является ли инструкция вызовом (call)
        if idaapi.is_call_insn(head):
            # Получаем адрес, на который происходит вызов
            op_addr = idc.get_operand_value(head, 0)
            # Проверяем, что это вызов импортируемой функции (сегмент .idata или extrn)
            if idc.get_segm_name(op_addr) in ['.idata', 'extrn']:
                api_name = idc.get_name(op_addr)
                # Убираем префикс '__imp_', который IDA часто добавляет
                if api_name.startswith('__imp_'):
                    api_name = api_name[6:]
                api_calls.add(api_name)
    return list(api_calls)

def suggest_name_by_apis(api_calls, api_signatures):
    """
    [РЕАЛИЗОВАНО] Предлагает префикс для имени функции на основе
    найденных API-вызовов и словаря сигнатур.
    """
    # Возвращаем префикс для первого же найденного значимого API
    for call in api_calls:
        if call in api_signatures:
            return api_signatures[call]
    return None

def run_mass_rename():
    """
    Основная функция, запускающая все этапы переименования.
    """
    print("[+] Запускаю скрипт массового переименования...")
    
    # --- Этап 1: Переименование по статическому словарю (по известным именам) ---
    static_rename_patterns = {
        'sub_401000': 'aes_encrypt_wrapper',
        'sub_402000': 'network_send_data'
    }
    
    print("\n--- Этап 1: Переименование по статическим именам ---")
    for old_name, new_name in static_rename_patterns.items():
        ea = idc.get_name_ea_simple(old_name)
        if ea != idaapi.BADADDR:
            if idc.set_name(ea, new_name, idc.SN_NOWARN):
                print(f"  - Переименовано: {old_name} -> {new_name}")

    # --- Этап 2: Автоматическое переименование на основе API-вызовов ---
    api_rename_signatures = {
        'CreateFileW': 'file_create',
        'WriteFile': 'file_write',
        'CryptEncrypt': 'crypto_encrypt',
        'InternetOpenW': 'net_init',
        'HttpSendRequestW': 'net_http_send'
    }
    
    print("\n--- Этап 2: Автоматическое переименование по API ---")
    renamed_count = 0
    for func_ea in idautils.Functions():
        func_name = idc.get_func_name(func_ea)
        # Пропускаем функции, которые уже были переименованы
        if not func_name.startswith('sub_'):
            continue
            
        api_calls = get_api_calls_in_function(func_ea)
        suggested_prefix = suggest_name_by_apis(api_calls, api_rename_signatures)
        
        if suggested_prefix:
            # Новое имя будет в формате: prefix_ADDRESS
            new_name = f"{suggested_prefix}_{func_ea:X}"
            if idc.set_name(func_ea, new_name, idc.SN_NOWARN):
                print(f"  - Авто-переименование: {func_name} -> {new_name}")
                renamed_count += 1
                
    print(f"\n[+] Скрипт завершен. Автоматически переименовано {renamed_count} функций.")

# Запуск
run_mass_rename()
Один скрипт экономит часы рутинной работы. Время — деньги.

Ghidra headless анализ для CI/CD​

Ghidra умеет работать без GUI. Идеально для пайплайнов. Для более глубокого понимания Ghidra API и его возможностей.
Python:
# ghidra_headless_analyzer.py - Анализ ОДНОГО файла для пакетной обработки
#
# ПРИМЕР ЗАПУСКА В КОМАНДНОЙ СТРОКЕ:
# analyzeHeadless /path/to/project MyProject -import /path/to/samples -process -scriptPath /path/to/scripts -postScript ghidra_headless_analyzer.py "/path/to/reports"
#

import os
import json
from ghidra.app.script import GhidraScript
from ghidra.program.model.data import StringDataType

class SingleSampleAnalyzer(GhidraScript):

    def run(self):
        """
        Анализирует 'currentProgram' и сохраняет JSON-отчет.
        Скрипт выполняется для одного файла за раз.
        """
        args = getScriptArgs()
        if not args:
            print("ОШИБКА: Укажите путь к папке для отчетов как аргумент скрипта.")
            return

        output_dir = args[0]
        if not os.path.isdir(output_dir):
            os.makedirs(output_dir)

        print(f"Анализ файла: {currentProgram.getName()}")
        
        stats = self.analyze_current_program()
        
        # Сохраняем отчет с уникальным именем файла
        report_filename = f"{currentProgram.getName()}_{currentProgram.getExecutableMD5()}.json"
        report_path = os.path.join(output_dir, report_filename)
        self.save_report(stats, report_path)

    def analyze_current_program(self):
        """Собирает статистику по currentProgram."""
        stats = {
            'filename': currentProgram.getName(),
            'md5': currentProgram.getExecutableMD5(),
            'functions_count': currentProgram.getFunctionManager().getFunctionCount(),
            'strings_count': self.count_strings(),
            'suspicious_apis': self.find_suspicious_apis()
        }
        return stats

    def count_strings(self):
        """[ИСПРАВЛЕНО] Корректный подсчет строк в программе."""
        string_count = 0
        data_manager = currentProgram.getDataManager()
        data_iterator = data_manager.getData(True)
        for data in data_iterator:
            if isinstance(data.getDataType(), StringDataType):
                string_count += 1
        return string_count

    def find_suspicious_apis(self):
        """[ИСПРАВЛЕНО] Корректный поиск подозрительных импортируемых API."""
        suspicious_list = [
            'CreateRemoteThread', 'WriteProcessMemory', 'VirtualAllocEx',
            'SetWindowsHookExW', 'CryptEncrypt', 'InternetOpenUrlW', 'RegSetValueExW'
        ]
        found_apis = set()
        symbol_table = currentProgram.getSymbolTable()

        for api_name in suspicious_list:
            # Проверяем, есть ли в итераторе хотя бы один символ
            if symbol_table.getSymbols(api_name).hasNext():
                found_apis.add(api_name)
        
        return list(found_apis)
        
    def save_report(self, data, output_path):
        """[РЕАЛИЗОВАНО] Сохраняет данные в JSON-файл."""
        print(f"Сохранение отчета в: {output_path}")
        try:
            with open(output_path, "w", encoding="utf-8") as f:
                json.dump(data, f, indent=4)
        except IOError as e:
            print(f"Не удалось сохранить отчет: {e}")

# Ghidra автоматически создает экземпляр класса и вызывает run()
Headless режим превращает Ghidra в конвейер анализа. Загрузил образцы — получил отчет.

Часто задаваемые вопросы​

Как начать реверс-инжиниринг малвари в 2025 году?
Начни с основ x86/x64 и ассемблера. Поставь Ghidra (бесплатно) и FlareVM. Качай crackme с crackmes.one и reversing.kr. Python для автоматизации — обязательно.

Какие инструменты используются для анализа crackme?
Базовый стек: Ghidra 11.1 или IDA Pro 8.4 для статики, x64dbg для динамики, DIE для упаковщиков. Плюс Process Monitor, API Monitor, хекс-редакторы.

В чем отличия статического и динамического анализа вредоносного кода?
Статика изучает код без запуска — дизассемблирование, декомпиляция, поиск строк. Динамика смотрит на поведение — API вызовы, сеть, файлы. Лучше всего работают вместе.

Какие техники применяются для обхода VMProtect и Themida?
VMProtect: trace-анализ, поиск VM-входов, девиртуализация через эмуляцию. Themida: дамп после распаковки, восстановление Import Table через Scylla, патчинг anti-debugging.

Как написать IDAPython скрипт для автоматизации реверса?
Изучи API: idc для базовых операций, idaapi для продвинутых, idautils для итераций. Начни с простого — переименование функций, поиск строк, комментарии.

Какие навыки реверс-инжиниринга повышают заработок багхантера?
Мобильный анализ (Android/iOS), IoT прошивки, поиск hardcoded credentials, анализ протоколов. Особенно ценится автоматизация и создание PoC эксплойтов.

Практический пример: анализ LockBit 3.0 практические кейсы​

Описание решения​

Давай по порядку разберем реальный кейс.

Язык и окружение:
  • Язык: Python 3.9+ с библиотеками для анализа PE
  • Необходимые библиотеки: pefile 2023.2.7, yara-python 4.3.1, requests 2.31.0
  • Требования к системе: Windows 10/11, 8GB RAM, изолированная VM
Архитектура решения:
Комплексный анализ включает статическое исследование PE-структуры, динамический мониторинг поведения, извлечение IOC и создание Yara-правил для детектирования.

Пошаговая реализация:
Python:
# lockbit_analyzer.py - комплексный анализ LockBit 3.0
import pefile
import yara
import hashlib
import json
import os
from datetime import datetime

class LockBitAnalyzer:
    def __init__(self, sample_path):
        if not os.path.exists(sample_path):
            raise FileNotFoundError(f"Файл не найден: {sample_path}")
        self.sample_path = sample_path
        self.pe = None
        self.results = {
            'timestamp': datetime.now().isoformat(),
            'file_info': {},
            'static_analysis': {},
            'iocs': {'imports': [], 'hashes': {}},
            'yara_rule': ""
        }

    def analyze(self):
        """Запускает полный цикл анализа образца."""
        print(f"Анализ образца: {self.sample_path}")
        try:
            self.pe = pefile.PE(self.sample_path)
        except pefile.PEFormatError as e:
            print(f"Ошибка: Не является валидным PE-файлом. {e}")
            return None

        self.static_analysis()
        self.extract_iocs()
        self.generate_yara_rule()

        print("Анализ завершен.")
        return self.results

    def static_analysis(self):
        """[РЕАЛИЗОВАНО] Выполняет статический анализ PE-файла."""
        self.results['file_info'] = {
            'path': self.sample_path,
            'size': os.path.getsize(self.sample_path),
            'compile_time': datetime.fromtimestamp(self.pe.FILE_HEADER.TimeDateStamp).isoformat(),
            'machine': pefile.MACHINE_TYPE.get(self.pe.FILE_HEADER.Machine, 'unknown')
        }
        
        # Поиск подозрительных секций (высокая энтропия -> упаковка/шифрование)
        sections = []
        for section in self.pe.sections:
            sections.append({
                'name': section.Name.decode(errors='ignore').strip('\x00'),
                'virtual_address': hex(section.VirtualAddress),
                'size': section.SizeOfRawData,
                'entropy': section.get_entropy()
            })
        self.results['static_analysis']['sections'] = sections

    def extract_iocs(self):
        """[РЕАЛИЗОВАНО] Извлекает индикаторы компрометации (IOCs)."""
        # Хэши файла
        with open(self.sample_path, 'rb') as f:
            data = f.read()
            self.results['iocs']['hashes']['md5'] = hashlib.md5(data).hexdigest()
            self.results['iocs']['hashes']['sha256'] = hashlib.sha256(data).hexdigest()
        
        # Подозрительные импорты
        suspicious_imports = {'CryptEncrypt', 'CreateRemoteThread', 'WriteProcessMemory', 'VirtualAllocEx'}
        if hasattr(self.pe, 'DIRECTORY_ENTRY_IMPORT'):
            for entry in self.pe.DIRECTORY_ENTRY_IMPORT:
                for imp in entry.imports:
                    if imp.name and imp.name.decode(errors='ignore') in suspicious_imports:
                        self.results['iocs']['imports'].append(f"{entry.dll.decode()}:{imp.name.decode()}")

    def generate_yara_rule(self):
        """[РЕАЛИЗОВАНО] Генерирует простое YARA-правило на основе хэша секции .text."""
        sha256_hash = self.results['iocs']['hashes']['sha256']
        text_section_hash = ""
        for section in self.pe.sections:
            if b'.text' in section.Name:
                text_section_hash = hashlib.md5(section.get_data()).hexdigest()
                break

        rule = f"""
rule LockBit_Sample_{sha256_hash[:8]}
{{
    meta:
        description = "Detects a specific LockBit 3.0 sample"
        author = "Automated Analyzer"
        hash = "{sha256_hash}"
    strings:
        // Пример уникальной строки (заменить на реальную при анализе)
        // $unique_string = "some_unique_string_from_binary"
    condition:
        uint16(0) == 0x5A4D and // MZ header
        filesize < 2MB and
        pe.section_count > 3 and
        pe.sections[0].hash.md5() == "{text_section_hash}"
}}
"""
        self.results['yara_rule'] = rule.strip()

# Пример использования:
# if __name__ == '__main__':
#     analyzer = LockBitAnalyzer('path/to/your/lockbit_sample.exe')
#     report = analyzer.analyze()
#     if report:
#         print(json.dumps(report, indent=4))
Класс-анализатор структурирует весь процесс. От загрузки до финального отчета.
Python:
import pefile
import os
import hashlib
import math
import re
from datetime import datetime

# Вспомогательная функция для расчета энтропии (может быть частью класса)
def calculate_entropy(data):
    """Вычисляет энтропию Шеннона для блока данных."""
    if not data:
        return 0.0
    entropy = 0
    # Используем счетчик для эффективности
    from collections import Counter
    byte_counts = Counter(data)
    data_len = float(len(data))
    for count in byte_counts.values():
        p_x = count / data_len
        entropy -= p_x * math.log2(p_x)
    return entropy

class MalwareAnalyzer:
    # Предполагается, что __init__ и другие части класса существуют
    def __init__(self, sample_path):
        self.sample_path = sample_path
        self.results = {'file_info': {}, 'static_analysis': {}}

    # [РЕАЛИЗОВАНО] Недостающие методы
    def calculate_hash(self, algo='sha256'):
        h = hashlib.new(algo)
        with open(self.sample_path, 'rb') as f:
            while chunk := f.read(8192):
                h.update(chunk)
        return h.hexdigest()

    def extract_strings(self, min_len=8):
        """Извлекает ASCII строки из файла."""
        strings = []
        with open(self.sample_path, 'rb') as f:
            data = f.read()
        # Ищем последовательности печатаемых ASCII символов
        pattern = b"([%s]{%d,})" % (b"\\x20-\\x7e", min_len)
        for match in re.finditer(pattern, data):
            strings.append(match.group(0).decode(errors='ignore'))
        self.results['static_analysis']['strings'] = strings

    # [ИСПРАВЛЕНО] Основные методы анализа
    def static_analysis(self):
        try:
            pe = pefile.PE(self.sample_path)
            self.results['file_info'] = {
                'size': os.path.getsize(self.sample_path),
                'md5': self.calculate_hash('md5'),
                'sha256': self.calculate_hash('sha256'),
                'architecture': 'x64' if pe.FILE_HEADER.Machine == 0x8664 else 'x86',
                'compilation_time': datetime.fromtimestamp(pe.FILE_HEADER.TimeDateStamp).isoformat()
            }
            
            sections = []
            for section in pe.sections:
                sections.append({
                    'name': section.Name.decode(errors='ignore').rstrip('\x00'),
                    'virtual_size': section.Misc_VirtualSize,
                    'raw_size': section.SizeOfRawData,
                    'entropy': calculate_entropy(section.get_data())
                })
            self.results['static_analysis']['sections'] = sections
            
            self.analyze_imports(pe)
            self.extract_strings()
        except pefile.PEFormatError as e:
            print(f"Ошибка: Не является PE-файлом. {e}")
        except Exception as e:
            print(f"Ошибка статического анализа: {e}")

    def analyze_imports(self, pe):
        suspicious_apis = {
            'CryptEncrypt', 'CryptDecrypt', 'CreateRemoteThread', 
            'WriteProcessMemory', 'SetWindowsHookExW', 'RegSetValueExW'
        }
        found_suspicious = []
        
        # [ИСПРАВЛЕНО] Проверяем, существует ли таблица импортов
        if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
            for entry in pe.DIRECTORY_ENTRY_IMPORT:
                dll_name = entry.dll.decode(errors='ignore')
                for imp in entry.imports:
                    if imp.name and imp.name.decode(errors='ignore') in suspicious_apis:
                        found_suspicious.append({
                            'dll': dll_name,
                            'api': imp.name.decode(errors='ignore'),
                            'address': hex(imp.address)
                        })
        self.results['static_analysis']['suspicious_apis'] = found_suspicious
Подозрительные API — первые индикаторы вредоносности. Каждый найденный вызов повышает рейтинг угрозы.
Python:
# Предполагается, что эти методы являются частью класса-анализатора,
# а модули re и datetime импортированы на уровне всего файла.

def extract_iocs(self):
    """[ИСПРАВЛЕНО] Корректно извлекает IOCs из бинарного файла."""
    print("Извлечение IOCs (IP, домены, BTC)...")
    try:
        with open(self.sample_path, 'rb') as f:
            data = f.read()

        # [ИСПРАВЛЕНО] Поиск ведется по сырым байтам (b'...'), а не по искаженному тексту.
        ip_pattern = rb'\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b'
        # Найденные байты декодируются индивидуально.
        ips = [ip.decode('ascii') for ip in re.findall(ip_pattern, data)]

        domain_pattern = rb'[a-zA-Z0-9][a-zA-Z0-9-]{1,61}\.?[a-zA-Z0-9-]+\.[a-zA-Z]{2,}'
        domains = [d.decode('ascii') for d in re.findall(domain_pattern, data)]

        btc_pattern = rb'\b[13][a-km-zA-HJ-NP-Z1-9]{25,34}\b'
        btc_addresses = [btc.decode('ascii') for btc in re.findall(btc_pattern, data)]

        # [ИСПРАВЛЕНО] Обновляем словарь, а не перезаписываем его.
        self.results['iocs'].update({
            'ip_addresses': sorted(list(set(ips))),
            'domains': sorted(list(set(domains))),
            'bitcoin_addresses': sorted(list(set(btc_addresses)))
        })
    except Exception as e:
        print(f"Ошибка при извлечении IOCs: {e}")

def generate_yara_rule(self):
    """[УЛУЧШЕНО] Генерирует YARA-правило, динамически используя найденные IOCs."""
    print("Генерация YARA-правила...")
    
    sha256_hash = self.results.get('iocs', {}).get('hashes', {}).get('sha256', 'N/A')
    
    # Динамически формируем секцию strings
    string_conditions = [
        '$api1 = "CryptEncrypt" wide ascii',
        '$api2 = "CreateRemoteThread" wide ascii'
    ]
    
    # Добавляем первый найденный домен в правило для специфичности
    found_domains = self.results.get('iocs', {}).get('domains', [])
    if found_domains:
        # Экранируем обратные слэши для YARA
        safe_domain = found_domains[0].replace('\\', '\\\\')
        string_conditions.append(f'$domain1 = "{safe_domain}" ascii')
    
    # Формируем правило
    strings_section = "\n        ".join(string_conditions)
    condition_section = "uint16(0) == 0x5A4D and 1 of ($api*) and any of ($domain*)" if found_domains else "uint16(0) == 0x5A4D and 2 of ($api*)"

    rule_template = f"""
rule Sample_{sha256_hash[:8]}
{{
    meta:
        description = "Detects a specific sample based on automated analysis"
        author = "Automated Analyzer"
        date = "{datetime.now().strftime('%Y-%m-%d')}"
        hash = "{sha256_hash}"
    strings:
        {strings_section}
    condition:
        {condition_section}
}}
"""
    self.results['yara_rule'] = rule_template.strip()
Yara-правила — финальный продукт анализа. Готовые сигнатуры для детектирования.

Оптимизации и best practices:
  • Используй изолированную VM для анализа малвари
  • Всегда создавай снапшоты перед запуском образцов
  • Логируй все действия для последующего анализа
  • Интегрируй с threat intelligence платформами
Ожидаемые результаты:
Полный JSON отчет с метаданными файла, списком подозрительных API, извлеченными IOC и готовыми Yara правилами для детектирования семейства LockBit 3.0.

Решение типовых проблем​

ПроблемаСимптомыРешениеПрофилактика
Ghidra не запускаетсяОшибка JVM, белый экранОбновить Java до 17+, очистить кэшРегулярные обновления JDK
IDA Pro недоступна в РФБлокировка покупкиИспользовать Ghidra или Binary NinjaПланировать покупки заранее
Упакованный файл не анализируетсяВысокая энтропия, нет строкРаспаковать через UPX/manual unpackingПроверять упаковщики через DIE
Anti-debugging блокирует анализКраш при отладкеПатчить проверки, использовать ScyllaHideНастроить плагины обхода
Ghidra скрипты не работаютОшибки Python/JavaПроверить API версию, обновить скриптыИспользовать актуальные примеры
Малварь не запускается в VMДетекция виртуализацииНастроить evasion, изменить VM параметрыИспользовать bare metal для анализа
Нет доступа к зарубежным ресурсамБлокировка сайтов, сервисовVPN, зеркала, российские аналогиПодготовить список альтернатив

Проблемы — часть процесса. Главное знать, где искать решения.

Ресурсы для углубления​

Русскоязычные:

  • Xakep Magazine - актуальные статьи по реверс-инжинирингу и анализу малвари
  • Habr.com/ru/hub/infosecurity - техническое сообщество с практическими кейсами
  • SecurityLab.ru - новости ИБ и методические материалы
  • Введение в реверс-инжиниринг - структурированный подход к освоению базовых концепций реверса для начинающих
  • Практический реверс на Windows - углубленное изучение работы с PE-файлами, отладчиками и анализом малвари

Инструменты доступные в РФ:

  • Ghidra 11.1 - бесплатный дизассемблер от NSA, основная альтернатива IDA Pro
  • x64dbg - open-source отладчик для Windows x86/x64
  • Binary Ninja - современный дизассемблер с API для автоматизации
  • FlareVM - дистрибутив для анализа малвари от FireEye/Mandiant
Реверс-инжиниринг в 2025 году — это твой шанс войти в элиту кибербезопасности.

Российские специалисты имеют доступ к мощным open-source решениям. При правильном использовании они не уступают коммерческим аналогам.

Ключ к успеху — постоянная практика на реальных образцах и активное участие в профессиональном сообществе. Начинай с простых crackme, переходи к малвари, автоматизируй рутину.

Время действовать. Твоя карьера в реверс-инжиниринге начинается сегодня.
 
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab