Гайд Продолжение серии. шема(оффсеты)+локал игрок

Участник
Статус
Онлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
1) хп - C_BaseEntity::m_iHealth
2) имя персонажа - можно из айдентити брать(CEntityInstance::m_pEntity, CEntityIdentity::m_name), можно C_DOTA_BaseNPC::m_iszUnitName
3) это не ентитилист, это список объектов типа C_NextBotCombatCharacter(или ниже по иерархии, например C_DOTA_BaseNPC и тд - они все являются валидными инстанциями C_NextBotCombatCharacter)
4) у локал плеера(или локал героя) есть DOTATeam_t C_BaseEntity::m_iTeamNum. если у кого-либо тима равна той что у локал игрока/героя = это союзник. нет = враг
5) у контроллера есть хендл героя C_DOTAPlayerController::m_hAssignedHero, а у героя C_BaseEntity::m_hOwnerEntity будет равен хендлу контроллера
6) локальный герой либо через CEngineClient/CNetworkGameClient, либо у контроллера есть CBasePlayerController::m_bIsLocalPlayerController
7) список контроллеров есть либо в C_DOTA_PlayerResource(плеер айдишники), либо в энтитисистеме сам отфильтруешь(как хочешь - по ртти по имени по метахуйне всякой), либо в метахуйне(то что ты назвал "энтитилистом" это список объектов C_NextBotCombatCharacter, существует также список объектов и C_DOTAPlayerController)
тебе прежде всего локальный контроллер(игрок) нужен
пошла возня, спасибо
пизжу немножко нету списка контроллеров такого же как списка C_NextBotCombatCharacter, это внутренний список который в конструкторе C_NextBotCombatCharacter пополняется(контроллер такой список не ведёт в конструкторе). ну сути это конечно не меняет - это все равно не энтитилист;
еще можно локал плеер контроллера в теории брать из CPrediction(Source2ClientPrediction001 @ 0x7ffeb603f700(client.dll+0x430f700) -> CPrediction) там на оффсете 0x50 лежит попробуй я не тестил
дамп обновил(19 апр 2024)
Пожалуйста, авторизуйтесь для просмотра ссылки.
 
