C++ Исходник C++23 библиотека с VMT хуками поиском сигнатур и разными мелочами.

Начинающий
Статус
Оффлайн
Регистрация
12 Ноя 2022
Сообщения
63
Реакции[?]
23
Поинты[?]
3K
Библиотека требует поддержки monadic функций для std::expected и std::optional
Пожалуйста, авторизуйтесь для просмотра ссылки.

Ориентирована на использование в Rust подобном стиле с выклченными исключениями и Error кодами.

RAII VMT хуки сами дестрактятся при выгрузке модуля, потому можно инжектить и выгружать dll множество раз во время разработки.

Ещё есть разного рода мелочи вроде поиска сигнатур с парсингом паттерна во время компиляции и удобный класс для адресов с monadic функциями.

Есть 2 варианта хуков. Unsafe хуки которые меняют оригинальную vmt и safe хуки, которые заменяют vptr объекта на скопированную vmt.
Вот небольшой пример unsafe хуков на SendNetMessage и PostReceivedNetMessage
и safe хука на NetworkSystem::CreateNetChannel для source 2 игр(cs2/d2)

C++:
#include <reutl/safe_vmt.hh>
#include <reutl/scanner.hh>

#include <windows.h>
#include <Psapi.h>
#include <thread>
#include <iostream>
#include <memory>
#include <cstdint>

enum NetChannelBufType : int {
    K_BUF_DEFAULT    = -1,
    K_BUF_UNRELIABLE = 0,
    K_BUF_RELIABLE   = 1,
    K_BUF_VOICE      = 2,
};

struct CNetworkSerializerPB {
    const char* unscoped_name;
    std::uint32_t category_mask;
    [[maybe_unused]] int unk;
    void* pb_binding;
    const char* group_name;
    std::int16_t msg_id;
    std::uint8_t group_id;
    std::uint8_t default_buf_type;
    [[maybe_unused]] std::uint8_t pad[28];
};

std::unique_ptr<reutl::VmHook> g_recv_msg_hk = nullptr;
std::unique_ptr<reutl::VmHook> g_send_msg_hk = nullptr;

auto hook_send_recv_unsafe() -> void
{
    const auto net_chan_vmt =
        reutl::find_pattern_in_module<"40 53 56 57 41 56 48 83 EC ?? 45 33 F6 48 8D 71">(
            "networksystem.dll")
            .value_or(std::nullopt)
            .transform([](const reutl::Addr addr) {
                return addr
                    .offset(0x15) //
                    .deref_instr_rel<std::int32_t>(7)
                    .to_ptr();
            });

    if (!net_chan_vmt) {
        std::cout << "NetChannel signature not found\n";
        return;
    }

    using RecvMsg = auto (*)(void*, CNetworkSerializerPB*, void*, void*, int)->void;

    auto recv_msg_cb = [](void* self, CNetworkSerializerPB* msg_handle, void* pb_msg, void* type,
                          const int bits) -> void {
        std::cout << "recv: " << msg_handle->msg_id << '\n';

        const auto orig = static_cast<RecvMsg>(g_recv_msg_hk->get_orig());
        return orig(self, msg_handle, pb_msg, type, bits);
    };

    g_recv_msg_hk =
        reutl::make_vm_hook(net_chan_vmt.value(), 0x56, static_cast<RecvMsg>(recv_msg_cb))
            .value_or(nullptr);

    if (!g_recv_msg_hk) {
        std::cout << "Error occurred while installing PostReceivedNetMessage hook\n";
        std::abort();
    }

    using SendMsg = auto (*)(void*, CNetworkSerializerPB*, void*, NetChannelBufType)->bool;

    auto send_msg_cb = [](void* self, CNetworkSerializerPB* msg_handle, void* pb_msg,
                          NetChannelBufType buf_type) -> bool {
        std::cout << "send: " << msg_handle->msg_id << '\n';
        const auto orig = static_cast<SendMsg>(g_send_msg_hk->get_orig());

        return orig(self, msg_handle, pb_msg, buf_type);
    };

    g_send_msg_hk =
        reutl::make_vm_hook(net_chan_vmt.value(), 0x45, static_cast<SendMsg>(send_msg_cb))
            .value_or(nullptr);

    if (!g_send_msg_hk) {
        std::cout << "Error occurred while installing PostReceivedNetMessage hook\n";
        std::abort();
    }
}

