Вопрос Dota 2 netvar manager

Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
thanks a lot for that i was doing something wrong made me think that this was wrong
thanks a lot mate for all the help ur providing but i still cant find the hero entity itself even in the dissect structure
wdym?
did you not look at the code?
C++:
(*(CHandle*)((uintptr_t)Entity/*player controller*/ + offset_m_hAssignedHero)).index()
is the index of the hero in the entity system. just get the entity by that index(the same way you got players by index)
did you not see the log?
DebugString: "player unnamed(0x13dac701c00) controls hero indexed 157"
DebugString: "player Kat(0x13d4dab1c00) controls hero indexed 209"
DebugString: "player Kjetil(0x13cc7e42a00) controls hero indexed 256"
DebugString: "player Борис(0x13cca980000) controls hero indexed 304"
DebugString: "player Julia(0x13c78d80000) controls hero indexed 351"
DebugString: "player Jéssica(0x13d34276200) controls hero indexed 399"
DebugString: "player Anne(0x13d38564600) controls hero indexed 447"
DebugString: "player Bjørn(0x13d34274600) controls hero indexed 495"
DebugString: "player กิตติ(0x13d38b50000) controls hero indexed 542"
DebugString: "player Zhang(0x13d2e8a5400) controls hero indexed 590"
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
Начинающий
Статус
Оффлайн
Регистрация
11 Фев 2023
Сообщения
39
Реакции[?]
0
Поинты[?]
0
dude iam kinda sure that u know that i still dont have the context of the
GetEntityByIndex right ?

but lemme guess is it void* HeroObject = (void*)((uintptr_t)List + ((CHandle)((uintptr_t)Entity + offset_m_hAssignedHero)).index() % 512); ?
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
dude iam kinda sure that u know that i still dont have the context of the
GetEntityByIndex right ?

but lemme guess is it void* HeroObject = (void*)((uintptr_t)List + ((CHandle)((uintptr_t)Entity + offset_m_hAssignedHero)).index() % 512); ?
somewhat close but not really.
what exactly do you not understand about the layout of the entity system and its 64 entitylists(512 identities each)?
you have pointers to lists starting at (entitysystem + 0x10) - i.e. + 0x10, +0x18, +0x20, +0x28, ..., +0x208
you use modular arithmetic to break the entity index down into a list index(div 512) and an entry index(mod 512).
just like how you would break 56 hours into 2 days and 8 hours(56 div 24 = 2, 56 mod 24 = 8)
you select the list ptr and read it: list = *(void**)((uintptr_t)entitysystem + 0x10 + 8 * list_index)
you then, in that list(dont forget to check it for nullptr), select an entry: identity = (void*)((uintptr_t)list + entry_index * 0x78)
you got the identity. you then get its m_pEntity: entity = *(void**)(identity)
C++:
const auto _GetEntityByIndex = [entitysystem](std::size_t index) -> void*
{
    const auto entitysystem_lists = (const void**)((const std::uint8_t*)entitysystem + 0x10);
    const auto list =
        entitysystem_lists[index / ENTITY_SYSTEM_LIST_SIZE];
    if(list)
    {
        const auto entry_index = index % ENTITY_SYSTEM_LIST_SIZE;
        constexpr auto sizeof_CEntityIdentity = 0x78;
        const auto identity = (const std::uint8_t*)list + entry_index * sizeof_CEntityIdentity;
        return *(void**)identity;
    }
    return nullptr;
};
 