Последнее редактирование:
Участник
Статус
Онлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
добавил ентити класс хуиту в дамп(см https://yougame.biz/threads/306193/)
Пожалуйста, авторизуйтесь для просмотра ссылки.
в теории(не тестил но должно работать) можно получать любую сущность(среди тех, классы которых есть в списке(1368 классов в списке)) спокойно по классу
вот например: получение плеер ресурса
Код:
class "C_DOTA_PlayerResource" desc 0x16266c208c0 cls 0x7ffd9ca8ec10(client.dll + 0x477ec10) info 0x7ffd9ca8ebc0(client.dll + 0x477ebc0) SchemaBinding 0x7ffd9c630460(client.dll + 0x4320460) LastIdentity @ 0x7ffd9ca8ed10(client.dll + 0x477ed10) = 0x16266532f80
в client.dll на указанном статичном адресе всегда лежит последняя айдентити указанного класса. можно спокойно без сиг брать плеерресурс
если объектов несколько(например, игроки) - можно взять последнюю айдентити, обработать ее и просто обратно потом идти в ней по CEntityIdentity::m_pNextByClass(0x70 оффсет), пока этот m_pNextByClass не будет равен нулю(это значит что дошли до самого первого объекта)
таким способом можно брать C_DOTA_PlayerResource, C_DOTAGamerules(через C_DOTAGamerulesProxy сущность и ее нетвар m_pGameRules), C_DOTA_DataRadiant/C_DOTA_DataDire, игроков(C_DOTAPlayerController) и прочую хуйню
минус в том что нет абстрактных сущностей(например нельзя получить "нпс" или "героев"), есть только конкретные(например C_DOTA_Unit_Hero_Weaver)
C++:
struct CEntityClassInfo
{
    const char* name_1{};
    const char* name_2{};
    const char* name_3{};
    CEntityClass* cls{};
    CEntityClassInfo* base_class{};
    CSchemaClassBinding* binding{};
};

struct CEntityClass : public NormalClass
{
    void* m_pPanoramaGameScriptScope{};
    void* unk_1{};
    void* unk_2{};
    void* unk_3{};
    void* unk_4{};
    CEntityClassInfo* class_info{};
    CEntityClassInfo* base_class_info{};

    constexpr static inline auto LAST_IDENTITY_OFFSET = 0x100;
    const auto& GetLastIdentity() const
    {
        return Member<CEntityIdentity*>(LAST_IDENTITY_OFFSET);
    }
    constexpr static inline auto DESC_OFFSET = 0x108;
    const auto& GetDesc() const
    {
        return Member<ClassDescription*>(DESC_OFFSET);
    }
};

class ClassDescription
{
public:
    const char* client_name{};
    const char* server_name{};
    CEntityClass* cls{};
    const char* scoped_name{};
    void* unk{};
    std::uint32_t id{};
};

//4C 8B 0D ?? ?? ?? ?? 4D 85 C9 74 ?? 33 C0
//or CNetworkClientService(NetworkClientService_001) virtual function 23
//or CNetworkClientService(NetworkClientService_001) at offset 0xA8
class CNetworkGameClient : public VClass
{
    class ServerClassNode
    {
        const char* class_server_name{};
        ClassDescription* desc{};
    };
    static inline constexpr auto m_pServerClasses_offset = 0x1A8;
public:
    const auto& GetServerClasses() const noexcept
    {
        return Member<CUtlVector<ServerClassNode>>(m_pServerClasses_offset);
    }
};

...

//GetServerClasses() find blah blah blah ClassDescription::client_name == "My Shit" blah blah blah return ClassDescription::desc->cls->GetLastIdentity()
 
Последнее редактирование:
🤡
Пользователь
Статус
Оффлайн
Регистрация
28 Апр 2014
Сообщения
127
Реакции[?]
163
Поинты[?]
21K
добавил ентити класс хуиту в дамп(см https://yougame.biz/threads/306193/)
Пожалуйста, авторизуйтесь для просмотра ссылки.
в теории(не тестил но должно работать) можно получать любую сущность(среди тех, классы которых есть в списке(1368 классов в списке)) спокойно по классу
вот например: получение плеер ресурса
Код:
class "C_DOTA_PlayerResource" desc 0x16266c208c0 cls 0x7ffd9ca8ec10(client.dll + 0x477ec10) info 0x7ffd9ca8ebc0(client.dll + 0x477ebc0) SchemaBinding 0x7ffd9c630460(client.dll + 0x4320460) LastIdentity @ 0x7ffd9ca8ed10(client.dll + 0x477ed10) = 0x16266532f80
в client.dll на указанном статичном адресе всегда лежит последняя айдентити указанного класса. можно спокойно без сиг брать плеерресурс
если объектов несколько(например, игроки) - можно взять последнюю айдентити, обработать ее и просто обратно потом идти в ней по CEntityIdentity::m_pNextByClass(0x70 оффсет), пока этот m_pNextByClass не будет равен нулю(это значит что дошли до самого первого объекта)
таким способом можно брать C_DOTA_PlayerResource, C_DOTAGamerules(через C_DOTAGamerulesProxy сущность и ее нетвар m_pGameRules), C_DOTA_DataRadiant/C_DOTA_DataDire, игроков(C_DOTAPlayerController) и прочую хуйню
минус в том что нет абстрактных сущностей(например нельзя получить "нпс" или "героев"), есть только конкретные(например C_DOTA_Unit_Hero_Weaver)
C++:
struct CEntityClassInfo
{
    const char* name_1{};
    const char* name_2{};
    const char* name_3{};
    ClassDescription* descr{};
    CEntityClassInfo* base_class{};
    CSchemaClassBinding* binding{};
};

struct CEntityClass : public NormalClass
{
    void* m_pPanoramaGameScriptScope{};
    void* unk_1{};
    void* unk_2{};
    void* unk_3{};
    void* unk_4{};
    CEntityClassInfo* class_info{};
    CEntityClassInfo* base_class_info{};

    constexpr static inline auto LAST_IDENTITY_OFFSET = 0x100;
    const auto& GetLastIdentity() const
    {
        return Member<CEntityIdentity*>(LAST_IDENTITY_OFFSET);
    }
    constexpr static inline auto DESC_OFFSET = 0x108;
    const auto& GetDesc() const
    {
        return Member<ClassDescription*>(DESC_OFFSET);
    }
};

class ClassDescription
{
public:
    const char* client_name{};
    const char* server_name{};
    CEntityClass* cls{};
    const char* scoped_name{};
    void* unk{};
    std::uint32_t id{};
};

//4C 8B 0D ?? ?? ?? ?? 4D 85 C9 74 ?? 33 C0
//or CNetworkClientService(NetworkClientService_001) virtual function 23
//or CNetworkClientService(NetworkClientService_001) at offset 0xA8
class CNetworkGameClient : public VClass
{
    class ServerClassNode
    {
        const char* class_server_name{};
        ClassDescription* desc{};
    };
    static inline constexpr auto m_pServerClasses_offset = 0x1A8;
public:
    const auto& GetServerClasses() const noexcept
    {
        return Member<CUtlVector<ServerClassNode>>(m_pServerClasses_offset);
    }
};

...

//GetServerClasses() find blah blah blah ClassDescription::client_name == "My Shit" blah blah blah return ClassDescription::desc->cls->GetLastIdentity()
Слегка дополню твои структурки. И да, RuntimeIndex можно использовать для идентификации типа ентити, если нужна абстракция (Герой это или Крип), ты можешь итерировать по BaseClass'у. CEntityClass довольно полезная вещь, там куда больше чего можно через него делать, но это уже другой разговор.

ServerClassNode ->

C++:
struct CNetworkInstanceHandle_t
{
    CUtlString m_pszClientName;
    CEntityClassNetworkInstance *m_pNetworkInstance;
};


ClassDescription ->
C++:
class CEntityClassNetworkInstance
{
public:
    const char                  *m_pszServerName;
    const char                  *m_pszClientName;
    CEntityClass                *m_pClass;
    const char                  *m_pszScopedName;
    FlattenedSerializerHandle_t *m_pSerializerHandle;
    RuntimeIndex_t m_iRuntimeIndex;
    int        m_ClassID;
    CUtlString m_ClassIDString;
};
CEntityClass -> (Фулл не буду кидать, задача остальных доделать, если хотят, но размер: static_assert(sizeof(CEntityClass) == 0x110))
C++:
panorama::CPanoramaGameScriptScope *m_pPanoramaGameScriptScope;       // 0x0000
EntInput_t                         *m_pInputs;                        // 0x0008
EntOutput_t                        *m_pOutputs;                       // 0x0010
int                                 m_nInputCount;                    // 0x0018
int                                 m_nOutputCount;                   // 0x001C
EntClassComponentOverride_t        *m_pComponentOverrides;            // 0x0020
CEntityClassInfo                   *m_pClassInfo;                     // 0x0028
CEntityClassInfo                   *m_pBaseClassInfo;                 // 0x0030

CEntityClassInfo ->
C++:
class CEntityClassInfo
{
public:
    CUtlString m_pszClassname;        // 0x0000
    CUtlString m_pszCPPClassname;     // 0x0008
    CUtlString m_pszDescription;      // 0x0010
    CEntityClass        *m_pClass;              // 0x0014
    CEntityClassInfo    *m_pBaseClassInfo;      // 0x0018
    CSchemaClassBinding *m_pSchemaClassBinding; // 0x0028
    datamap_t           *m_pDataDescMap;        // 0x0030
    datamap_t           *m_pPredDescMap;        // 0x0038
};                                              // Size: 0x0040
static_assert(sizeof(CEntityClassInfo) == 0x40);


Единственное, не уверен на счет твоего 0x100. Последний раз когда я реверсил и ребилдил это все, там лежала именно ПЕРВАЯ ентити выбранного CEntityClass, а не последняя.

C++:
CEntityIdentity                    *m_pFirstEntity;                   // 0x0100
 
Последнее редактирование:
Участник
Статус
Онлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
Слегка дополню твои структурки. И да, RuntimeIndex можно использовать для идентификации типа ентити, если нужна абстракция (Герой это или Крип), ты можешь итерировать по BaseClass'у. CEntityClass довольно полезная вещь, там куда больше чего можно через него делать, но это уже другой разговор.

ServerClassNode ->

C++:
struct CNetworkInstanceHandle_t
{
    CUtlString m_pszClientName;
    CEntityClassNetworkInstance *m_pNetworkInstance;
};


ClassDescription ->
C++:
class CEntityClassNetworkInstance
{
public:
    const char                  *m_pszServerName;
    const char                  *m_pszClientName;
    CEntityClass                *m_pClass;
    const char                  *m_pszScopedName;
    FlattenedSerializerHandle_t *m_pSerializerHandle;
    RuntimeIndex_t m_iRuntimeIndex;
    int        m_ClassID;
    CUtlString m_ClassIDString;
};
CEntityClass -> (Фулл не буду кидать, задача остальных доделать, если хотят, но размер: static_assert(sizeof(CEntityClass) == 0x110))
C++:
panorama::CPanoramaGameScriptScope *m_pPanoramaGameScriptScope;       // 0x0000
EntInput_t                         *m_pInputs;                        // 0x0008
EntOutput_t                        *m_pOutputs;                       // 0x0010
int                                 m_nInputCount;                    // 0x0018
int                                 m_nOutputCount;                   // 0x001C
EntClassComponentOverride_t        *m_pComponentOverrides;            // 0x0020
CEntityClassInfo                   *m_pClassInfo;                     // 0x0028
CEntityClassInfo                   *m_pBaseClassInfo;                 // 0x0030

CEntityClassInfo ->
C++:
class CEntityClassInfo
{
public:
    CUtlString m_pszClassname;        // 0x0000
    CUtlString m_pszCPPClassname;     // 0x0008
    CUtlString m_pszDescription;      // 0x0010
    CEntityClass        *m_pClass;              // 0x0014
    CEntityClassInfo    *m_pBaseClassInfo;      // 0x0018
    CSchemaClassBinding *m_pSchemaClassBinding; // 0x0028
    datamap_t           *m_pDataDescMap;        // 0x0030
    datamap_t           *m_pPredDescMap;        // 0x0038
};                                              // Size: 0x0040
static_assert(sizeof(CEntityClassInfo) == 0x40);


Единственное, не уверен на счет твоего 0x100. Последний раз когда я реверсил и ребилдил это все, там лежала именно ПЕРВАЯ ентити выбранного CEntityClass, а не последняя.

C++:
CEntityIdentity                    *m_pFirstEntity;                   // 0x0100
ну я проверял(только что на последней версии доты), там эта хуйня на 0x100 обновлялась при добавлении новой сущности. если она обновляется при добавлении новой, значит она первой быть не может соответственно(иначе бы стабильно оставалась одной и той же). не ну с точки зрения наименований - она действительно первая(потому что дальше от нее идет итерация по m_pNextByClass), но по факту она последняя(т.е. самая новая). получается это реверс линкед лист(от конца(самой новой) к началу(самой первой)), а это его голова(следовательно первая), но это контринтуитивно выглядит. поэтому я написал что она последняя(хотя тогда m_pNextByClass выглядит контринтуитивно). кароче по факту она последняя(самая новая) но она является головой реверс линкед листа(поэтому называется первой). в общем у габена наркоманские наименования какието которые не сообщают сами по себе что это реверс линкед лист.
в CNetworkInstanceHandle_t там серверное имя (CBaseEntity например вместо C_BaseEntity),
1713625719112.png
а в CEntityClassNetworkInstance там сначала клиентское имя а потом серверное имя(видимо поменяли после какого-то апдейта потому что у меня в структуре тоже раньше наоборот было)
1713625783230.png
 
Начинающий
Статус
Оффлайн
Регистрация
19 Апр 2024
Сообщения
9
Реакции[?]
1
Поинты[?]
1K
Liberalist, большое спасибо за проделанный труд! Подскажи пожалуйста как в данный момемент происходит дамп, - много ли ручной работы?
Просто думаю может быть сделать CI\CD - которая автоматически бы создавала ассеты в gitlab\github?
 
Участник
Статус
Онлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
Liberalist, большое спасибо за проделанный труд! Подскажи пожалуйста как в данный момемент происходит дамп, - много ли ручной работы?
Просто думаю может быть сделать CI\CD - которая автоматически бы создавала ассеты в gitlab\github?
просто длл инжектишь в мейн меню(ну т.е. после прогрузки) в доту.
посмотри на
Пожалуйста, авторизуйтесь для просмотра ссылки.
Пожалуйста, авторизуйтесь для просмотра ссылки.
я щас над оффлайн(из файла на диске) дампером шемы работаю(POC качества), позже отпишусь по этому поводу
 
Начинающий
Статус
Оффлайн
Регистрация
4 Апр 2024
Сообщения
28
Реакции[?]
1
Поинты[?]
1K
Всем привет,хочу задать пару вопросов:
1) Мне не совсем понятно отношение в схемах Liberalist 'a, например класса C_BaseEntity к CBasePlayerController т.е. именно в схеме это что? Наследование?
2) Нетвары тут и тут отличаются. В чем разница и почему тут идет перечисление как если бы они были членами объекта, а тут будто они описывают сам член?
3) Сами нетвары. Я правильно понимаю, что это некие глобальные переменные, в которые и из которых отображаются данные в\из члены объекта?
4) Еще вопрос, из следующий темы правда, есть у кого сигнатура OnTeamVisibilityChanged или способ поиска? Хрефа такого более нету.