std::unique_ptr<reutl::SafeVmt> g_nw_sys_vmt = nullptr;

auto safe_net_chan_hk() -> void
{
    using CreateInterface = auto (*)(const char*, int*)->void*;

    const auto create_interface = reinterpret_cast<CreateInterface>(
        GetProcAddress(GetModuleHandleA("networksystem.dll"), "CreateInterface"));

    void* nw_sys = create_interface("NetworkSystemVersion001", nullptr);

    g_nw_sys_vmt = std::make_unique<reutl::SafeVmt>(nw_sys);

    using CreateNetChan = auto (*)(void*, int, void*, const char*, unsigned, unsigned)->void*;

    auto create_net_chan_cb = [](void* self, int unk, void* ns_addr, const char* str, unsigned unk2,
                                 unsigned unk3) -> void* {
        std::cout << "NetChannel created\n";
        const auto orig = static_cast<CreateNetChan>(g_nw_sys_vmt->get_orig(0x1A).value());

        return orig(self, unk, ns_addr, str, unk2, unk3);
    };

    g_nw_sys_vmt->install_hook(0x1A, static_cast<CreateNetChan>(create_net_chan_cb));
}

auto on_inject() -> void
{
    safe_net_chan_hk();
    hook_send_recv_unsafe();
}

auto WINAPI DllMain(HINSTANCE dll, DWORD call_reason, LPVOID reserved) -> BOOL
{
    switch (call_reason) {
    case DLL_PROCESS_ATTACH: {
        AllocConsole();
        freopen_s(reinterpret_cast<FILE**> stdout, "CONOUT$", "w", stdout);
        CreateThread(nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(on_inject), 0, 0, 0);
        break;
    }
    case DLL_PROCESS_DETACH:
        if (reserved != nullptr)
            break; // do not do cleanup if process termination scenario

        // Perform any necessary cleanup.
        fclose(stdout);
        FreeConsole();
        break;
    default:
        break;
    }
    return TRUE;
}

с msvc работает отлично.
На clang будет работать только с 17.0.0 версии. Которая ещё не распространяется и её нужно билдить с исходников.

Есть покрытие тестами, но если встретите баг при использовании - пишите.

Пожалуйста, авторизуйтесь для просмотра ссылки.
 
anonymous
Участник
Статус
Оффлайн
Регистрация
18 Окт 2022
Сообщения
607
Реакции[?]
216
Поинты[?]
144K
Жесть мудрено так мудрено с этим чисто на хакатон ехать
Ноо код шикарный конечно 🅿
 
Ревёрсер среднего звена
Пользователь
Статус
Оффлайн
Регистрация
24 Ноя 2022
Сообщения
303
Реакции[?]
108
Поинты[?]
57K
Библиотека требует поддержки monadic функций для std::expected и std::optional
Пожалуйста, авторизуйтесь для просмотра ссылки.

Ориентирована на использование в Rust подобном стиле с выклченными исключениями и Error кодами.

RAII VMT хуки сами дестрактятся при выгрузке модуля, потому можно инжектить и выгружать dll множество раз во время разработки.

Ещё есть разного рода мелочи вроде поиска сигнатур с парсингом паттерна во время компиляции и удобный класс для адресов с monadic функциями.

Есть 2 варианта хуков. Unsafe хуки которые меняют оригинальную vmt и safe хуки, которые заменяют vptr объекта на скопированную vmt.
Вот небольшой пример unsafe хуков на SendNetMessage и PostReceivedNetMessage
и safe хука на NetworkSystem::CreateNetChannel для source 2 игр(cs2/d2)

C++:
#include <reutl/safe_vmt.hh>
#include <reutl/scanner.hh>

#include <windows.h>
#include <Psapi.h>
#include <thread>
#include <iostream>
#include <memory>
#include <cstdint>

enum NetChannelBufType : int {
    K_BUF_DEFAULT    = -1,
    K_BUF_UNRELIABLE = 0,
    K_BUF_RELIABLE   = 1,
    K_BUF_VOICE      = 2,
};

struct CNetworkSerializerPB {
    const char* unscoped_name;
    std::uint32_t category_mask;
    [[maybe_unused]] int unk;
    void* pb_binding;
    const char* group_name;
    std::int16_t msg_id;
    std::uint8_t group_id;
    std::uint8_t default_buf_type;
    [[maybe_unused]] std::uint8_t pad[28];
};

