Подписывайтесь на наш Telegram и не пропускайте важные новости! Перейти

Исходник Twizzy Bootkit — база для обхода EAC через Physical R/W и Syscall Hook

Sloppy
Начинающий
Начинающий
Статус
Оффлайн
Регистрация
13 Фев 2026
Сообщения
737
Реакции
19
Если вы искали отправную точку для создания своего гипервизора или просто хотите сидеть ниже уровня ядра Windows, то Twizzy — это тот самый скелет, который можно допилить до рабочего продукта. Это буткит, который реализует общение Usermode <-> Bootkit через хук системного вызова в ntoskrnl.

Основная ценность здесь не в «готовой кнопке», а в реализации чтения и записи физической памяти, что до сих пор является базой для обхода большинства современных античитов уровня BattlEye или EAC.

Техническая начинка:
  1. Чтение и запись физической памяти (Physical R/W).
  2. Получение Base Address процесса.
  3. Извлечение CR3 (актуально для обхода защиты памяти в EAC).
  4. Чтение/запись памяти ядра и процессов.
  5. Общение через хук функции NtAcquireProcessActivityReference в ntoskrnl.
Пожалуйста, авторизуйтесь для просмотра ссылки.


Как завести это чудо:
  1. Берем флешку, форматируем в FAT32.
  2. Переименовываем скомпилированный бинарник bootkit.efi в bootx64.efi.
  3. Создаем структуру папок: EFI/BOOT/bootx64.efi.
  4. В BIOS выставляем флешку в приоритет загрузки.
  5. Запускаемся. Если все ок, буткит подгрузится до старта основной ОС.

На данный момент все оффсеты жестко забиты под Windows 10. Если планируете использовать это на 11-й винде или других билдах, придется руками лезть в сурс и обновлять смещения, иначе словите BSOD при первом же вызове. Автор также советует переделать проект в полноценное EFI-приложение, чтобы Windows корректно возвращала память, а не считала её занятой рантайм-драйвером.

Пример Usermode части (коммуникация):
Код:
Expand Collapse Copy
#pragma once
#include <Windows.h>
#include <TlHelp32.h>
#include <cstdint>
#include <Psapi.h>
//twizzy 
constexpr uint64_t luh_magic = 0x12E7A12D; //thx sleepy
constexpr uint64_t luh_kernel_cr3_w10 = 0x1ad000;
constexpr uint64_t luh_kernel_cr3_w11 = 0x1ae000;
typedef struct cmd_t
{
    enum operations : int
    {
        write_physical = 0x0,
        read_physical = 0x1,
        get_cr3 = 0x2,
        get_base = 0x3
    };
 
    int operation;
    uint64_t address;
    uint64_t value;
    uint64_t pid;
    uint64_t magic;
    uint64_t buffer;
    uint64_t size;
 
    uint64_t base;
    uint64_t cr3;
};
 
typedef long( *nt_acquire_process_activity_reference_t )( int64_t, void*, int );
 
class c_bootkit
{
public:
    nt_acquire_process_activity_reference_t hooked_function = 0;
    uint64_t luh_pid = 0;
    uint64_t luh_cr3 = 0;
    bool init( )
    {
        auto ntdll = LoadLibrary( L"ntdll.dll" );
        if ( !ntdll )
            return false;
 
        hooked_function = ( nt_acquire_process_activity_reference_t ) GetProcAddress( ntdll, "NtAcquireProcessActivityReference" );
 
        if ( !hooked_function )
            return false;
 
        return true;
    }
 
    void create_request( cmd_t* cmd )
    {
        cmd->magic = luh_magic;
        hooked_function( ( int64_t ) cmd, 0, 0 );
    }
 
 
    uint64_t get_process_id( const wchar_t* name )
    {
        uint64_t pid = 0;
        auto snapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
 
        PROCESSENTRY32W entry = {};
        entry.dwSize = sizeof( PROCESSENTRY32W );
 
        if ( Process32FirstW( snapshot, &entry ) )
        {
            do
            {
                if ( wcscmp( entry.szExeFile, name ) == 0 )
                {
                    pid = entry.th32ProcessID;
                    break;
                }
            } while ( Process32NextW( snapshot, &entry ) );
        }
 
        luh_pid = pid;
        return pid;
    }
 
    uint64_t get_image_base( )
    {
        cmd_t cmd = { 0 };
        cmd.operation = cmd_t::operations::get_base;
        cmd.pid = luh_pid;
 
        this->create_request( &cmd );
 
        return cmd.base;
    }
 
    uint64_t get_cr3( ) //works on eac
    {
        if ( luh_cr3 )
            return luh_cr3;
 
        cmd_t cmd = { 0 };
        cmd.operation = cmd_t::operations::get_cr3;
        cmd.pid = luh_pid;
 
        create_request( &cmd );
 
        luh_cr3 = cmd.cr3;
        return cmd.cr3;
    }
    