За картинку прошу прощения,кажется эта учетка не позволяет добавлять картинки прямо на фору.
Пожалуйста, авторизуйтесь для просмотра ссылки.
 
Последнее редактирование:
🤡
Пользователь
Статус
Оффлайн
Регистрация
28 Апр 2014
Сообщения
127
Реакции[?]
163
Поинты[?]
21K
4) Еще вопрос, из следующий темы правда, есть у кого сигнатура OnTeamVisibilityChanged или способ поиска? Хрефа такого более нету.
OnTeamVisibilityChanged было раньше функцией в клиенте для проверки. Так сказать, flattened serializer, нынче этой функции нет, ты можешь просто читать нужный тебе нетвар для всех.
 
Участник
Статус
Онлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
Всем привет,хочу задать пару вопросов:
1) Мне не совсем понятно отношение в схемах Liberalist 'a, например класса C_BaseEntity к CBasePlayerController т.е. именно в схеме это что? Наследование?
2) Нетвары тут и тут отличаются. В чем разница и почему тут идет перечисление как если бы они были членами объекта, а тут будто они описывают сам член?
3) Сами нетвары. Я правильно понимаю, что это некие глобальные переменные, в которые и из которых отображаются данные в\из члены объекта?
4) Еще вопрос, из следующий темы правда, есть у кого сигнатура OnTeamVisibilityChanged или способ поиска? Хрефа такого более нету.