std::unique_ptr<reutl::VmHook> g_recv_msg_hk = nullptr;
std::unique_ptr<reutl::VmHook> g_send_msg_hk = nullptr;

auto hook_send_recv_unsafe() -> void
{
    const auto net_chan_vmt =
        reutl::find_pattern_in_module<"40 53 56 57 41 56 48 83 EC ?? 45 33 F6 48 8D 71">(
            "networksystem.dll")
            .value_or(std::nullopt)
            .transform([](const reutl::Addr addr) {
                return addr
                    .offset(0x15) //
                    .deref_instr_rel<std::int32_t>(7)
                    .to_ptr();
            });

    if (!net_chan_vmt) {
        std::cout << "NetChannel signature not found\n";
        return;
    }

    using RecvMsg = auto (*)(void*, CNetworkSerializerPB*, void*, void*, int)->void;

    auto recv_msg_cb = [](void* self, CNetworkSerializerPB* msg_handle, void* pb_msg, void* type,
                          const int bits) -> void {
        std::cout << "recv: " << msg_handle->msg_id << '\n';

        const auto orig = static_cast<RecvMsg>(g_recv_msg_hk->get_orig());
        return orig(self, msg_handle, pb_msg, type, bits);
    };

    g_recv_msg_hk =
        reutl::make_vm_hook(net_chan_vmt.value(), 0x56, static_cast<RecvMsg>(recv_msg_cb))
            .value_or(nullptr);

    if (!g_recv_msg_hk) {
        std::cout << "Error occurred while installing PostReceivedNetMessage hook\n";
        std::abort();
    }

    using SendMsg = auto (*)(void*, CNetworkSerializerPB*, void*, NetChannelBufType)->bool;

    auto send_msg_cb = [](void* self, CNetworkSerializerPB* msg_handle, void* pb_msg,
                          NetChannelBufType buf_type) -> bool {
        std::cout << "send: " << msg_handle->msg_id << '\n';
        const auto orig = static_cast<SendMsg>(g_send_msg_hk->get_orig());

        return orig(self, msg_handle, pb_msg, buf_type);
    };

    g_send_msg_hk =
        reutl::make_vm_hook(net_chan_vmt.value(), 0x45, static_cast<SendMsg>(send_msg_cb))
            .value_or(nullptr);

    if (!g_send_msg_hk) {
        std::cout << "Error occurred while installing PostReceivedNetMessage hook\n";
        std::abort();
    }
}

std::unique_ptr<reutl::SafeVmt> g_nw_sys_vmt = nullptr;

auto safe_net_chan_hk() -> void
{
    using CreateInterface = auto (*)(const char*, int*)->void*;

    const auto create_interface = reinterpret_cast<CreateInterface>(
        GetProcAddress(GetModuleHandleA("networksystem.dll"), "CreateInterface"));

    void* nw_sys = create_interface("NetworkSystemVersion001", nullptr);

    g_nw_sys_vmt = std::make_unique<reutl::SafeVmt>(nw_sys);

    using CreateNetChan = auto (*)(void*, int, void*, const char*, unsigned, unsigned)->void*;

    auto create_net_chan_cb = [](void* self, int unk, void* ns_addr, const char* str, unsigned unk2,
                                 unsigned unk3) -> void* {
        std::cout << "NetChannel created\n";
        const auto orig = static_cast<CreateNetChan>(g_nw_sys_vmt->get_orig(0x1A).value());

        return orig(self, unk, ns_addr, str, unk2, unk3);
    };

    g_nw_sys_vmt->install_hook(0x1A, static_cast<CreateNetChan>(create_net_chan_cb));
}

auto on_inject() -> void
{
    safe_net_chan_hk();
    hook_send_recv_unsafe();
}

auto WINAPI DllMain(HINSTANCE dll, DWORD call_reason, LPVOID reserved) -> BOOL
{
    switch (call_reason) {
    case DLL_PROCESS_ATTACH: {
        AllocConsole();
        freopen_s(reinterpret_cast<FILE**> stdout, "CONOUT$", "w", stdout);
        CreateThread(nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(on_inject), 0, 0, 0);
        break;
    }
    case DLL_PROCESS_DETACH:
        if (reserved != nullptr)
            break; // do not do cleanup if process termination scenario

        // Perform any necessary cleanup.
        fclose(stdout);
        FreeConsole();
        break;
    default:
        break;
    }
    return TRUE;
}

