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

Начинающий
Статус
Оффлайн
Регистрация
12 Сен 2020
Сообщения
42
Реакции[?]
3
Поинты[?]
0
Начинающий
Статус
Оффлайн
Регистрация
15 Дек 2018
Сообщения
146
Реакции[?]
9
Поинты[?]
0
ну я узнаю их по заполненности 8 байтовой ячейки. если там 4 байта нулей и 4 байта каких-то данных то скорее всего это 2 int'а(один из которых 0 а другой xxx) будет а не long long.
также по инструкциям mov dword:[rcx+offset], mov byte:[rcx+offset], mov word:[rcx+offset], mov qword:[rcx+offset]
а также по смыслу(если в классе всего 10 нетваров, то понятно что число 10(или 9 или 11) обозначает количество нетваров(или количество минус один/плюс один). также проверяю это и на другом классе и если там также то моя гипотеза верна. если нет то вывожу новую.).
char pad[6] это как раз таки 6 байт(я обозначил short + char[6], а можно было short + short + int/как душе угодно) которые я не смог определить зачем нужны, поэтому я просто на них забил. u64 idk точно также "i don't know", idk2 точно так же не смог определить.
ну и рекласс использую только для определения больших структур. там просто дофига мусора всякого на экране. а для маленьких структур типо описания нетвара из шемы и обычного окна dump в x64dbg хватает.
если мы говорим про массив то размер структуры это расстояние от одного члена до другого такого же в следующей структуре
То есть получается sizeofclass это два инта? У меня в реклассе в 8 байтной ячейки 90 1A 00 00 34 00 00 00, один из которых 90 1A 00 00 а другой 34 00 00 00?
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
То есть получается sizeofclass это два инта? У меня в реклассе в 8 байтной ячейки 90 1A 00 00 34 00 00 00, один из которых 90 1A 00 00 а другой 34 00 00 00?
в этой 8 байтовой ячейке два инта, первый это 0x1a90 это размер класса как через sizeof, а второй 0x34(я думаю больше short он априори быть не может, где ты видел класс с >32k членов?) но все же может быть intом потому что просто так вальвы захотели. ) это количество нетваров в классе.
ты сначала в x64dbg(реклассе) смотришь на структуру и мысленно себе представляешь какой член за что отвечает, потом вычисляешь оффсеты, потом все это переносишь в визуалку с учетом алайна(выравнивания. суть выравнивания в том что каждый новый член должен иметь оффсет кратный его размеру, то есть
struct{
char x;//0->1
//char pad[1];//тут пустое(ну точнее просто не используемое в твоем коде, а вот место в оперативе занимает) место в 1 байт из-за выравнивания
short p;//2->4, потому что оффсет кратен 2
int y;//4->8 , потому что оффсет кратен 4
int z;//8->12
//char pad2[4];//пустое место в 4 байт из-за выравнивания
u64 w;//16->24, потому что оффсет кратен 8
}
)
моя структура ClassDescription отражает такие оффсеты:
struct ClassDescription {
u64 idk;//0->8
cc classname;//8->16
cc modulename;//16->24
int sizeofclass;//24->28
short Size;//28->30
char pad[6];//30->36
//из-за алайна, так как следующий член u64, то он должен начинаться с ячейки кратной 8. то есть по сути char pad[10] на самом деле тут а не [6]. но как я уже и говорил все эти структуры сделаны мной и для меня, поэтому они сделаны в таком стиле и виде в каком были мои мысли в тот момент, поэтому я для себя просто сделал пометку pad[6] и в уме учел выравнивание и не стал эти 4 байта сюда заносить.
u64 MemberInfo;//40->48
u64 idk2;//48->56
SchemaParent* parent;//56->64
};
 
Начинающий
Статус
Оффлайн
Регистрация
15 Дек 2018
Сообщения
146
Реакции[?]
9
Поинты[?]
0
в этой 8 байтовой ячейке два инта, первый это 0x1a90 это размер класса как через sizeof, а второй 0x34(я думаю больше short он априори быть не может, где ты видел класс с >32k членов?) но все же может быть intом потому что просто так вальвы захотели. ) это количество нетваров в классе.
ты сначала в x64dbg(реклассе) смотришь на структуру и мысленно себе представляешь какой член за что отвечает, потом вычисляешь оффсеты, потом все это переносишь в визуалку с учетом алайна(выравнивания. суть выравнивания в том что каждый новый член должен иметь оффсет кратный его размеру, то есть
struct{
char x;//0->1
//char pad[1];//тут пустое(ну точнее просто не используемое в твоем коде, а вот место в оперативе занимает) место в 1 байт из-за выравнивания
short p;//2->4, потому что оффсет кратен 2
int y;//4->8 , потому что оффсет кратен 4
int z;//8->12
//char pad2[4];//пустое место в 4 байт из-за выравнивания
u64 w;//16->24, потому что оффсет кратен 8
}
)
моя структура ClassDescription отражает такие оффсеты:
struct ClassDescription {
u64 idk;//0->8
cc classname;//8->16
cc modulename;//16->24
int sizeofclass;//24->28
short Size;//28->30
char pad[6];//30->36
//из-за алайна, так как следующий член u64, то он должен начинаться с ячейки кратной 8. то есть по сути char pad[10] на самом деле тут а не [6]. но как я уже и говорил все эти структуры сделаны мной и для меня, поэтому они сделаны в таком стиле и виде в каком были мои мысли в тот момент, поэтому я для себя просто сделал пометку pad[6] и в уме учел выравнивание и не стал эти 4 байта сюда заносить.
u64 MemberInfo;//40->48
u64 idk2;//48->56
SchemaParent* parent;//56->64
};
Я запутался) К примеру взять sizeof(int), он вернет значение 4, то есть int равен 4 байтам, а 4 байта это примерно 00 00 00 00, так почему тогда первый инт в данном члене это 0x1A90 а не 0x1A900000? Там же 4 байта дается, а не 2, я не могу этого понять xD
 