За картинку прошу прощения,кажется эта учетка не позволяет добавлять картинки прямо на фору.
Пожалуйста, авторизуйтесь для просмотра ссылки.
1) да наследование. C_BaseEntity это абстрактный класс от которого все сущности наследуют напрямую или через родителей/пра-родителей
иерархия у C_DOTAPlayerController например вот такая
Код:
class C_DOTAPlayerController extends CBasePlayerController
...
class CBasePlayerController extends C_BaseEntity
...
class C_BaseEntity extends CEntityInstance
...
class CEntityInstance extends IHandleEntity
...
class IHandleEntity
я для удобства дублирую всю иерархию(чтобы видеть все члены сразу) в файл(базовые классы там написано base class). сами члены данного класса находятся в самом низу
можешь сравнить/сопоставить с другими дампами, мб это что-то прояснит
(
например
Пожалуйста, авторизуйтесь для просмотра ссылки.
Пожалуйста, авторизуйтесь для просмотра ссылки.
)
т.к. наследство у сущностей в доте простое в 99.9% случаев(без выебонов с множественным наследованием) то любая инстанция ребенка является валидной инстанцией родителя(и пра-родителя). любой указатель на C_DOTAPlayerController также является указателем на C_BaseEntity(не надо ничего смещать т.к. простое наследование)(кароче грубо говоря все что есть у C_BaseEntity(хп, тима и тд) есть и у C_DOTAPlayerController ровно на тех же местах)
2) это метадата(хуйня которая описывает какието (обычно незначительные/неинтересные) детали. кароче просто дополнительное описание грубо говоря). красные это на самом классе(доп описание к самому классу), синие это на членах(доп описание к конкретному члену). это не нетвары.
3) это не глобальные переменные. во-первых это члены структуры(т.е. они существуют у каждой структуры - например возьми то же хп. хп оно у всех есть. это не одна какаято глобальная переменная. хп есть у тебя, у врагов, у крипов, у курьеров - и у всех оно разное и независимое. очевидно если бы оно было глобальным оно бы было у всех одинаково), во-вторых это члены структуры которые могут быть связаны с нетворкингом(т.е. передаваться по сети - например хп сущности ты получаешь с сервера, ты его не сам выдумываешь)(netvar = network variable)(некоторые члены не являются нетварами(не связаны никак с сетью и чисто локальные) и их нету в этом дампе)
4) почитай https://yougame.biz/threads/306236/
если вкратце то m_iTaggedAsVisibleByTeam есть нетвар, он хранит нужную инфу, но он затирается каждый тик(при ивенте движка CLoopGameMode::OnClientSimulate вроде). его значение приходит тебе с сервера но потом стирается. либо это стирание патчишь(сомнительная идея) либо до стирания значение нетвара сохраняешь либо более креативные выходы из ситуации ищешь. хвбп(Hardware Breakpoint) в помощь(в чит енджине этот функционал называется Find out what writes to this address). смотришь кто записывает(сначала это будет networksystem.dll(пишет реальное значение), потом client.dll(стирает в 4 вроде. ну кароче выбрасывает значение))
 