с msvc работает отлично.
На clang будет работать только с 17.0.0 версии. Которая ещё не распространяется и её нужно билдить с исходников.

Есть покрытие тестами, но если встретите баг при использовании - пишите.

Пожалуйста, авторизуйтесь для просмотра ссылки.
Не читал, но одобряю
Кончено, сишная парадигма мне всегда будет ближе, чем эта функциональщина, но если захотелось так, то почему бы и нет
 
Начинающий
Статус
Оффлайн
Регистрация
12 Ноя 2022
Сообщения
63
Реакции[?]
23
Поинты[?]
3K
Не читал, но одобряю
Кончено, сишная парадигма мне всегда будет ближе, чем эта функциональщина, но если захотелось так, то почему бы и нет
так expected эрор коды это и есть сишная парадигма, нежели плюсовые эксепшны от которых растёт бинарь и BSODит ядро на ошибку аллокции для вектора.

Rust ближе к си по парадигме чем плюсы. Собственно потому его в linux kernel и взяли. В некст стандарте Си (c2x) будет свой способ возврата значения ошибки через return нежели через inout параметры.

Если ты про монады - это просто сахар который уменьшает кол-во состояний функции. runtime cost нулевой.

пайпы std::range::views/range-v3 тоже самое делает, но у них runtime cost не нулевой почти в 2 раза по перфу просадка из за того что компилятор пропускает некоторые оптимизации.
в README.md написано /std:c++latest если msvc.

если clang -std=c++2b но там нужно билдить с исходников потому что не работает compile time parser для паттерна сигнатуры.

Тестил в голдболте gcc 13 линуксовый частями. Вроде работает. Но mingw 13 где взять и как билдить я хз.
На данный момент доступен только 12. С 12 не работает.
 
Последнее редактирование:
what?
Пользователь
Статус
Оффлайн
Регистрация
10 Мар 2019
Сообщения
302
Реакции[?]
41
Поинты[?]
9K
так expected эрор коды это и есть сишная парадигма, нежели плюсовые эксепшны от которых растёт бинарь и BSODит ядро на ошибку аллокции для вектора.

Rust ближе к си по парадигме чем плюсы. Собственно потому его в linux kernel и взяли. В некст стандарте Си (c2x) будет свой способ возврата значения ошибки через return нежели через inout параметры.

Если ты про монады - это просто сахар который уменьшает кол-во состояний функции. runtime cost нулевой.

пайпы std::range::views/range-v3 тоже самое делает, но у них runtime cost не нулевой почти в 2 раза по перфу просадка из за того что компилятор пропускает некоторые оптимизации.

в README.md написано /std:c++latest если msvc.

если clang -std=c++2b но там нужно билдить с исходников потому что не работает compile time parser для паттерна сигнатуры.

Тестил в голдболте gcc 13 линуксовый частями. Вроде работает. Но mingw 13 где взять и как билдить я хз.
На данный момент доступен только 12. С 12 не работает.
вопрос от новичка. Я так понимаю щас намного лучше учить rust с плюсами для разработки всяких прикольных программ?
 
Ревёрсер среднего звена
Пользователь
Статус
Оффлайн
Регистрация
24 Ноя 2022
Сообщения
303
Реакции[?]
108
Поинты[?]
57K
так expected эрор коды это и есть сишная парадигма, нежели плюсовые эксепшны от которых растёт бинарь и BSODит ядро на ошибку аллокции для вектора.

Rust ближе к си по парадигме чем плюсы. Собственно потому его в linux kernel и взяли. В некст стандарте Си (c2x) будет свой способ возврата значения ошибки через return нежели через inout параметры.

Если ты про монады - это просто сахар который уменьшает кол-во состояний функции. runtime cost нулевой.

пайпы std::range::views/range-v3 тоже самое делает, но у них runtime cost не нулевой почти в 2 раза по перфу просадка из за того что компилятор пропускает некоторые оптимизации.
Нихуя не понял. Но ебаные assert-ные ошибки в STL это и правда пиздец, никаким трай-кетчем не отловишь
Слово "монада" видел только как термин во всяких Хаскеллях(моноид в категории эндофункторов my ass!)
 