Последнее редактирование:
Начинающий
Статус
Оффлайн
Регистрация
11 Фев 2023
Сообщения
39
Реакции[?]
0
Поинты[?]
0
somewhat close but not really.
what exactly do you not understand about the layout of the entity system and its 64 entitylists(512 identities each)?
you have pointers to lists starting at (entitysystem + 0x10) - ie + 0x10, +0x18, +0x20, +0x28, ..., +0x208
you use modular arithmetic to break the entity index down into a list index(div 512) and an entry index(mod 512).
just like how you would break 56 hours into 2 days and 8 hours(56 div 24 = 2, 56 mod 24 = 8)
you select the list ptr and read it: list = *(void**)((uintptr_t)entitysystem + 0x10 + 8 * list_index)
you then, in that list(dont forget to check it for nullptr), select an entry: identity = (void*)((uintptr_t)list + entry_index * 0x78)
you got the identity. you then get its m_pEntity: entity = *(void**)(identity)
C++:
const auto _GetEntityByIndex = [entitysystem](std::size_t index) -> void*
{
    const auto entitysystem_lists = (const void**)((const std::uint8_t*)entitysystem + 0x10);
    const auto list =
        entitysystem_lists[index / ENTITY_SYSTEM_LIST_SIZE];
    if(list)
    {
        const auto entry_index = index % ENTITY_SYSTEM_LIST_SIZE;
        constexpr auto sizeof_CEntityIdentity = 0x78;
        const auto identity = (const std::uint8_t*)list + entry_index * sizeof_CEntityIdentity;
        if (identity)
        {
            return *(void**)identity;
        }
    }
    return nullptr;
};

oh my god, thanks a lot dude for ur help i really appreciate ur help <3

i just want to know how do u know all of that ?
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
oh my god, thanks a lot dude for ur help i really appreciate ur help <3

i just want to know how do u know all of that ?
reverse engineering, duh
this is a reconstruction of what the game does, I didn't invent it
1723394990693.png
C++:
if(param > 32766) return nullptr;
list_index = param / 512;// technically param >> 9 but that's the same thing(512 is 2 in power of 9)
if(list_index > 63) return nullptr;
list = *(entity_system + 0x10 + list_index * 8);
if(!list) return nullptr;
entry_index = param % 512;//technically param & 511 but that's the same thing(512 is a power of two)
entry_index *= 0x78;//this isn't the index anymore, it's index * 0x78
list += entry_index;//this isn't the list anymore, it's list + entry_index * 0x78
if(!list) return nullptr;//this check isn't really necessary
if((*(list + m_hEntityHandle) & 32767) != param) return nullptr;//check that identity's index matches requested index(I don't see why it wouldn't so I don't have this check)
return *(list + m_pEntity);//m_pEntity is 0 so this is essentially return *list;
 
Начинающий
Статус
Оффлайн
Регистрация
11 Фев 2023
Сообщения
39
Реакции[?]
0
Поинты[?]
0
hey again how can i find the creeps , towers , roshan entities ?

iam using this method to get my hero entity


C++:
const auto _GetEntityByIndex = [CGameEntitySystem](std::size_t index) -> void*
                {
                    constexpr auto ENTITY_SYSTEM_LIST_SIZE = 512;
                    const auto entitysystem_lists = (const void**)((const std::uint8_t*)CGameEntitySystem + 0x10);
                    const auto list = entitysystem_lists[index / ENTITY_SYSTEM_LIST_SIZE];
                    if (list)
                    {
                        const auto entry_index = index % ENTITY_SYSTEM_LIST_SIZE;
                        constexpr auto sizeof_CEntityIdentity = 0x78;
                        const auto identity = (const std::uint8_t*)list + entry_index * sizeof_CEntityIdentity;
                        if (identity)
                        {
                            return *(void**)identity;
                        }
                    }
                    return nullptr;
                };
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
hey again how can i find the creeps , towers , roshan entities ?

iam using this method to get my hero entity


C++:
const auto _GetEntityByIndex = [CGameEntitySystem](std::size_t index) -> void*
                {
                    constexpr auto ENTITY_SYSTEM_LIST_SIZE = 512;
                    const auto entitysystem_lists = (const void**)((const std::uint8_t*)CGameEntitySystem + 0x10);
                    const auto list = entitysystem_lists[index / ENTITY_SYSTEM_LIST_SIZE];
                    if (list)
                    {
                        const auto entry_index = index % ENTITY_SYSTEM_LIST_SIZE;
                        constexpr auto sizeof_CEntityIdentity = 0x78;
                        const auto identity = (const std::uint8_t*)list + entry_index * sizeof_CEntityIdentity;
                        if (identity)
                        {
                            return *(void**)identity;
                        }
                    }
                    return nullptr;
                };
C_DOTA_BaseNPC_Creep_Neutral
C_DOTA_BaseNPC_Creep_Lane
C_DOTA_BaseNPC_Tower
 
