Конвары и конкомманды

Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
(микротуториал)
все квары и комманды(и прочие плюхи) есть тут(дамп от 08.09.2022)
Пожалуйста, авторизуйтесь для просмотра ссылки.
с новой обновой очень сильно реворкнули квары.
1) находим сами квары:
Берем интерфейс(CreateInterface)(
Пожалуйста, авторизуйтесь для просмотра ссылки.
)
tier0.dll:
VEngineCvar007 -> CCvar
в нем тыкаем на все интересное(и внутри того на что тыкали так же тыкаем)
1662575219600.png
на оффсете 0x40 лежит кучка интересностей
1662575265900.png
обсматриваем эти интересности
1662575303200.png
ну думаю очевидно что это конвар

сразу в консоли замечаем что тип квара у нас boolean(true/false)

видим что структура квара имеет размер 80 байт
первый указатель это имя
второй указатель не интересен нам(он указывает на некст квар токо не совсем на него а на ячейку перед ним но не суть. у нас и так все квары в массиве зачем нам некст)
третий и четвертый указатели(если это указатели) нам пока не интересны они везде по нулям
пятая ячейка это забегая вперед скажу - два инта: тип и какаято хуита
дальше идёт инт флаги
дальше идёт указатель на какуюто хуйню
дальше идёт юнион значения.
чтобы определить где там тип где там что, берем квары разных типов и сравниваем что же у них разное


сразу бросается в глаза после описания идёт какойто инт который у обоих различается
и потом еще ниже тоже различается инт(это флаги)
простой способ проверить - тупо МЕНЯЕМ эти неизвестные хрени.
у tv_broadcast_url например семёрку меняем на ноль
до модификации:

после:

ну сразу видим что это оказывается ТИП конвара, и судя по всему 0 это булеана, а 7 это строка(остальные значения этого енума находятся аналогично - меняем тупо от 0 до 1 2 3 4 5 и тд и тп и проверяем в консоли значение(и выставляем его тоже для проверки. например пробуем отрицательное значение поставить, пробуем огромное, пробуем дробное и тд и тп) пока у нас не крашнет xD)
енум сразу скажу вот такой
C++:
    enum class EConvarType : std::uint8_t
    {
        BOOL = 0,
        INT32,
        UINT32,
        INT64,
        UINT64,
        FLOAT,
        DOUBLE,
        STRING,
        COLOR_RGBA,
        UNK_SOME_TWO_FLOATS,
        UNK_SOME_THREE_FLOATS,
        UNK_SOME_FOUR_FLOATS,
        UNK_SOME_THREE_FLOATS_AGAIN,
    };
там к концу идут массивы из флоатов от 2 до 4 элементов размером
ну и тот же самый способ для определения оффсета флагов - ищем какие-нибудь квары с флагами которые отображаются в консольке в find, смотрим структуру этих кваров, меняем подозрительные поля смотрим что происходит с флагами в консольке в find. способ "меняй и смотри что будет"
теперь давайте посчитаем количество кваров в этом списке кваров
возвращаемся к списку, скроллим дохуя в реклассе и находим конец визуально(ну находим точку где начинается мусор)


мы видим что вот это у нас последний валидный квар в списке
просто выделяем от конца до начала

67616 видим размер общий. размер одного узла явно 8+8 байт(указатель на конвар и какойто индексо-подобный шлак), делим 67616 на 16 = 4226
ищем 4226 в нашем CCvar

нашли парочку, перезапускаем доту там чекаем тестим выбираем какую-нибудь смотрим какая переменная не ломается и правильно отображает колво кваров. я например взял ту что на 0x58 мне она красивее кажется
вот вам и контейнер
начало на 0x40, размер в типе uint16 на 0x58,
элемент структурой:
C++:
    struct CvarNode
    {
        ConVariable* var{};
        int some_leaf_like_index_shit{};
    };
сам квар вот такой
C++:
union ConVarValue
{
    bool boolean{};
    std::uint64_t u64;
    std::int64_t i64;
    std::uint32_t u32;
    std::int32_t i32;
    float flt;
    double dbl;
    const char* str;
    std::uint32_t clr_rgba;
    std::array<float, 2> two_floats;
    std::array<float, 3> three_floats;
    std::array<float, 4> four_floats;
};