Начинающий
Статус
Оффлайн
Регистрация
12 Ноя 2022
Сообщения
63
Реакции[?]
23
Поинты[?]
3K
Нихуя не понял. Но ебаные assert-ные ошибки в STL это и правда пиздец, никаким трай-кетчем не отловишь
Слово "монада" видел только как термин во всяких Хаскеллях(моноид в категории эндофункторов my ass!)
обычных рантайм ассертов в STL если честно не припомню.
может static ассертные ? static ассерт это компайл тайм проверка, это наоборот очень хорошо.
Концепты с++20 делают похожую задачу, но функционала больше.

обычные ассерты тоже хорошая штука, позволяют проверить инвариант.
Чтобы возвращать ошибки только на ошибки среды выполнения. Ну условно там памяти нет для аллокции.
Тоесть ошибки которые от тебя не зависят.

Ассертом же в дебаг сборке проверить то что ты какую то херню в параметры функции не передал например.
Сразу видишь где ошибка произошла, не нужно дебажить.
В релизе ассерты выключаются.

Кстати если прям очень хочется, то ассерты по идее можно трай кэтчем поймать.

либо виндовый SEH __try

либо плюсовый catch(...)
 
Начинающий
Статус
Оффлайн
Регистрация
12 Ноя 2022
Сообщения
63
Реакции[?]
23
Поинты[?]
3K
вопрос от новичка. Я так понимаю щас намного лучше учить rust с плюсами для разработки всяких прикольных программ?
для новичка лучше всего учить plain C. Не прыгать сразу после основ на плюсы, а довести до выского уровня. Потом уже думать.

С другой стороны если начинать с раста, то он выдаёт намного более понятные для новичка ошибки.
Есть хорошая документация и комъюнити.
Но я не уверен что можно его идеи понять полностью, не зная плюсов, причём достаточно современных плюсов.

Не хочу давать советы, слишком субъективно и зависит от твоего типа личности и мозга, пробуй сам и делай выводы что тебе больше подходит.
 
Участник
Статус
Оффлайн
Регистрация
23 Апр 2022
Сообщения
694
Реакции[?]
326
Поинты[?]
12K
Библиотека требует поддержки monadic функций для std::expected и std::optional
Пожалуйста, авторизуйтесь для просмотра ссылки.

Ориентирована на использование в Rust подобном стиле с выклченными исключениями и Error кодами.

RAII VMT хуки сами дестрактятся при выгрузке модуля, потому можно инжектить и выгружать dll множество раз во время разработки.

Ещё есть разного рода мелочи вроде поиска сигнатур с парсингом паттерна во время компиляции и удобный класс для адресов с monadic функциями.

Есть 2 варианта хуков. Unsafe хуки которые меняют оригинальную vmt и safe хуки, которые заменяют vptr объекта на скопированную vmt.
Вот небольшой пример unsafe хуков на SendNetMessage и PostReceivedNetMessage
и safe хука на NetworkSystem::CreateNetChannel для source 2 игр(cs2/d2)

C++:
#include <reutl/safe_vmt.hh>
#include <reutl/scanner.hh>

#include <windows.h>
#include <Psapi.h>
#include <thread>
#include <iostream>
#include <memory>
#include <cstdint>

enum NetChannelBufType : int {
    K_BUF_DEFAULT    = -1,
    K_BUF_UNRELIABLE = 0,
    K_BUF_RELIABLE   = 1,
    K_BUF_VOICE      = 2,
};

struct CNetworkSerializerPB {
    const char* unscoped_name;
    std::uint32_t category_mask;
    [[maybe_unused]] int unk;
    void* pb_binding;
    const char* group_name;
    std::int16_t msg_id;
    std::uint8_t group_id;
    std::uint8_t default_buf_type;
    [[maybe_unused]] std::uint8_t pad[28];
};

std::unique_ptr<reutl::VmHook> g_recv_msg_hk = nullptr;
std::unique_ptr<reutl::VmHook> g_send_msg_hk = nullptr;