Начинающий
Статус
Оффлайн
Регистрация
4 Апр 2024
Сообщения
28
Реакции[?]
1
Поинты[?]
1K
По какой-то причине не могу завершить вызов FindDeclaredClass. Он в своем теле вызывает метод FindType_DeclaredClass, который возвращает 0 и перед выходом из FindDeclaredClass все падает на попытке переписать строку по адресу в регистре rax - получаю EXCEPTION_ACCESS_VIOLATION.
Я как-то неправильно вызываю метод? Погуглил, вроде должно работать как и прежде.

Пожалуйста, авторизуйтесь для просмотра ссылки.
 
Участник
Статус
Онлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
По какой-то причине не могу завершить вызов FindDeclaredClass. Он в своем теле вызывает метод FindType_DeclaredClass, который возвращает 0 и перед выходом из FindDeclaredClass все падает на попытке переписать строку по адресу в регистре rax - получаю EXCEPTION_ACCESS_VIOLATION.
Я как-то неправильно вызываю метод? Погуглил, вроде должно работать как и прежде.

Пожалуйста, авторизуйтесь для просмотра ссылки.
там изменились параметры
если ты посмотришь на свой скрин там у тебя краш на строке mov qword ptr ds:[rbx], 0; а сам rbx в начале функи ставится в rdx(mov rbx, rdx) (сама причина краша в том что у тебя в rdx указатель на строку(она в .rdata(она ридонли) лежит(ну скорее всего. не видел остальных частей кода но 99% что это так)) в итоге дота пишет в твой ридонли сегмент и получает пизды)
т.е. функция высирает свой результат во второй параметр
кароче
C++:
using T_FindDeclaredClass = void*(*)(void* thisptr_typescope, void** out_result, const char* class_name);
...
void* out_class_C_DOTAPlayerController = nullptr;
FindDeclaredClass
(
    scope_client_dll,
    &out_class_C_DOTAPlayerController,
    "C_DOTAPlayerController"
);
if (out_class_C_DOTAPlayerController)
{
    ...
}
Пожалуйста, авторизуйтесь для просмотра ссылки.
мне лично кажется они либо ебанулись, либо(более вероятный вариант) сделали структуру в стиле
C++:
struct CSchemaClassInfoPtr
{
    CSchemaClassInfo* ptr;
};
и начали возвращать ее по значению, потому что именно так по конвенции из связанных методов передаются структуры по значению(rcx - thisptr, rdx - указатель на аллоцированное вызывателем место под структуру; rax после вызова(ну т.е. возврат) в итоге будет равен изначальному rdx который передавали)
т.е. функция просто стала CSchemaClassInfoPtr FindDeclaredClass(const char*) а не CSchemaClassInfo* FindDeclaredClass(const char*)
 