struct ConVariable
{
    const char* name{};
    void* next_convar_node_like_shit{};
    void* unk1{};
    void* unk2{};
    const char* help{};
        EConvarType type{};
        int unk_maybe_number_of_times_changed{};
        int flags{};
        int unk4{};
        int CALLBACK_INDEX{};
        int unk5{};
        ConVarValue value{};
}
ну собсна вот вам и квары, бегаете по всему списку находите нужный по имени ставите нужное значение в соответствии с типом квара.
таким же способом находятся и конкомманды - тыкаем на все интересное находим чтото подозрительное

структура там простенькая
C++:
struct ConCmd
{
    const char* name{};
    const char* help{};
    int flags{};
    void* accessor{};
    void* accessor_related_shit_maybe{};
    int shit_unk{};
    int CallbackListIndex{};
};
самих именно коллбеков комманд нет прямо там в структуре, но в структере есть индекс коллбека.
массив коллбеков лежит рядом на 0x118

2) регистрация конкомманд
я например еще люблю регать свои консольные команды это весело(понятно что лучше сделать меню и тд и тп)
хотите зарегать свою команду - смотрите как регаются команды в доте(например cl_ent_find_index возьмём). ищем какую-нибудь команду по строке
видим такую картину

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


ну кароче вот так вот команды регаются.
C++:
    struct ConCMDID
    {
        static inline constexpr auto BAD_ID = 0xFFFF;
        std::uint64_t impl{};

        bool IsGood() const noexcept
        {
            return impl != BAD_ID;
        }

        void Invalidate() noexcept
        {
            impl = BAD_ID;
        }
    };
struct ConCMDRegistrationInfo
    {
        const char* cmd_name{};
        const char* help_str{};
        std::uint64_t flags{};
        void* callback{};
        void* unk1{};
        void* unk2{};
        void* unk3{};
        void* output_id_holder{};
    };
    ConCommandSource2(const std::string_view& name, const std::string_view& desc, void(* callback)(void*, const CCommand&))
    {
        ICvar::ConCMDRegistrationInfo info{};
        info.cmd_name = name.data();
        info.help_str = desc.data();
        info.callback = callback;
        info.output_id_holder = this;
        Constructor::Invoke(&info);
    }
    ...
//CCvar VVV
    private:
    //search for xrefs for constructed concmd variables.
    static inline constexpr auto UnRegisterCMDVFTable_Index = 38;
public:
    auto UnRegisterCMD(const ConCMDID& id)
    {
        CallVFunc<UnRegisterCMDVFTable_Index>(id);
    }
пример кастомной команды:

3) выставление значений кварам с учётом уведомления об изменении
смотрим в квар который просто так не меняется(требует уведомления), например dota_camera_distance
смотрим в реклассе и ищем подозрительные вещи. мне например сразу же в глаза бросилось

ставим хвбп дворд на чтение, меняем конвар из консоли:

сразу видим что наша 84 летит в edi, потом edi летит в eax, потом eax умножается на три(а потом еще на 8, то есть итого на двадцать четыре) потом это дерьмо прибавляется к rsi+80. смотрим что же там на rsi(это CCvar) + 0x80:


очевидно что это таблица коллбеков кваров. окей дальше
берем наш коллбек от dota_camera_distance(ну 0x84 умножаем на 24 и прибавляем к [CCvar + 0x80])
ставим бп чекаем арги(чекнув место вызова функции)

на скрине видно 4 аргумента(rcx, edx, r8, r9) типы чисто судя по размеру регистров void*, int, void*, void*
сразу скажу кароче коллбек выглядит вот так(один из аргументов неизвестен. ну я ноль передаю вроде с св читс и дистанцией камеры работает собственно)
C++:
    struct ConVarID
    {
        static inline constexpr auto BAD_ID = 0xFFFFFFFF;
        std::uint64_t impl{};
        void* var_ptr{};

        bool IsGood() const noexcept
        {
            return impl != BAD_ID;
        }

        void Invalidate() noexcept
        {
            impl = BAD_ID;
        }
    };