auto hook_send_recv_unsafe() -> void
{
    const auto net_chan_vmt =
        reutl::find_pattern_in_module<"40 53 56 57 41 56 48 83 EC ?? 45 33 F6 48 8D 71">(
            "networksystem.dll")
            .value_or(std::nullopt)
            .transform([](const reutl::Addr addr) {
                return addr
                    .offset(0x15) //
                    .deref_instr_rel<std::int32_t>(7)
                    .to_ptr();
            });

    if (!net_chan_vmt) {
        std::cout << "NetChannel signature not found\n";
        return;
    }

    using RecvMsg = auto (*)(void*, CNetworkSerializerPB*, void*, void*, int)->void;

    auto recv_msg_cb = [](void* self, CNetworkSerializerPB* msg_handle, void* pb_msg, void* type,
                          const int bits) -> void {
        std::cout << "recv: " << msg_handle->msg_id << '\n';

        const auto orig = static_cast<RecvMsg>(g_recv_msg_hk->get_orig());
        return orig(self, msg_handle, pb_msg, type, bits);
    };

    g_recv_msg_hk =
        reutl::make_vm_hook(net_chan_vmt.value(), 0x56, static_cast<RecvMsg>(recv_msg_cb))
            .value_or(nullptr);

    if (!g_recv_msg_hk) {
        std::cout << "Error occurred while installing PostReceivedNetMessage hook\n";
        std::abort();
    }

    using SendMsg = auto (*)(void*, CNetworkSerializerPB*, void*, NetChannelBufType)->bool;

    auto send_msg_cb = [](void* self, CNetworkSerializerPB* msg_handle, void* pb_msg,
                          NetChannelBufType buf_type) -> bool {
        std::cout << "send: " << msg_handle->msg_id << '\n';
        const auto orig = static_cast<SendMsg>(g_send_msg_hk->get_orig());

        return orig(self, msg_handle, pb_msg, buf_type);
    };

    g_send_msg_hk =
        reutl::make_vm_hook(net_chan_vmt.value(), 0x45, static_cast<SendMsg>(send_msg_cb))
            .value_or(nullptr);

    if (!g_send_msg_hk) {
        std::cout << "Error occurred while installing PostReceivedNetMessage hook\n";
        std::abort();
    }
}

std::unique_ptr<reutl::SafeVmt> g_nw_sys_vmt = nullptr;

auto safe_net_chan_hk() -> void
{
    using CreateInterface = auto (*)(const char*, int*)->void*;

    const auto create_interface = reinterpret_cast<CreateInterface>(
        GetProcAddress(GetModuleHandleA("networksystem.dll"), "CreateInterface"));

    void* nw_sys = create_interface("NetworkSystemVersion001", nullptr);

    g_nw_sys_vmt = std::make_unique<reutl::SafeVmt>(nw_sys);

    using CreateNetChan = auto (*)(void*, int, void*, const char*, unsigned, unsigned)->void*;

    auto create_net_chan_cb = [](void* self, int unk, void* ns_addr, const char* str, unsigned unk2,
                                 unsigned unk3) -> void* {
        std::cout << "NetChannel created\n";
        const auto orig = static_cast<CreateNetChan>(g_nw_sys_vmt->get_orig(0x1A).value());

        return orig(self, unk, ns_addr, str, unk2, unk3);
    };

    g_nw_sys_vmt->install_hook(0x1A, static_cast<CreateNetChan>(create_net_chan_cb));
}

auto on_inject() -> void
{
    safe_net_chan_hk();
    hook_send_recv_unsafe();
}

auto WINAPI DllMain(HINSTANCE dll, DWORD call_reason, LPVOID reserved) -> BOOL
{
    switch (call_reason) {
    case DLL_PROCESS_ATTACH: {
        AllocConsole();
        freopen_s(reinterpret_cast<FILE**> stdout, "CONOUT$", "w", stdout);
        CreateThread(nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(on_inject), 0, 0, 0);
        break;
    }
    case DLL_PROCESS_DETACH:
        if (reserved != nullptr)
            break; // do not do cleanup if process termination scenario

        // Perform any necessary cleanup.
        fclose(stdout);
        FreeConsole();
        break;
    default:
        break;
    }
    return TRUE;
}

с msvc работает отлично.
На clang будет работать только с 17.0.0 версии. Которая ещё не распространяется и её нужно билдить с исходников.

Есть покрытие тестами, но если встретите баг при использовании - пишите.