    template <typename t>
    t read_physical( uint64_t address )
    {
        cmd_t cmd = { 0 };
        cmd.address = address;
        t buffer{ };
        cmd.buffer = ( uint64_t ) &buffer;
        cmd.size = sizeof( t );
        cmd.operation = cmd_t::operations::read_physical;
        create_request( &cmd );
 
        return buffer;
    }
 
    template <typename t>
    void write_physical( uint64_t address, t value )
    {
        cmd_t cmd = { 0 };
        cmd.address = address;
        t buffer = value;
        cmd.value = ( uint64_t ) &buffer;
        cmd.size = sizeof( t );
        cmd.operation = cmd_t::operations::write_physical;
        create_request( &cmd );
    }
 
    uint64_t translate_virtual( uint64_t virtual_address, uint64_t cr3 )
    {
        if ( !virtual_address || !cr3 )
            return 0;
        uint64_t pml4_idx = ( virtual_address >> 39 ) & 0x1FF;
        uint64_t pdpt_idx = ( virtual_address >> 30 ) & 0x1FF;
        uint64_t pd_idx = ( virtual_address >> 21 ) & 0x1FF;
        uint64_t pt_idx = ( virtual_address >> 12 ) & 0x1FF;
        uint64_t page = virtual_address & 0xFFF;
        uint64_t pml4_base = cr3 & 0x000FFFFFFFFFF000ULL;
        uint64_t pml4e_raw = pml4_base + ( pml4_idx * 8 );
        uint64_t pml4e = this->read_physical<uint64_t>( pml4e_raw );
 
        if ( !( pml4e & 1 ) )
            return 0;
 
        uint64_t pdpt_base = pml4e & 0x000FFFFFFFFFF000ULL;
        uint64_t pdpte_raw = pdpt_base + ( pdpt_idx * 8 );
        uint64_t pdpte = this->read_physical<uint64_t>( pdpte_raw );
 
        if ( !( pdpte & 1 ) )
            return 0;
 
        if ( pdpte & ( 1ULL << 7 ) )
        {
            uint64_t physical = ( pdpte & 0x000FFFFFC0000000ULL ) | ( virtual_address & 0x000000003FFFFFFFULL );
            return physical;
        }
 
 
        uint64_t pd_base = pdpte & 0x000FFFFFFFFFF000ULL;
        uint64_t pde_raw = pd_base + ( pd_idx * 8 );
        uint64_t pde = this->read_physical<uint64_t>( pde_raw );
 
        if ( !( pde & 1 ) )
            return 0;
 
        if ( pde & ( 1ULL << 7 ) )
        {
            uint64_t physical = ( pde & 0x000FFFFFFFE00000ULL ) | ( virtual_address & 0x00000000001FFFFFULL );
            return physical;
        }
 
        uint64_t pt_base = pde & 0x000FFFFFFFFFF000ULL;
        uint64_t pte_raw = pt_base + ( pt_idx * 8 );
        uint64_t pte = this->read_physical<uint64_t>( pte_raw );
 
        if ( !( pte & 1 ) )
            return 0;
 
        uint64_t physical = ( pte & 0x000FFFFFFFFFF000ULL ) | ( virtual_address & 0x0000000000000FFFULL );
        return physical;
    }
 
    template <typename t>
    t read_kernel( uint64_t address )
    {
        uint64_t physical = this->translate_virtual( address, luh_kernel_cr3_w10 );
        
        if ( !physical )
            return t{ };
 
        return this->read_physical<t>( physical );
    }
 
    template <typename t>
    void write_kernel( uint64_t address, t value )
    {
        uint64_t physical = this->translate_virtual( address, luh_kernel_cr3_w10 );
 
        if ( !physical )
            return;
 
        this->write_physical<t>( physical, value );
    }
 
    template <typename t>
    t read_virtual( uint64_t address )
    {
        uint64_t physical = this->translate_virtual( address, luh_cr3 );
 
        if ( !physical )
            return t{ };
 
        return this->read_physical<t>( physical );
    }
 
    template <typename t>
    void write_virtual( uint64_t address, t value )
    {
        uint64_t physical = this->translate_virtual( address, luh_cr3 );
 
        if ( !physical )
            return;
 
        this->write_physical<t>( physical, value );
    }
 
    uint64_t get_ntoskrnl_base( )
    {
        uint64_t base = 0;
        uint32_t yea = 0;
 
        EnumDeviceDrivers( nullptr, 0, reinterpret_cast< unsigned long* >( &yea ) );
 
        uint32_t count = yea / sizeof( void* );
        void** drivers = new void* [ count ];
 
        if ( EnumDeviceDrivers( drivers, yea, reinterpret_cast< unsigned long* >( &yea ) ) )
            base = reinterpret_cast< uint64_t >( drivers[ 0 ] );
 
        delete[] drivers;
        return base;
    }
};

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

Любителям «пастить и не думать» тут делать нечего, а вот как база для изучения UEFI-разработки и Kernel-моддинга проект более чем достойный. Интересно посмотреть, как этот метод будет чувствовать себя после очередного патча защиты ntoskrnl.
 
Назад
Сверху Снизу