Последнее редактирование:
Участник
Статус
Онлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
дапм шемы от 30 Nov 2015 21:30:17 (версия на 2 месяца старше чем последняя версия в которой дилибы с символами были 25 January 2016 23:12:54 (ее тоже потом планирую сдампить руки недошли)) если кому-то надо(там может быть всякое говно которое спрятали из шемы, тот же CEntityClass и т.д.)
Пожалуйста, авторизуйтесь для просмотра ссылки.
 
🤡
Пользователь
Статус
Оффлайн
Регистрация
28 Апр 2014
Сообщения
127
Реакции[?]
163
Поинты[?]
21K
там изменились параметры
если ты посмотришь на свой скрин там у тебя краш на строке mov qword ptr ds:[rbx], 0; а сам rbx в начале функи ставится в rdx(mov rbx, rdx) (сама причина краша в том что у тебя в rdx указатель на строку(она в .rdata(она ридонли) лежит(ну скорее всего. не видел остальных частей кода но 99% что это так)) в итоге дота пишет в твой ридонли сегмент и получает пизды)
т.е. функция высирает свой результат во второй параметр
кароче
C++:
using T_FindDeclaredClass = void*(*)(void* thisptr_typescope, void** out_result, const char* class_name);
...
void* out_class_C_DOTAPlayerController = nullptr;
FindDeclaredClass
(
    scope_client_dll,
    &out_class_C_DOTAPlayerController,
    "C_DOTAPlayerController"
);
if (out_class_C_DOTAPlayerController)
{
    ...
}
Пожалуйста, авторизуйтесь для просмотра ссылки.
мне лично кажется они либо ебанулись, либо(более вероятный вариант) сделали структуру в стиле
C++:
struct CSchemaClassInfoPtr
{
    CSchemaClassInfo* ptr;
};
и начали возвращать ее по значению, потому что именно так по конвенции из связанных методов передаются структуры по значению(rcx - thisptr, rdx - указатель на аллоцированное вызывателем место под структуру; rax после вызова(ну т.е. возврат) в итоге будет равен изначальному rdx который передавали)
т.е. функция просто стала CSchemaClassInfoPtr FindDeclaredClass(const char*) а не CSchemaClassInfo* FindDeclaredClass(const char*)
И тут ты прав, так сказать, даю жопу что у них такой враппер, т.к. у них есть подобное еще в панораме и думаю они просто взяли сейм класс и ренеймнули (На самом деле, подобного у них много где есть).

C++:
template <class T>
struct SchemaHandle_t
{
    SchemaHandle_t() : m_pObj( NULL ) {}
    SchemaHandle_t( T *obj ) : m_pObj( obj ) {}
    T* Get() { return m_pObj; }

    T* m_pObj;
};
То есть функция скорее всего чот типо такого. SchemaHandle_t<CSchemaClassInfo> FindDeclaredClass
 
Последнее редактирование:
Участник
Статус
Онлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
добавил дамп шемы и ртти с июня 2015 до мая 2024(в ~3хмесячных инкрементах), можно там смотреть всякое говно которое удалили/спрятали из доты/шемы(мало ли)
Пожалуйста, авторизуйтесь для просмотра ссылки.
сам дампер позже выложу(там онли ртти и шема; оффлайн(с дллок на диске, с использованием LoadLibrary(без него тоже можно(частичный ммап без импортов и дллмейнов) но нестабильно(слишком много говна надо эмулировать) и неразумно))) сюда же
 