Начинающий
Статус
Оффлайн
Регистрация
12 Сен 2020
Сообщения
42
Реакции[?]
3
Поинты[?]
0
Я запутался) К примеру взять sizeof(int), он вернет значение 4, то есть int равен 4 байтам, а 4 байта это примерно 00 00 00 00, так почему тогда первый инт в данном члене это 0x1A90 а не 0x1A900000? Там же 4 байта дается, а не 2, я не могу этого понять xD
перечитай еще раз, ответы исчерпывающие даны
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
Я запутался) К примеру взять sizeof(int), он вернет значение 4, то есть int равен 4 байтам, а 4 байта это примерно 00 00 00 00, так почему тогда первый инт в данном члене это 0x1A90 а не 0x1A900000? Там же 4 байта дается, а не 2, я не могу этого понять xD
это может быть и два short, один из которых равен 0x1a90 а другой 0. точно знают только вальвы,а мы можем лишь предполагать. но впринципе размер класса очень даже может быть больше >32k байт поэтому скорее всего это int.
по поводу 0x1A90 и 0x1A900000, вспомни про little endian.
это когда у типа данных размером n>1 каждый байт перевернут. то есть у int структура такая
первый байт, второй байт, третий байт, четвертый байт.
в оперативке на little endian(любой пк впринципе) машине этот int будет храниться так:
четвертый байт, третий байт, второй байт, первый байт
в итоге считывая данные из оперативки тебе потом нужно будет перевернуть эти данные(mov <register>,word/dword/qword:[] уже автоматически переворачивает перед тем как в регистр засунуть, поэтому ты в своем коде с этим вряд ли встретишься, за тебя уже все сделано).
вот у тебя в оперативке 90 1A 00 00 34 00 00 00
это значит если это два int, то первый это
_byteswap_ulong(0x901a0000) = 00 00 1a 90 = 0x1a90
второй _byteswap_ulong(0x34000000) = 00 00 00 34 = 0x34
а не как ты говорил 0x1A900000.
 
Начинающий
Статус
Оффлайн
Регистрация
15 Дек 2018
Сообщения
146
Реакции[?]
9
Поинты[?]
0
это может быть и два short, один из которых равен 0x1a90 а другой 0. точно знают только вальвы,а мы можем лишь предполагать. но впринципе размер класса очень даже может быть больше >32k байт поэтому скорее всего это int.
по поводу 0x1A90 и 0x1A900000, вспомни про little endian.
это когда у типа данных размером n>1 каждый байт перевернут. то есть у int структура такая
первый байт, второй байт, третий байт, четвертый байт.
в оперативке на little endian(любой пк впринципе) машине этот int будет храниться так:
четвертый байт, третий байт, второй байт, первый байт
в итоге считывая данные из оперативки тебе потом нужно будет перевернуть эти данные(mov <register>,word/dword/qword:[] уже автоматически переворачивает перед тем как в регистр засунуть, поэтому ты в своем коде с этим вряд ли встретишься, за тебя уже все сделано).
вот у тебя в оперативке 90 1A 00 00 34 00 00 00
это значит если это два int, то первый это
_byteswap_ulong(0x901a0000) = 00 00 1a 90 = 0x1a90
второй _byteswap_ulong(0x34000000) = 00 00 00 34 = 0x34
а не как ты говорил 0x1A900000.
Спасибо тебе большое
а где находится SchemaTypeDescription и MemberDescription?
 
Последнее редактирование:
Начинающий
Статус
Оффлайн
Регистрация
12 Сен 2020
Сообщения
42
Реакции[?]
3
Поинты[?]
0
а есть какое-то объяснение, что такое InGame(CEngineClient), или это просто логическая конструкция истины? вроде интуитивно понятно, а если задуматься, что за процесс происходит, то не очень.
 