Начинающий
Статус
Оффлайн
Регистрация
11 Фев 2023
Сообщения
39
Реакции[?]
0
Поинты[?]
0
Последнее редактирование:
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
dude i meant why iam just getting the hero entities not all entities like creeps , jungle creeps , towers etc ....
C++:
for int i ∈ [0; EntitySystem->GetHighestIndex()]:
    EntitySystem->GetEntityByIndex(i);
    ...
GetHighestIndex:
Код:
GetHighestIndex:
$ ==>            | 8B81 20150000              | mov eax,dword ptr ds:[rcx+1520]
$+6              | 8902                       | mov dword ptr ds:[rdx],eax
$+8              | 48:8BC2                    | mov rax,rdx
$+B              | C3                         | ret

    xref(cl_showents cmd):
    $ ==>            | 40:53                      | push rbx
    $+2              | 48:81EC 30020000           | sub rsp,230
    $+9              | 48:8B0D 60069103           | mov rcx,qword ptr ds:[7FFBF64EABC0]
    $+10             | 48:8D9424 50020000         | lea rdx,qword ptr ss:[rsp+250]
    $+18             | 33DB                       | xor ebx,ebx
    $+1A             | E8 B135EBFF                | call client.7FFBF2A8DB20                                               | <--- GetHighestIndex
    $+1F             | 8B08                       | mov ecx,dword ptr ds:[rax]
    $+21             | FFC1                       | inc ecx
    $+23             | 85C9                       | test ecx,ecx
    $+25             | 0F8E FC000000              | jle client.7FFBF2BDA677
    $+2B             | 48:89BC24 40020000         | mov qword ptr ss:[rsp+240],rdi
    $+33             | 0F1F40 00                  | nop dword ptr ds:[rax],eax
    $+37             | 66:0F1F8400 00000000       | nop word ptr ds:[rax+rax],ax
    $+40             | 48:8B0D 29069103           | mov rcx,qword ptr ds:[7FFBF64EABC0]
    $+47             | 8BD3                       | mov edx,ebx
    $+49             | E8 F241ECFF                | call client.7FFBF2A9E790
    $+4E             | 48:8BF8                    | mov rdi,rax
    $+51             | 48:85C0                    | test rax,rax
    $+54             | 74 76                      | je client.7FFBF2BDA61C
    $+56             | C64424 30 00               | mov byte ptr ss:[rsp+30],0
    $+5B             | 48:8BC8                    | mov rcx,rax
    $+5E             | 48:8B10                    | mov rdx,qword ptr ds:[rax]
    $+61             | FF92 40010000              | call qword ptr ds:[rdx+140]
    $+67             | 4C:8D05 122D9701           | lea r8,qword ptr ds:[7FFBF454D2D0]                                     | 00007FFBF454D2D0:"'%s'"
    $+6E             | BA 00010000                | mov edx,100
    $+73             | 48:8D8C24 30010000         | lea rcx,qword ptr ss:[rsp+130]
    $+7B             | 4C:8B48 08                 | mov r9,qword ptr ds:[rax+8]
    $+7F             | FF15 534E8E01              | call qword ptr ds:[<&V_snprintf>]
    $+85             | 48:8B47 10                 | mov rax,qword ptr ds:[rdi+10]
    $+89             | 48:8D15 1ACD9101           | lea rdx,qword ptr ds:[7FFBF44F72FA]
    $+90             | 4C:8D8C24 30010000         | lea r9,qword ptr ss:[rsp+130]
    $+98             | 4C:8D4424 30               | lea r8,qword ptr ss:[rsp+30]
    $+9D             | 48:8B48 18                 | mov rcx,qword ptr ds:[rax+18]
    $+A1             | 48:8D05 02CD9101           | lea rax,qword ptr ds:[7FFBF44F72FA]
    $+A8             | 48:85C9                    | test rcx,rcx
    $+AB             | 48:0F45D1                  | cmovne rdx,rcx
    $+AF             | 48:8D0D BAD14D02           | lea rcx,qword ptr ds:[7FFBF50B77C0]                                    | 00007FFBF50B77C0:"Ent %3d: %s class %s name %s\n"
    $+B6             | 48:85D2                    | test rdx,rdx
    $+B9             | 48:0F45C2                  | cmovne rax,rdx
    $+BD             | 8BD3                       | mov edx,ebx
    $+BF             | 48:894424 20               | mov qword ptr ss:[rsp+20],rax
    $+C4             | FF15 FE428E01              | call qword ptr ds:[<&void __cdecl ConMsg(char const *, ...)>]
    $+CA             | EB 31                      | jmp client.7FFBF2BDA64D
    $+CC             | 4C:8D05 6DD14D02           | lea r8,qword ptr ds:[7FFBF50B7790]                                     | 00007FFBF50B7790:"(missing), "
    $+D3             | BA 00010000                | mov edx,100
    $+D8             | 48:8D4C24 30               | lea rcx,qword ptr ss:[rsp+30]
    $+DD             | FF15 F54D8E01              | call qword ptr ds:[<&V_snprintf>]
    $+E3             | 4C:8D05 66D14D02           | lea r8,qword ptr ds:[7FFBF50B77A0]                                     | 00007FFBF50B77A0:"(missing)"
    $+EA             | BA 00010000                | mov edx,100
 