Последнее редактирование:
Участник
Статус
Онлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
дерьмодампер шемы и ртти оффлайн POC качества(на доту работает на ксго вроде тоже)
shitcode:
Пожалуйста, авторизуйтесь для просмотра ссылки.
если вкратце то регистрация в шеме происходит через CSchemaRegistration_blablabla классы в модулях, эти классы имеют у себя виртуальную функцию RegisterAllBindings. эта функция состоит из двух фаз - предварительной и финальной;
биндинги на диске хранят всё кроме типов - типы заполняются из RegisterAllBindings(изза этого нельзя просто с диска(ну т.е. из самого .dll файла без его прогрузки) брать биндинги и дампить их - ну точнее можно(ток их сначала еще идентифицировать тогда придется) но тогда не будет инфы о типах нетваров никакой - только имена оффсеты мета и прочая хуита)
следовательно надо грузить .dll'ки и вызывать у них эти RegisterAllBindings - здесь можно либо частично ммапить без импортов без нихуя(хотя это не на всех версиях доты работает - на некоторых импорты вызываются(следовательно их тоже либо эмулировать либо грузить)) и эмулировать шема систему(ну это хуйня идея слишком много работы и слишком нестабильно между версиями), либо просто нормально полноценно грузить официальную schemasystem.dll и остальные модули тоже нормально грузить, и потом уже доставать либо из шема системы всю инфу(нестабильно между версиями) либо просто абузить тот факт что всё пролетает через стабильные CSchemaSystemTypeScope::InstallSchemaClassBinding(0 index) и CSchemaSystemTypeScope::InstallSchemaEnumBinding(1 index). собственно весь дампер держится на этих двух хуках(вмт по ртти находится)
существует две "мажорные" версии шемы - 2015-2019 и 2019+ (между ними еще есть 2018-2019 кусочек который похож на 2019+ но чуть чуть отличается я его скипнул там ~6 месяцев всего лишь он жил или меньше даже). разница между этими версиями это сами структуры биндингов и того что они содержат(члены, мета, типы и тд) и порядок параметров в InstallSchemaClassBinding/InstallSchemaEnumBinding.
дллки грузятся, хукаются InstallSchemaClassBinding/InstallSchemaEnumBinding в шеме, вызывается экспорт у каждого из модулей InstallSchemaBindings(это грубо говоря просто g_pInterfaceGlobals._g_pSchemaSystem = addr_of_CSchemaSystem и foreach(CSchemaRegistration_blablabla) RegisterAllBindings). все что пролетает через хуки трансформируется в стабильный вид и сохраняется в список, потом после того как всё зарегалось по списку идут фиксы(например инфа(размер и выравнивание) о некоторых типах недоступна изначально(при первичной регистрации) и такие инвалидные типы фиксятся после того как всё зарегалось, за исключением ~11 типов которых в шеме просто нет(~4/5 штук) или нет в конкретно данных версиях но есть в следующих/предыдущих - они остаются как есть с 0 размером и выравниванием, родители фиксятся(родители должны быть в локальном масштабе, а шема может на указывать дубликаты из другого масштаба в качестве родителей(ну это токо для дампа фулл иерархии))) потом запись всей этой хуйни на диск. единственная "нестабильность" это вызов GetSizeAndAlign у которого индекс нестабильный но он не захардкожен а ищется сканом так что все работает вроде нормально на доту(42 версии проверил 2015-2024) и кс2(8 версий 2023-2024)
если кому-то нужны one-liner'ы компиляции то:
MSVC: x64 Native Tools Command Prompt for VS 2022(в пуске есть)
cl /std:c++latest /O2 /EHsc schema_dumper.cpp
Clang-cl:
clang-cl /std:c++latest /O2 /EHsc schema_dumper.cpp
 
Последнее редактирование:
Начинающий
Статус
Оффлайн
Регистрация
19 Апр 2024
Сообщения
9
Реакции[?]
1
Поинты[?]
1K
POC качества(на доту работа
дерьмодампер шемы и ртти оффлайн POC качества(на доту работает на ксго вроде тоже)
shitcode:
Пожалуйста, авторизуйтесь для просмотра ссылки.
если вкратце то регистрация в шеме происходит через CSchemaRegistration_blablabla классы в модулях, эти классы имеют у себя виртуальную функцию RegisterAllBindings. эта функция состоит из двух фаз - предварительной и финальной;
биндинги на диске хранят всё кроме типов - типы заполняются из RegisterAllBindings(изза этого нельзя просто с диска(ну т.е. из самого .dll файла без его прогрузки) брать биндинги и дампить их - ну точнее можно(ток их сначала еще идентифицировать тогда придется) но тогда не будет инфы о типах нетваров никакой - только имена оффсеты мета и прочая хуита)
следовательно надо грузить .dll'ки и вызывать у них эти RegisterAllBindings - здесь можно либо частично ммапить без импортов без нихуя(хотя это не на всех версиях доты работает - на некоторых импорты вызываются(следовательно их тоже либо эмулировать либо грузить)) и эмулировать шема систему(ну это хуйня идея слишком много работы и слишком нестабильно между версиями), либо просто нормально полноценно грузить официальную schemasystem.dll и остальные модули тоже нормально грузить, и потом уже доставать либо из шема системы всю инфу(нестабильно между версиями) либо просто абузить тот факт что всё пролетает через стабильные CSchemaSystemTypeScope::InstallSchemaClassBinding(0 index) и CSchemaSystemTypeScope::InstallSchemaEnumBinding(1 index). собственно весь дампер держится на этих двух хуках(вмт по ртти находится)
существует две "мажорные" версии шемы - 2015-2019 и 2019+ (между ними еще есть 2018-2019 кусочек который похож на 2019+ но чуть чуть отличается я его скипнул там ~6 месяцев всего лишь он жил или меньше даже). разница между этими версиями это сами структуры биндингов и того что они содержат(члены, мета, типы и тд) и порядок параметров в InstallSchemaClassBinding/InstallSchemaEnumBinding.
дллки грузятся, хукаются InstallSchemaClassBinding/InstallSchemaEnumBinding в шеме, вызывается экспорт у каждого из модулей InstallSchemaBindings(это грубо говоря просто g_pInterfaceGlobals._g_pSchemaSystem = addr_of_CSchemaSystem и foreach(CSchemaRegistration_blablabla) RegisterAllBindings). все что пролетает через хуки трансформируется в стабильный вид и сохраняется в список, потом после того как всё зарегалось по списку идут фиксы(например инфа(размер и выравнивание) о некоторых типах недоступна изначально(при первичной регистрации) и такие инвалидные типы фиксятся после того как всё зарегалось, за исключением ~11 типов которых в шеме просто нет(~4/5 штук) или нет в конкретно данных версиях но есть в следующих/предыдущих - они остаются как есть с 0 размером и выравниванием, родители фиксятся(родители должны быть в локальном масштабе, а шема может на указывать дубликаты из другого масштаба в качестве родителей(ну это токо для дампа фулл иерархии))) потом запись всей этой хуйни на диск. единственная "нестабильность" это вызов GetSizeAndAlign у которого индекс нестабильный но он не захардкожен а ищется сканом так что все работает вроде нормально на доту(42 версии проверил 2015-2024) и кс2(8 версий 2023-2024)
Это очень круто, спасибо что делишься опытом! Может есть смысл сделать CI\CD для автодампа ассетов в gitlab\github?
Можно сделать автозапуск по выходу обновления и тригерить пайплайн
 
Участник
Статус
Онлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
Это очень круто, спасибо что делишься опытом! Может есть смысл сделать CI\CD для автодампа ассетов в gitlab\github?
Можно сделать автозапуск по выходу обновления и тригерить пайплайн
ты можешь все что хочешь с этим делать; если не лень и хочешь - делай
 
Начинающий
Статус
Оффлайн
Регистрация
14 Янв 2024
Сообщения
31
Реакции[?]
1
Поинты[?]
2K
Для тех кто новичок как и я, чтобы собрать и запустить дампер шемы (консольное приложение):

1) обновить visual studio до последней версии (17.9.6) и в свойствах проекта поставить "C++ (/std:c++latest) ", так как у меня не было 23 стандарта;
2) будет ошибка " E0028 выражение должно иметь константное значение 1096: static constexpr auto mappings = std::to_array({..." игнорируем;
3) в функции main в строчке в std::filesystem::path default_game_dir = R"(depots\...)"; (depots\...) заменяем на вашу директорию игры,
у меня: std::filesystem::path default_game_dir = R"(D:\SteamLibrary\steamapps\common\dota 2 beta)";
4) запускаем екзешник, в директории запуска создастся папка dumps с файлами, операция на зеоне 2689 занимает около 2х минут