Последнее редактирование:
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
а есть какое-то объяснение, что такое InGame(CEngineClient), или это просто логическая конструкция истины? вроде интуитивно понятно, а если задуматься, что за процесс происходит, то не очень.
зайди в ида в дилиб и посмотришь что будет происходить))
в классе CEngineClient есть виртуальная функция IsInGame, я ее вызываю.(то есть вызываю функцию по указателю InGame(который я достал из вмтхи CEngineClient), первым параметром(то есть this) передаю CEngineClient)
вот она из дилиба
1601232344833.png
на +0x110 какой-то мусор
на +0x80 в вмт лежит вот эта функция
1601232314552.png
на 0x60 лежит IsActive из того же класса.
1601232499046.png
все просто, название очевидное. функция есть и в любой другой игре на сурс движке.
 
Начинающий
Статус
Оффлайн
Регистрация
12 Сен 2020
Сообщения
42
Реакции[?]
3
Поинты[?]
0
да, извиняюсь, завис, хотя непросто
 
Последнее редактирование:
Начинающий
Статус
Оффлайн
Регистрация
15 Дек 2018
Сообщения
146
Реакции[?]
9
Поинты[?]
0
зайди в ида в дилиб и посмотришь что будет происходить))
в классе CEngineClient есть виртуальная функция IsInGame, я ее вызываю.(то есть вызываю функцию по указателю InGame(который я достал из вмтхи CEngineClient), первым параметром(то есть this) передаю CEngineClient)
вот она из дилиба
Посмотреть вложение 101983
на +0x110 какой-то мусор
на +0x80 в вмт лежит вот эта функция
Посмотреть вложение 101982
на 0x60 лежит IsActive из того же класса.
Посмотреть вложение 101984
все просто, название очевидное. функция есть и в любой другой игре на сурс движке.
А где находится SchemaTypeDescription и MemberDescription? Бегаю по классу в отладчике, все найти не могу
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
А где находится SchemaTypeDescription и MemberDescription? Бегаю по классу в отладчике, все найти не могу
auto Declaration = scope->FindDeclaredClass(c);
for (u64 i = 0; i < Declaration->Size; i++) {
Pointer<CSchemaSystem::MemberDescription> Description = Declaration->MemberInfo + i * 0x20;
auto netvar_type = Description->schematypeptr->name;
...
}
 
Начинающий
Статус
Оффлайн
Регистрация
15 Дек 2018
Сообщения
146
Реакции[?]
9
Поинты[?]
0
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
А зачем у тебя здесь в a->MemberInfo + i * 0x20 идет умножение на 20?
потому что MemberInfo это указатель на массив структур MemberDescription размером 0x20.
прибавляю 0x20*i и получаю указатели на элементы этого массива(ну то есть указатель на начало структуры). впринципе просто можно объявить MemberInfo как MemberDescription* и использовать
C++:
a->MemberInfo[i]
 
Начинающий
Статус
Оффлайн
Регистрация
15 Дек 2018
Сообщения
146
Реакции[?]
9
Поинты[?]
0
потому что MemberInfo это указатель на массив структур MemberDescription размером 0x20.
прибавляю 0x20*i и получаю указатели на элементы этого массива(ну то есть указатель на начало структуры). впринципе просто можно объявить MemberInfo как MemberDescription* и использовать
C++:
a->MemberInfo[i]
Спасибо
 
Начинающий
Статус
Оффлайн
Регистрация
15 Дек 2018
Сообщения
146
Реакции[?]
9
Поинты[?]
0
Кста, в ClassDescription первый член вроде это указатель, который вернул FindDeclaredClass
 
Начинающий
Статус
Оффлайн
Регистрация
15 Дек 2018
Сообщения
146
Реакции[?]
9
Поинты[?]
0
А почему может крашить при таком варианте вызова функции?
// CEngineClient
u64 CEngineClient = CreateInterface("engine2.dll", "Source2EngineToClient001");
u64 CEngineClientVTable = *(u64*)CEngineClient;

u64 GetLocalPlayer = *(u64*)(CEngineClientVTable + 22 * 8);
int IsLocalPlayer = -1;
u64 GetLocalPlayerResult = ((u64(__fastcall*)(u64 _CEngineClient, u64 _Result))GetLocalPlayer)(CEngineClient, IsLocalPlayer);
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
А почему может крашить при таком варианте вызова функции?
// CEngineClient
u64 CEngineClient = CreateInterface("engine2.dll", "Source2EngineToClient001");
u64 CEngineClientVTable = *(u64*)CEngineClient;

u64 GetLocalPlayer = *(u64*)(CEngineClientVTable + 22 * 8);
int IsLocalPlayer = -1;
u64 GetLocalPlayerResult = ((u64(__fastcall*)(u64 _CEngineClient, u64 _Result))GetLocalPlayer)(CEngineClient, IsLocalPlayer);
может потому что ты передаешь int вместо int* :)
u64 GetLocalPlayerResult = ((u64(__fastcall*)(u64 _CEngineClient, u64 _Result))GetLocalPlayer)(CEngineClient, &IsLocalPlayer);
//функция спрашивает КУДА записать результат, а ты ей даешь вместо этого значение переменной а не ее адрес
еще нолик третьим параметром передай это вроде SplitScreenSlot судя по LWSS virtual int GetLocalPlayer( int splitScreenSlot = 0 )
 
Сверху Снизу