Последнее редактирование:
Начинающий
Статус
Оффлайн
Регистрация
11 Фев 2023
Сообщения
39
Реакции[?]
0
Поинты[?]
0
hey again could u please tell me how can i understand what have u wrote ?

the assembly part ?
 
Начинающий
Статус
Оффлайн
Регистрация
11 Фев 2023
Сообщения
39
Реакции[?]
0
Поинты[?]
0
i used ai model to generate function out from this assembly code
the final look will be like this


assembly to cpp function:
#include <cstdint>

// Define the structure with the highestIndex at offset 1520 (0x5F0)
struct SomeStruct {
    // ... other members ...

    // Assuming highestIndex is at offset 1520 bytes
    // You might need to use padding or pragma directives to ensure the correct offset
    // For simplicity, we'll represent it directly
    int highestIndex; // Located at offset 1520
};

// Function to get the highest index
int* GetHighestIndex(SomeStruct* obj, int* output) {
    // Retrieve the highestIndex from the object and store it in output
    *output = obj->highestIndex;
   
    // Return the output pointer
    return output;
}
How can I use it ?
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
hey again could u please tell me how can i understand what have u wrote ?

the assembly part ?
the assembly part is there so that YOU can go and find the member offset for your version of the game(and in the future if/when that part of code gets updated). that 0x1520 might not be relevant(it's from a 1 month old dota version)
so go find that place in an up-to-date version of dota(for example via string xref "Ent %3d: %s class %s name %s\n"), then check the assembly of GetHighestIndex
and check the offset(maybe it's still 0x1520, maybe not)
to get a member by offset you can just add that offset(use integer arithmetic(cast ptr to std::uintptr_t before adding) not pointer arithmetic!) to the pointer to the object(entitysystem in our case) and reinterpret result as pointer to member type(int in our case) and dereference
C++:
int highest_index = *(int*)((std::uintptr_t)entitysystem + 0x1520);
then you just iterate from 0 to highest_index(keep in mind that it represents a valid index(so dont skip it). it will be -1 when no entities exist) and get entities by index
 
Начинающий
Статус
Оффлайн
Регистрация
11 Фев 2023
Сообщения
39
Реакции[?]
0
Поинты[?]
0
the assembly part is there so that YOU can go and find the member offset for your version of the game(and in the future if/when that part of code gets updated). that 0x1520 might not be relevant (it's from a 1 month old dota version)
so go find that place in an up-to-date version of dota(for example via string xref "Ent %3d: %s class %s name %s\n"), then check the assembly of GetHighestIndex
and check the offset(maybe it's still 0x1520, maybe not)
to get a member by offset you can just add that offset(use integer arithmetic(cast ptr to std::uintptr_t before adding) not pointer arithmetic!) to the pointer to the object(entitysystem in our case) and reinterpret result as pointer to member type(int in our case) and dereference
C++:
int highest_index = *(int*)((std::uintptr_t)entitysystem + 0x1520);
then you just iterate from 0 to highest_index(keep in mind that it represents a valid index(so dont skip it). it will be -1 when no entities exist) and get entities by index
thanks a lot iam really glade cuz i have someone like u answering my question thanks a lot <3 also i will try and get back to u , again thanks a lot
 
Сверху Снизу