using t_CvarCallback = void(*)(const ConVarID& id, int unk1, const ConVarValue* val, const ConVarValue* old_val);
вот например св читс + дистанция камеры:
C++:
/*
    t_CvarCallback GetCVarCallback(int index)
    {
        if (index)
        {
            auto table = Member<void*>(0x80);
            if (table)
                return *reinterpret_cast<t_CvarCallback*>(reinterpret_cast<std::uintptr_t>(table) + 24 * index);
        }
        return nullptr;
    }
*/
            /*
                auto CCvar::GetCvarList() const noexcept
                {
                    return std::span<const CvarNode>{ Member<const CvarNode*>(0x40), Member<std::uint16_t>(0x58) };
                }
            */
         
for (const auto& [cvar_node, idx] : ICvar::Create()->GetCvarList() | indexed_range)
            {
                if (cvar_node.var)
                {
                    if (make_stringview(cvar_node.var->name) == "dota_camera_distance")
                    {
                        const auto old_val = cvar_node.var->value;
                        cvar_node.var->value.flt = 2222.0f;
                        if (auto cb = ICvar::Create()->GetCVarCallback(cvar_node.var->CALLBACK_INDEX); cb)
                            cb(ICvar::ConVarID{ .impl = static_cast<std::uint64_t>(idx), .var_ptr = (void*)&cvar_node},
                                0, &cvar_node.var->value, & old_val);
                    }
                    if (make_stringview(cvar_node.var->name) == "sv_cheats")
                    {
                        const auto old_val = cvar_node.var->value;
                        cvar_node.var->value.boolean = true;
                        if (auto cb = ICvar::Create()->GetCVarCallback(cvar_node.var->CALLBACK_INDEX); cb)
                            cb(ICvar::ConVarID{ .impl = static_cast<std::uint64_t>(idx), .var_ptr = (void*)&cvar_node },
                                0, &cvar_node.var->value, &old_val);
                    }
                }
            }
 
Последнее редактирование:
Начинающий
Статус
Оффлайн
Регистрация
28 Июн 2022
Сообщения
15
Реакции[?]
1
Поинты[?]
1K
C++:
    struct ConCMDID
    {
        static inline constexpr auto BAD_ID = 0xFFFF;
        std::uint64_t impl{};

        bool IsGood() const noexcept
        {
            return impl != BAD_ID;
        }

        void Invalidate() noexcept
        {
            impl = BAD_ID;
        }
    };
struct ConCMDRegistrationInfo
    {
        const char* cmd_name{};
        const char* help_str{};
        std::uint64_t flags{};
        void* callback{};
        void* unk1{};
        void* unk2{};
        void* unk3{};
        void* output_id_holder{};
    };
    ConCommandSource2(const std::string_view& name, const std::string_view& desc, void(* callback)(void*, const CCommand&))
    {
        ICvar::ConCMDRegistrationInfo info{};
        info.cmd_name = name.data();
        info.help_str = desc.data();
        info.callback = callback;
        info.output_id_holder = this;
        Constructor::Invoke(&info);
    }
    ...
//CCvar VVV
    private:
    //search for xrefs for constructed concmd variables.
    static inline constexpr auto UnRegisterCMDVFTable_Index = 38;
public:
    auto UnRegisterCMD(const ConCMDID& id)
    {
        CallVFunc<UnRegisterCMDVFTable_Index>(id);
    }
can you please tell what is CCommand and Constructor::Invoke ?

Код:
CvarNode* node = (*(CvarNode**)this);
if (strcmp(node1->var->name, "dota_camera_distance") == 0)
            {
                node->var->value.flt = 3000.0f;
            }
i already have list of cvar and i want to change dota_camera_distance but now i need the callback registercommand to update
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
can you please tell what is CCommand and Constructor::Invoke ?

Код:
CvarNode* node = (*(CvarNode**)this);
if (strcmp(node1->var->name, "dota_camera_distance") == 0)
            {
                node->var->value.flt = 3000.0f;
            }
i already have list of cvar and i want to change dota_camera_distance but now i need the callback registercommand to update
(THIS IS FOR REGISTERING YOUR OWN CONSOLE COMMANDS)
CComand is the wrapper for arguments that are passed on the console(see source code of the source engine
Пожалуйста, авторизуйтесь для просмотра ссылки.
). just ignore it if you don't need to parse any arguments in your command
Constructor::Invoke is the invocation of this function:
1662622083100.png
 