Пожалуйста, авторизуйтесь для просмотра ссылки.
Видел эту тему на uc ( noad ) пару дней назад, это твой код?
 
Начинающий
Статус
Оффлайн
Регистрация
12 Ноя 2022
Сообщения
63
Реакции[?]
23
Поинты[?]
3K
А что тогда с конструкторами, с ними же нормально std::expected невозможно использовать, мне приходит в голову только отдельный вариейбл с значением типа как std::optional<ErrorCode>
Или есть пропер вариант?
Хз зачем под хайдом, хороший вопрос, другим может тоже полезно быть.
Тебе экспектед нужен ведь только когда может произойти рантайм ошибка во время конструкции, причём ошибка именно в execution environment, по типу ошибка VirtualAlloc или VirtualProtect, а не просто неправильное значение. Неправильные параметры должны быть отловлены ассертами и static ассертами иначе ты заебёшься на каждый чих свой эррор код делать.

Если у тебя есть возможная ошибка во время конструкции, ты просто делаешь класс с приватным конструктором и friend factory make_something(...).
Вся логика должна быть в фактори функции, которая возвращает expected<Something, ErrCodesEnum>, а именно конструктор просто устанавливает значения, которые ему передаёт фактори.
Это практически паттерн для софта, который пишется без эксепшнов на эррор кодах. Хотя можно просто с конструктора колить std::abort если что то не нравится.

Условно у меня в либе есть class VmHook, во время создания которого может произойти execution environment ошибка при записи в память(VirtualProtect вернёт ошибку), потому сделана специальная factory функция make_vm_hook(...)
Пожалуйста, авторизуйтесь для просмотра ссылки.
которая возвращает expected.

Есть ещё класс Addr (адрес) при конструкции которого никаких env ошибок произойти не может. Потому там просто публичный noexcept конструктор Addr.
Изначально я делал всё на фактори функциях для consistency, но это уродливо выглядило и я решил что нет смысла усложнять код ради consistency.
Пожалуйста, авторизуйтесь для просмотра ссылки.
 
Последнее редактирование:
anonymous
Участник
Статус
Оффлайн
Регистрация
18 Окт 2022
Сообщения
607
Реакции[?]
216
Поинты[?]
144K
Откуда ты так хорошо знаешь c++ давай не пропадай таланту реверси движок и делай хвх чит :pikachu:
 
Начинающий
Статус
Оффлайн
Регистрация
12 Ноя 2022
Сообщения
63
Реакции[?]
23
Поинты[?]
3K
Тогда ещё вопрос, почему ты используешь оператор new вместе с smart ptr, разве в данном случае не лучше использовать make_unique, так как конструктор и так объявлен как явный?
edit: А также можем ли мы использовать std::move, что не копировать ?
make_unique не будет работать для конструктора VmHook(). Конструктор приватный, а make_unique его вызывает.
Есть "трюк" с объявлением unique_ptr как friend класса, но в данном случае не прям особо критично, а так стараюсь make_unique использовать когда возможно.

Да, можно мувать.

1684002079207.png

единственное не особо вижу где их мувать. Обычно хуки и вмтшки в голбальном пространстве хранят. Если только в векторе хранить всё вмтшки или все хуки чтобы при реаллокации мувало.
 
Начинающий
Статус
Оффлайн
Регистрация
12 Ноя 2022
Сообщения
63
Реакции[?]
23
Поинты[?]
3K
Откуда ты так хорошо знаешь c++
Лет 8 на нём пишу с перерывами если считать, но я не очень хорошо знаю. Не задрачивал никогда синтаксис.
В читах знание плюсов(синтаксиса) не решает, да и в целом думаю в большинств достаточно успешных проектов - низкое код квалити.
реверси движок и делай хвх чит
да движок я знаю и так из доты. Может что то и напишу, но точно не хвх. Там за кс нужно шарить, а у меня 10 часов наиграно.
 
Ревёрсер среднего звена
Пользователь
Статус
Оффлайн
Регистрация
24 Ноя 2022
Сообщения
303
Реакции[?]
108
Поинты[?]
57K
в большинств достаточно успешных проектов - низкое код квалити
Так и есть. Помимо того, что сроки и дедлайны вынуждают говнокодить, некоторые люди просто ебанутые на голову
В красивом коде всё-таки что-то есть. Чувствуется моральное превосходство
 
Сверху Снизу