Liberalist, спасибо за помощь и развитие сообщества
 
Последнее редактирование:
Участник
Статус
Онлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
Для тех кто новичок как и я, чтобы собрать и запустить дампер шемы (консольное приложение):

1) обновить visual studio до последней версии (17.9.6) и в свойствах проекта поставить "C++ (/std:c++latest) ", так как у меня не было 23 стандарта;
2) будет ошибка " E0028 выражение должно иметь константное значение 1096: static constexpr auto mappings = std::to_array({..." игнорируем;
3) в функции main в строчке в std::filesystem::path default_game_dir = R"(depots\...)"; (depots\...) заменяем на вашу директорию игры,
у меня: std::filesystem::path default_game_dir = R"(D:\SteamLibrary\steamapps\common\dota 2 beta)";
4) запускаем екзешник, в директории запуска создастся папка dumps с файлами, операция на зеоне 2689 занимает около 2х минут

Liberalist, спасибо за помощь и развитие сообщества
1) 23 стандарта нигде нету он еще не вышел(ну точнее не имплементирован) до конца, в мсвс он c++latest называется, в кленге/гсс c++2b
и не обязательно такую высокую версию визуалки ставить впринципе, и на 17.4.4 все работает
3) это дефолтные пути(для того чтобы из визуалки прямо там сразу без выебонов запускать(ну там можно параметры командной строки указать в настройках проекта конечно)), там можно в консоли просто передавать в качестве аргументов путь-к-доте, путь-куда-дампить, игру(dota/csgo/и т.д.)(под "игрой" подразумевается имя папки где лежат client.dll server.dll и тд - это имя разное в разных играх, в доте dota, в кс2 csgo, ...)
4) чето многовато, у тебя хдд наверно? там основная нагрузка скорее не на проц а на диск(18,020 Files, 115 Folders - 214,316,062 bytes)
и я надеюсь ты в релизе собираешь?) 6 сек у меня занимает(если в 1 файл все 200мб высирать(для теста просто)), 10 сек если в разные файлы всё высирать
 
Начинающий
Статус
Оффлайн
Регистрация
14 Янв 2024
Сообщения
31
Реакции[?]
1
Поинты[?]
2K
не обязательно такую высокую версию
из-за требований в начале кода: "// c++23 - tested on clang 18.1.5 / msvc 19.40.33808"

чето многовато, у тебя хдд наверно?
нет, м2, но на нём много скульных баз в рантайме

я надеюсь ты в релизе собираешь?)
нет, дебаг, так как при попытке собрать релиз 560 ошибок;

вот результат: 6 + 127 + 10 + 41 = 184 / 60 = 3 минуты

schema_registration: 5690ms
printing & saving schema dump: 127322ms
rtti_saving: 9678ms
saving info...
info_saving: 40806ms
 
Сверху Снизу