Последнее редактирование:
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
дамп еще актуальный?
ну я обновил дамп(08.09.2022), но вопрос в том что для тебя значит "актуальный".
эти дампы они предназначены не для использования в игре а просто для того чтобы посмотреть как что делать какие нетвары есть какие типы и тд какие имена и типы интерфейсов и в каких модулях, какие геймсистемы есть и тд и тп
если тебе нужны оффсеты - так бери их на рантайме с шемы и не парься. в дампе ты токо смотришь что и где брать, а сам оффсет берешь с шемы уже внутри игры, там несложно
 
Shitcode lord 💩
Забаненный
Статус
Оффлайн
Регистрация
25 Ноя 2020
Сообщения
272
Реакции[?]
84
Поинты[?]
8K
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Как же раньше всё просто было. FindCommand("dota_camera_distance")->SetFloat(1500);
А сейчас как? Я ни хрена не понял, как с коллбеками работать. Если до игры указывать -- всё ок. В игре -- меняется только в кносли значение.
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
Как же раньше всё просто было. FindCommand("dota_camera_distance")->SetFloat(1500);
А сейчас как? Я ни хрена не понял, как с коллбеками работать. Если до игры указывать -- всё ок. В игре -- меняется только в кносли значение.
ну да. я приду отпишусь потом как пофиксить
 
Начинающий
Статус
Оффлайн
Регистрация
28 Июн 2022
Сообщения
15
Реакции[?]
1
Поинты[?]
1K
ну да. я приду отпишусь потом как пофиксить
in CSGO callback is inside IConvar class, but now its hard to work with convar after update dota2 7.32b, it used to be so easy before .
Пожалуйста, авторизуйтесь для просмотра ссылки.
Код:
static ConVar* vmFov = interfaces.cvar->findVar("viewmodel_fov");
    if (vmFov)
    {
        vmFov->onChangeCallbacks.size = 0; // set to 0 for callback
        vmFov->setValue(vars::viewModelFov);
    }
 
Shitcode lord 💩
Забаненный
Статус
Оффлайн
Регистрация
25 Ноя 2020
Сообщения
272
Реакции[?]
84
Поинты[?]
8K
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
А че, ExecuteClientCmd с концами же выпилили, да? Не вижу её. Так-то камеру можно было бы и через неё менять, без лишних заморочек.
 
Пользователь
Статус
Оффлайн
Регистрация
8 Апр 2022
Сообщения
663
Реакции[?]
104
Поинты[?]
67K
А че, ExecuteClientCmd с концами же выпилили, да? Не вижу её. Так-то камеру можно было бы и через неё менять, без лишних заморочек.
а зачем можно же вот так функу из панорамы скрипта вызывать
PanoramaScript__SetCameraDistance(global::PanoramaScript_GameUI, camera_dist);
 
Shitcode lord 💩
Забаненный
Статус
Оффлайн
Регистрация
25 Ноя 2020
Сообщения
272
Реакции[?]
84
Поинты[?]
8K
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
а зачем можно же вот так функу из панорамы скрипта вызывать
PanoramaScript__SetCameraDistance(global::PanoramaScript_GameUI, camera_dist);
Ну давай тогда вообще в консоль руками писать будем.
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
у sv cheats даже если меняешь значение все равно ничего не меняется
in CSGO callback is inside IConvar class, but now its hard to work with convar after update dota2 7.32b, it used to be so easy before .
Пожалуйста, авторизуйтесь для просмотра ссылки.
Код:
static ConVar* vmFov = interfaces.cvar->findVar("viewmodel_fov");
    if (vmFov)
    {
        vmFov->onChangeCallbacks.size = 0; // set to 0 for callback
        vmFov->setValue(vars::viewModelFov);
    }
Как же раньше всё просто было. FindCommand("dota_camera_distance")->SetFloat(1500);
А сейчас как? Я ни хрена не понял, как с коллбеками работать. Если до игры указывать -- всё ок. В игре -- меняется только в кносли значение.
гайд обновил читаем секцию
"3) выставление значений кварам с учётом уведомления об изменении"
также обновил немножко структуру ConVariable
 
Пользователь
Статус
Оффлайн
Регистрация
8 Апр 2022
Сообщения
663
Реакции[?]
104
Поинты[?]
67K
/del был не тот индекс
 
Последнее редактирование:
Пользователь
Статус
Оффлайн
Регистрация
8 Апр 2022
Сообщения
663
Реакции[?]
104
Поинты[?]
67K
а как регать не конкомманды а конвары? типо с мин и макс значением, и т.д.
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
Сверху Снизу